Merge "Poll /sys/kernel/tracing/tracing_on before returning from trace capture start" into androidx-main
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt
index 61dd1c6..8e7258a6 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/Shell.kt
@@ -299,6 +299,11 @@
}
throw IllegalStateException("Failed to stop $runningProcesses")
}
+
+ @RequiresApi(21)
+ fun pathExists(absoluteFilePath: String): Boolean {
+ return executeCommand("ls $absoluteFilePath").trim() == absoluteFilePath
+ }
}
@RequiresApi(Build.VERSION_CODES.LOLLIPOP)
diff --git a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoHelper.kt b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoHelper.kt
index 5d5e266a..2b0cf5d 100644
--- a/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoHelper.kt
+++ b/benchmark/benchmark-common/src/main/java/androidx/benchmark/perfetto/PerfettoHelper.kt
@@ -114,6 +114,58 @@
throw perfettoStartupException("Perfetto tracing failed to start.", null)
}
Log.i(LOG_TAG, "Perfetto tracing started successfully with pid $perfettoPid.")
+
+ checkTracingOn()
+ }
+
+ /**
+ * Poll for tracing_on to be set to 1.
+ *
+ * This is a good indicator that tracing is actually enabled (including the app atrace tag), and
+ * that content will be captured in the trace buffer
+ */
+ private fun checkTracingOn(): Unit = userspaceTrace("poll tracing_on") {
+ val path: String = when {
+ Shell.pathExists(TRACING_ON_PATH) -> {
+ TRACING_ON_PATH
+ }
+ Shell.pathExists(TRACING_ON_FALLBACK_PATH) -> {
+ TRACING_ON_FALLBACK_PATH
+ }
+ else -> {
+ throw perfettoStartupException(
+ "Unable to find path to tracing_on (e.g. $TRACING_ON_PATH)",
+ null
+ )
+ }
+ }
+
+ val pollTracingOnMaxCount = 50
+ val pollTracingOnMs = 100L
+
+ repeat(pollTracingOnMaxCount) {
+ when (val output = Shell.executeCommand("cat $path").trim()) {
+ "0" -> {
+ userspaceTrace("wait for trace to start (tracing_on == 1)") {
+ SystemClock.sleep(pollTracingOnMs)
+ }
+ }
+ "1" -> {
+ // success!
+ Log.i(LOG_TAG, "$path = 1, polled $it times, capture fully started")
+ return@checkTracingOn
+ }
+ else -> {
+ throw perfettoStartupException(
+ "Saw unexpected tracing_on contents: $output",
+ null
+ )
+ }
+ }
+ }
+
+ val duration = pollTracingOnMs * pollTracingOnMaxCount
+ throw perfettoStartupException("Error: did not detect tracing on after $duration ms", null)
}
/**
@@ -294,6 +346,10 @@
private val SUPPORTED_64_ABIS = setOf("arm64-v8a", "x86_64")
private val SUPPORTED_32_ABIS = setOf("armeabi")
+ // potential paths that tracing_on may reside in
+ private const val TRACING_ON_PATH = "/sys/kernel/tracing/tracing_on"
+ private const val TRACING_ON_FALLBACK_PATH = "/sys/kernel/debug/tracing/tracing_on"
+
@TestOnly
fun isAbiSupported(): Boolean {
Log.d(LOG_TAG, "Supported ABIs: ${Build.SUPPORTED_ABIS.joinToString()}")
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureTest.kt
index 4cf3f2b..e9996c5 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/PerfettoCaptureTest.kt
@@ -38,6 +38,7 @@
import org.junit.runner.RunWith
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
+import kotlin.test.assertTrue
/**
* Tests for PerfettoCapture
@@ -90,39 +91,43 @@
perfettoCapture.start(listOf(Packages.TEST))
- verifyTraceEnable(true)
+ assertTrue(
+ Trace.isEnabled(),
+ "In-process tracing should be enabled immediately after trace capture is started"
+ )
- // TODO: figure out why this sleep (200ms+) is needed - possibly related to b/194105203
- Thread.sleep(500)
-
- // Tracing non-trivial duration for manual debugging/verification
- trace(CUSTOM_TRACE_SECTION_LABEL_1) { Thread.sleep(20) }
- trace(CUSTOM_TRACE_SECTION_LABEL_2) { Thread.sleep(20) }
+ /**
+ * Trace section labels, in order
+ *
+ * We trace for non-trivial duration both to enable easier manual debugging, but also to
+ * help clarify problems in front/back trace truncation, with indication of severity.
+ *
+ * We use unique, app tag names to avoid conflicting with other legitimate platform tracing.
+ */
+ val traceSectionLabels = List(20) {
+ "PerfettoCaptureTest_$it".also { label ->
+ trace(label) { Thread.sleep(50) }
+ }
+ }
perfettoCapture.stop(traceFilePath)
val matchingSlices = PerfettoTraceProcessor.querySlices(
absoluteTracePath = traceFilePath,
- CUSTOM_TRACE_SECTION_LABEL_1,
- CUSTOM_TRACE_SECTION_LABEL_2
+ "PerfettoCaptureTest_%"
)
// Note: this test avoids validating platform-triggered trace sections, to avoid flakes
// from legitimate (and coincidental) platform use during test.
assertEquals(
- listOf(CUSTOM_TRACE_SECTION_LABEL_1, CUSTOM_TRACE_SECTION_LABEL_2),
+ traceSectionLabels,
matchingSlices.sortedBy { it.ts }.map { it.name }
)
matchingSlices
.forEach {
- assertTrue(it.dur > 15_000_000) // should be at least 15ms
+ assertTrue(it.dur > 30_000_000) // should be at least 30ms
}
}
-
- companion object {
- const val CUSTOM_TRACE_SECTION_LABEL_1 = "PerfettoCaptureTest_1"
- const val CUSTOM_TRACE_SECTION_LABEL_2 = "PerfettoCaptureTest_2"
- }
}
fun verifyTraceEnable(enabled: Boolean) {
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoTraceProcessor.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoTraceProcessor.kt
index 68803a4c..8bed227 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoTraceProcessor.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/PerfettoTraceProcessor.kt
@@ -72,6 +72,8 @@
/**
* Query a trace for a list of slices - name, timestamp, and duration.
+ *
+ * Note that sliceNames may include wildcard matches, such as `foo%`
*/
fun querySlices(
absoluteTracePath: String,
@@ -79,7 +81,7 @@
): List {
val whereClause = sliceNames
.joinToString(separator = " OR ") {
- "slice.name = '$it'"
+ "slice.name LIKE \"$it\""
}
return Slice.parseListFromQueryResult(