aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Holk <eholk@google.com>2019-03-06 20:15:03 -0800
committerEric Holk <eholk@google.com>2019-03-07 10:21:37 -0800
commit78fc9b1c2d27161f3c9ff943a8249a4219dcba4b (patch)
treea794a270a9c327a2b8489f624578e3deead5a1e6
parentacfb58a5f7ec3bb11d13b14755400028ba2663de (diff)
downloadtrebuchet-78fc9b1c2d27161f3c9ff943a8249a4219dcba4b.tar.gz
Teach StartupAnalyzer to handle threads with no slices
Sometimes we end up with threads that have no slices to them, which was crashing the startup analyzer. This change uses POSITIVE_INFINITY as the start time for threads with no slices. This change also includes a regression test that was generated by reducing a trace that exercised this bug. Further regression tests should now be easier to add. Test: atest Change-Id: Ibc82abb6406689b2e1f8c15558458d16e9f3f65d
-rw-r--r--Android.bp16
-rw-r--r--TEST_MAPPING4
-rw-r--r--trebuchet/startup-common/src/StartupCommon.kt2
-rw-r--r--trebuchet/startup-common/test/StartupCommonTests.kt69
4 files changed, 90 insertions, 1 deletions
diff --git a/Android.bp b/Android.bp
index c5dcc62..7fd8807 100644
--- a/Android.bp
+++ b/Android.bp
@@ -61,6 +61,22 @@ java_test_host {
test_suites: ["general-tests"],
}
+java_test_host {
+ name: "trebuchet-startup-common-tests",
+ defaults: ["trebuchet-defaults"],
+ srcs: [
+ "trebuchet/startup-common/test/**/*.kt",
+ ],
+ static_libs: [
+ "trebuchet-core",
+ "trebuchet-startup-common",
+ ],
+ libs: [
+ "junit",
+ ],
+ test_suites: ["general-tests"],
+}
+
java_binary_host {
name: "AnalyzerKt",
defaults: ["trebuchet-defaults"],
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 97a5fde..5be5baf 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -8,6 +8,10 @@
"exclude-annotation": "trebuchet.testutils.NeedsSampleData"
}
]
+ },
+ {
+ "name": "trebuchet-startup-common-tests",
+ "host": true
}
]
}
diff --git a/trebuchet/startup-common/src/StartupCommon.kt b/trebuchet/startup-common/src/StartupCommon.kt
index da6c378..13345c5 100644
--- a/trebuchet/startup-common/src/StartupCommon.kt
+++ b/trebuchet/startup-common/src/StartupCommon.kt
@@ -210,7 +210,7 @@ fun Model.getStartupEvents() : List<StartupEvent> {
val newProc = this.findProcess(newProcName, systemServerSlice.startTime, systemServerSlice.endTime)
val startProcSlice = systemServerProc.findFirstSlice(SLICE_NAME_PROC_START, newProcName, systemServerSlice.startTime, systemServerSlice.endTime)
val rfdSlice = systemServerProc.findFirstSliceOrNull(SLICE_NAME_REPORT_FULLY_DRAWN, newProcName, systemServerSlice.startTime)
- val firstSliceTime = newProc.threads.map { it.slices.first().startTime }.min()!!
+ val firstSliceTime = newProc.threads.map { it.slices.firstOrNull()?.startTime ?: Double.POSITIVE_INFINITY }.min()!!
val schedSliceInfo : MutableMap<SchedulingState, Double> = mutableMapOf()
newProc.threads.first().schedSlices.forEach schedLoop@ { schedSlice ->
diff --git a/trebuchet/startup-common/test/StartupCommonTests.kt b/trebuchet/startup-common/test/StartupCommonTests.kt
new file mode 100644
index 0000000..0a73d70
--- /dev/null
+++ b/trebuchet/startup-common/test/StartupCommonTests.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package trebuchet.analyzer.startup
+
+import getStartupEvents
+import org.junit.Test
+import trebuchet.io.BufferProducer
+import trebuchet.io.DataSlice
+import trebuchet.io.asSlice
+import trebuchet.model.Model
+import trebuchet.task.ImportTask
+import trebuchet.util.PrintlnImportFeedback
+
+fun parseString(source: String): Model {
+ val task = ImportTask(PrintlnImportFeedback())
+ return task.import(object : BufferProducer {
+ var hasRead = false
+ override fun next(): DataSlice? {
+ if (hasRead) return null
+ hasRead = true
+ return source.asSlice()
+ }
+ })
+}
+
+class StartupCommonTest {
+ @Test
+ fun testEmptyThreadStart() {
+ // This is a reduced trace based on one seen in the wild that used to
+ // crash because it creates a thread with no slices assigned to it.
+ val test = """
+TRACE:
+# tracer: nop
+#
+# entries-in-buffer/entries-written: 289801/289801 #P:4
+#
+# _-----=> irqs-off
+# / _----=> need-resched
+# | / _---=> hardirq/softirq
+# || / _--=> preempt-depth
+# ||| / delay
+# TASK-PID TGID CPU# |||| TIMESTAMP FUNCTION
+# | | | | |||| | |
+ Binder:980_13-3951 ( 980) [002] ...1 1628.269667: tracing_mark_write: E|980
+ Binder:980_13-3951 ( 980) [002] ...2 1628.270068: tracing_mark_write: S|980|launching: com.example.eholk.myfirstapp|0
+ <...>-1104 (-----) [000] ...1 1628.292040: tracing_mark_write: B|980|Start proc: com.example.eholk.myfirstapp
+ <...>-1103 (-----) [002] d..4 1628.300748: sched_waking: comm=system_server pid=980 prio=118 target_cpu=001
+ RenderThread-9817 ( 9793) [003] d..3 1628.457017: sched_waking: comm=holk.myfirstapp pid=9793 prio=110 target_cpu=002
+ RenderThread-9817 ( 9793) [003] ...1 1628.457191: tracing_mark_write: B|9793|Thread birth
+ """
+
+ val trace = parseString(test)
+ trace.getStartupEvents()
+ }
+}