1 /*
2  * Copyright 2017 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package trebuchet.importers.ftrace
18 
19 import org.junit.Assert.*
20 import org.junit.Test
21 import trebuchet.importers.FatalImportFeedback
22 import trebuchet.io.StreamingReader
23 import trebuchet.model.Model
24 import trebuchet.testutils.makeReader
25 
26 class FtraceImporterTest {
27 
Stringnull28     fun String.makeLoadedReader(): StreamingReader {
29         val reader = this.makeReader()
30         reader.loadIndex(reader.keepLoadedSize.toLong())
31         return reader
32     }
33 
testImporterFornull34     @Test fun testImporterFor() {
35         val line1 = "atrace-7100  ( 7100) [001] ...1  4492.047398: tracing_mark_write: trace_event_clock_sync: parent_ts=4492.069824"
36         val line2 = "<idle>-0     (-----) [001] dN.4  4492.047448: sched_wakeup: comm=ksoftirqd/1 pid=15 prio=120 success=1 target_cpu=001"
37         val traceData = withHeader(line1, line2)
38         assertNotNull(FtraceImporter.Factory.importerFor(HEADER.makeLoadedReader(), FatalImportFeedback))
39         assertNotNull(FtraceImporter.Factory.importerFor(traceData.makeLoadedReader(), FatalImportFeedback))
40         assertNull(FtraceImporter.Factory.importerFor(HEADER.makeReader(), FatalImportFeedback))
41         assertNull(FtraceImporter.Factory.importerFor(traceData.makeReader(), FatalImportFeedback))
42         assertNull(FtraceImporter.Factory.importerFor("Hello, World!".makeLoadedReader(), FatalImportFeedback))
43         assertNull(FtraceImporter.Factory.importerFor(line1.makeLoadedReader(), FatalImportFeedback))
44     }
45 
testImporterTimestampnull46     @Test fun testImporterTimestamp() {
47         val traceData = withHeader(
48             "equicksearchbox-6381  ( 6381) [004] ...1  4493.734816: tracing_mark_write: trace_event_clock_sync: parent_ts=23816.083984",
49             "equicksearchbox-6381  ( 6381) [004] ...1  4493.734855: tracing_mark_write: trace_event_clock_sync: realtime_ts=1491850748338")
50         val importer = FtraceImporter(FatalImportFeedback)
51         val modelFragment = importer.import(traceData.makeReader())
52         assertNotNull(modelFragment)
53         if (modelFragment == null) return // just to make Kotlin happy
54         assertEquals(23816.083984, modelFragment.parentTimestamp, .001)
55         assertEquals(1491850748338, modelFragment.realtimeTimestamp)
56     }
57 
testImportBeginEndnull58     @Test fun testImportBeginEnd() {
59         val traceData = withHeader(
60                 " equicksearchbox-6381  ( 6381) [004] ...1  4493.734816: tracing_mark_write: E",
61                 " equicksearchbox-6381  ( 6381) [005] ...1  4493.730786: tracing_mark_write: B|6381|Choreographer#doFrame",
62                 " equicksearchbox-6381  ( 6381) [005] ...1  4493.730824: tracing_mark_write: B|6381|input",
63                 " equicksearchbox-6381  ( 6381) [005] ...1  4493.732287: tracing_mark_write: E",
64                 " equicksearchbox-6381  ( 6381) [005] ...1  4493.732310: tracing_mark_write: B|6381|traversal",
65                 " equicksearchbox-6381  ( 6381) [005] ...1  4493.732410: tracing_mark_write: B|6381|draw",
66                 " equicksearchbox-6381  ( 6381) [004] ...1  4493.734816: tracing_mark_write: E",
67                 " equicksearchbox-6381  ( 6381) [004] ...1  4493.734828: tracing_mark_write: E",
68                 " equicksearchbox-6381  ( 6381) [004] ...1  4493.734855: tracing_mark_write: E")
69         val importer = FtraceImporter(FatalImportFeedback)
70         val modelFragment = importer.import(traceData.makeReader())
71         assertNotNull(modelFragment)
72         if (modelFragment == null) return // just to make Kotlin happy
73         assertEquals(1, modelFragment.processes.size)
74         val process = modelFragment.processes[0]
75         assertEquals(6381, process.id)
76         assertEquals("equicksearchbox", process.name)
77         assertEquals(1, process.threads.size)
78         val thread = process.threads.first()
79         assertEquals(6381, thread.id)
80         assertEquals("equicksearchbox", thread.name)
81         val sliceGroup = thread.slicesBuilder
82         assertFalse(sliceGroup.hasOpenSlices())
83         assertEquals(1, sliceGroup.slices.size)
84         val doFrameSlice = sliceGroup.slices[0]
85         assertEquals("Choreographer#doFrame", doFrameSlice.name)
86         assertEquals(2, doFrameSlice.children.size)
87         assertEquals("input", doFrameSlice.children[0].name)
88         assertEquals(0, doFrameSlice.children[0].children.size)
89         assertEquals("traversal", doFrameSlice.children[1].name)
90         assertEquals(1, doFrameSlice.children[1].children.size)
91         assertEquals("draw", doFrameSlice.children[1].children[0].name)
92     }
93 
testImportBeginEndNoTgidsnull94     @Test fun testImportBeginEndNoTgids() {
95         val traceData = withHeader(
96                 " equicksearchbox-6381  (-----) [004] ...1  4493.734828: tracing_mark_write: E",
97                 " equicksearchbox-6381  (-----) [005] ...1  4493.730786: tracing_mark_write: B|6381|Choreographer#doFrame",
98                 " equicksearchbox-6381  (-----) [005] ...1  4493.730824: tracing_mark_write: B|6381|input",
99                 " equicksearchbox-6381  (-----) [005] ...1  4493.732287: tracing_mark_write: E",
100                 " equicksearchbox-6381  (-----) [005] ...1  4493.732310: tracing_mark_write: B|6381|traversal",
101                 " equicksearchbox-6381  (-----) [005] ...1  4493.732410: tracing_mark_write: B|6381|draw",
102                 " equicksearchbox-6381  (-----) [004] ...1  4493.734816: tracing_mark_write: E",
103                 " equicksearchbox-6381  (-----) [004] ...1  4493.734828: tracing_mark_write: E",
104                 " equicksearchbox-6381  (-----) [004] ...1  4493.734855: tracing_mark_write: E")
105         val importer = FtraceImporter(FatalImportFeedback)
106         val modelFragment = importer.import(traceData.makeReader())
107         assertNotNull(modelFragment)
108         if (modelFragment == null) return // just to make Kotlin happy
109         assertEquals(1, modelFragment.processes.size)
110         val process = modelFragment.processes[0]
111         assertEquals(6381, process.id)
112         assertEquals("equicksearchbox", process.name)
113         assertEquals(1, process.threads.size)
114         val thread = process.threads.first()
115         assertEquals(6381, thread.id)
116         assertEquals("equicksearchbox", thread.name)
117         val sliceGroup = thread.slicesBuilder
118         assertFalse(sliceGroup.hasOpenSlices())
119         assertEquals(1, sliceGroup.slices.size)
120         val doFrameSlice = sliceGroup.slices[0]
121         assertEquals("Choreographer#doFrame", doFrameSlice.name)
122         assertEquals(2, doFrameSlice.children.size)
123         assertEquals("input", doFrameSlice.children[0].name)
124         assertEquals(0, doFrameSlice.children[0].children.size)
125         assertEquals("traversal", doFrameSlice.children[1].name)
126         assertEquals(1, doFrameSlice.children[1].children.size)
127         assertEquals("draw", doFrameSlice.children[1].children[0].name)
128     }
129 
testCountersnull130     @Test fun testCounters() {
131         val model = parse(
132                 "          <...>-4932  (-----) [000] ...1  4493.660106: tracing_mark_write: C|3691|iq|1",
133                 "InputDispatcher-4931  ( 3691) [000] ...1  4493.660790: tracing_mark_write: C|3691|iq|0")
134         assertEquals(1, model.processes.size)
135         val p = model.processes[3691]!!
136         assertEquals(3691, p.id)
137         assertEquals(3, p.threads.size)
138         assertTrue(p.threads.any { it.id == 3691 })
139         assertTrue(p.threads.any { it.id == 4931 })
140         assertTrue(p.threads.any { it.id == 4932 })
141         assertEquals(1, p.counters.size)
142         val c = p.counters[0]
143         assertEquals(2, c.events.size)
144         assertEquals(4493.660106, c.events[0].timestamp, .1)
145         assertEquals(1, c.events[0].count)
146         assertEquals(4493.660790, c.events[1].timestamp, .1)
147         assertEquals(0, c.events[1].count)
148 
149     }
150 
parsenull151     fun parse(vararg lines: String): Model {
152         val traceData = withHeader(*lines)
153         val importer = FtraceImporter(FatalImportFeedback)
154         val modelFragment = importer.import(traceData.makeReader())
155         assertNotNull(modelFragment)
156         return Model(modelFragment!!)
157     }
158 
withHeadernull159     fun withHeader(vararg lines: String): String {
160         return lines.joinToString("\n", HEADER)
161     }
162 
163     val HEADER = """TRACE:
164 # tracer: nop
165 #
166 # entries-in-buffer/entries-written: 69580/69580   #P:8
167 #
168 #                                      _-----=> irqs-off
169 #                                     / _----=> need-resched
170 #                                    | / _---=> hardirq/softirq
171 #                                    || / _--=> preempt-depth
172 #                                    ||| /     delay
173 #           TASK-PID    TGID   CPU#  ||||    TIMESTAMP  FUNCTION
174 #              | |        |      |   ||||       |         |
175 """
176 }