Trace-based FrameTimingMetric, Step 2

Bug: 195987329
Bug: 183129298
Fixes: 200082324
Test: TrivialListScrollBenchmark # Validated on 29 & 31
Test: ./gradlew benchmark:benchmark-common:cC benchmark:benchmark-macro:cC

Completes migration of FrameTimingMetric to be trace-based, and
surface FrameNegativeSlack when available.

This change also makes several related changes to frame metrics coming
from FrameTimingQuery:

* Deleted FrameTime, as it's always preferable to use something
  deadline based

* Renamed BasicFrameTime -> FrameCpuTime for clarity, and to match metric plan

* Made FrameSlack negative, so the *worst* frames show up in 99P,
  instead of best. This avoids having to differentate between low=bad
  and high=bad metrics.

Adds FrameTimingGfxInfoMetric to existing scroll benchmarks for
temporary continuity in CI tracking.

Change-Id: Ied56278b1f76f37df44181dc736590753aa1cb30
diff --git a/benchmark/benchmark-macro/api/restricted_current.txt b/benchmark/benchmark-macro/api/restricted_current.txt
index ab915af..fd0ce9c 100644
--- a/benchmark/benchmark-macro/api/restricted_current.txt
+++ b/benchmark/benchmark-macro/api/restricted_current.txt
@@ -32,12 +32,12 @@
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static boolean isSupportedWithVmSettings(androidx.benchmark.macro.CompilationMode);
   }
 
-  public final class FrameTimingMetric extends androidx.benchmark.macro.Metric {
-    ctor public FrameTimingMetric();
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class FrameTimingGfxInfoMetric extends androidx.benchmark.macro.Metric {
+    ctor public FrameTimingGfxInfoMetric();
   }
 
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class FrameTimingTraceMetric extends androidx.benchmark.macro.Metric {
-    ctor public FrameTimingTraceMetric();
+  public final class FrameTimingMetric extends androidx.benchmark.macro.Metric {
+    ctor public FrameTimingMetric();
   }
 
   public final class IdeSummaryStringKt {
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/IdeSummaryStringTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/IdeSummaryStringTest.kt
index 3357a1f..a150eee 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/IdeSummaryStringTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/IdeSummaryStringTest.kt
@@ -123,7 +123,7 @@
         assertEquals(
             """
                 |foo
-                |  Metric1   P50  50.0,   P90  90.0,   P95  95.0,   P99  99.0
+                |  Metric1   P50   50.0,   P90   90.0,   P95   95.0,   P99   99.0
                 |
             """.trimMargin(),
             summaryV1
@@ -131,7 +131,7 @@
         assertEquals(
             """
                 |foo
-                |  Metric1   P50  50.0,   P90  90.0,   P95  95.0,   P99  99.0
+                |  Metric1   P50   50.0,   P90   90.0,   P95   95.0,   P99   99.0
                 |    Traces: Iteration [0](file://iter0.trace) [1](file://iter1.trace) [2](file://iter2.trace)
                 |
             """.trimMargin(),
@@ -157,7 +157,7 @@
             """
                 |foo
                 |  Metric1   min   0.0,   median   1.0,   max   2.0
-                |  Metric2   P50  50.0,   P90  90.0,   P95  95.0,   P99  99.0
+                |  Metric2   P50   50.0,   P90   90.0,   P95   95.0,   P99   99.0
                 |
             """.trimMargin(),
             summaryV1
@@ -166,7 +166,7 @@
             """
                 |foo
                 |  Metric1   [min   0.0](file://iter0.trace),   [median   1.0](file://iter1.trace),   [max   2.0](file://iter2.trace)
-                |  Metric2   P50  50.0,   P90  90.0,   P95  95.0,   P99  99.0
+                |  Metric2   P50   50.0,   P90   90.0,   P95   95.0,   P99   99.0
                 |    Traces: Iteration [0](file://iter0.trace) [1](file://iter1.trace) [2](file://iter2.trace)
                 |
             """.trimMargin(),
diff --git a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/FrameTimingQueryTest.kt b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/FrameTimingQueryTest.kt
index df2b10f..4f6af3c 100644
--- a/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/FrameTimingQueryTest.kt
+++ b/benchmark/benchmark-macro/src/androidTest/java/androidx/benchmark/macro/perfetto/FrameTimingQueryTest.kt
@@ -17,10 +17,9 @@
 package androidx.benchmark.macro.perfetto
 
 import androidx.benchmark.macro.createTempFileFromAsset
-import androidx.benchmark.macro.perfetto.FrameTimingQuery.FrameSubMetric.BasicFrameTime
-import androidx.benchmark.macro.perfetto.FrameTimingQuery.FrameSubMetric.FrameSlackTime
-import androidx.benchmark.macro.perfetto.FrameTimingQuery.FrameSubMetric.FrameTime
-import androidx.benchmark.macro.perfetto.FrameTimingQuery.FrameSubMetric.UiFrameTime
+import androidx.benchmark.macro.perfetto.FrameTimingQuery.SubMetric.FrameCpuTime
+import androidx.benchmark.macro.perfetto.FrameTimingQuery.SubMetric.FrameNegativeSlackTime
+import androidx.benchmark.macro.perfetto.FrameTimingQuery.SubMetric.FrameUiTime
 import androidx.benchmark.perfetto.PerfettoHelper.Companion.isAbiSupported
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
@@ -45,8 +44,8 @@
 
         assertEquals(
             expected = mapOf(
-                BasicFrameTime to listOf(9907605L, 6038595L, 4812136L, 3938490L),
-                UiFrameTime to listOf(3086979L, 2868490L, 2232709L, 1889479L)
+                FrameCpuTime to listOf(9907605L, 6038595L, 4812136L, 3938490L),
+                FrameUiTime to listOf(3086979L, 2868490L, 2232709L, 1889479L)
             ),
             actual = frameSubMetrics.mapValues {
                 it.value.subList(0, 4)
@@ -72,17 +71,16 @@
         )
         assertEquals(
             expected = mapOf(
-                FrameTime to listOf(15292863L, 8800138L, 6474705L, 8199845L),
-                BasicFrameTime to listOf(6881407L, 5648542L, 3830261L, 4343438L),
-                UiFrameTime to listOf(2965052L, 3246407L, 1562188L, 1945469L),
-                FrameSlackTime to listOf(5207137L, 11699862L, 14025295L, 12300155L)
+                FrameCpuTime to listOf(6881407L, 5648542L, 3830261L, 4343438L),
+                FrameUiTime to listOf(2965052L, 3246407L, 1562188L, 1945469L),
+                FrameNegativeSlackTime to listOf(-5207137L, -11699862L, -14025295L, -12300155L)
             ),
             actual = frameSubMetrics.mapValues {
                 it.value.subList(0, 4)
             }
         )
         assertEquals(
-            expected = List(4) { 96 },
+            expected = List(3) { 96 },
             actual = frameSubMetrics.map { it.value.size },
             message = "Expect same number of frames for each metric"
         )
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/IdeSummaryString.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/IdeSummaryString.kt
index 9868e6e..fd1de64 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/IdeSummaryString.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/IdeSummaryString.kt
@@ -69,10 +69,10 @@
             } +
             measurements.sampledMetrics.map {
                 val name = it.name.padStart(maxLabelLength)
-                val p50 = it.p50.toDisplayString()
-                val p90 = it.p90.toDisplayString()
-                val p95 = it.p95.toDisplayString()
-                val p99 = it.p99.toDisplayString()
+                val p50 = it.p50.toDisplayString().padStart(maxValueLength)
+                val p90 = it.p90.toDisplayString().padStart(maxValueLength)
+                val p95 = it.p95.toDisplayString().padStart(maxValueLength)
+                val p99 = it.p99.toDisplayString().padStart(maxValueLength)
                 // we don't try and link percentiles, since they're grouped across multiple iters
                 "  $name   P50  $p50,   P90  $p90,   P95  $p95,   P99  $p99"
             }
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt
index a6f127b..272b007 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/Metric.kt
@@ -21,6 +21,7 @@
 import androidx.annotation.RestrictTo
 import androidx.benchmark.Shell
 import androidx.benchmark.macro.perfetto.FrameTimingQuery
+import androidx.benchmark.macro.perfetto.FrameTimingQuery.SubMetric
 import androidx.benchmark.macro.perfetto.PerfettoResultsParser.parseStartupResult
 import androidx.benchmark.macro.perfetto.PerfettoTraceProcessor
 import androidx.test.platform.app.InstrumentationRegistry
@@ -43,7 +44,13 @@
     internal abstract fun getMetrics(packageName: String, tracePath: String): IterationResult
 }
 
-public class FrameTimingMetric : Metric() {
+/**
+ * Legacy version of FrameTimingMetric, based on 'dumpsys gfxinfo' instead of trace data.
+ *
+ * Temporary - to be removed after transition to FrameTimingMetric
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
+public class FrameTimingGfxInfoMetric : Metric() {
     private lateinit var packageName: String
     private val helper = JankCollectionHelper()
 
@@ -138,26 +145,33 @@
 }
 
 /**
- * WIP trace-based replacement for [FrameTimingMetric].
+ * Metric which captures timing information from frames produced by a benchmark, such as
+ * a scrolling or animation benchmark.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
 @Suppress("CanSealedSubClassBeObject")
-public class FrameTimingTraceMetric : Metric() {
+public class FrameTimingMetric : Metric() {
     internal override fun configure(packageName: String) {}
     internal override fun start() {}
     internal override fun stop() {}
 
     internal override fun getMetrics(packageName: String, tracePath: String): IterationResult {
-        val frameTimesMs = FrameTimingQuery.getFrameSubMetrics(
+        val subMetricsMsMap = FrameTimingQuery.getFrameSubMetrics(
             absoluteTracePath = tracePath,
             captureApiLevel = Build.VERSION.SDK_INT,
             packageName = packageName
-        )[FrameTimingQuery.FrameSubMetric.FrameTime]!!
-            .map { it / 1_000_000.0 } // Convert to ms
-
+        )
+            .filterKeys { it == SubMetric.FrameCpuTime || it == SubMetric.FrameNegativeSlackTime }
+            .mapKeys {
+                if (it.key == SubMetric.FrameCpuTime) "frameCpuTimeMs" else "frameNegativeSlackMs"
+            }
+            .mapValues { entry ->
+                entry.value.map { timeNs ->
+                    timeNs / 1_000_000.0 // Convert to ms
+                }
+            }
         return IterationResult(
             singleMetrics = emptyMap(),
-            sampledMetrics = mapOf("frameTimeMs" to frameTimesMs),
+            sampledMetrics = subMetricsMsMap,
             timelineRangeNs = null
         )
     }
diff --git a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/FrameTimingQuery.kt b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/FrameTimingQuery.kt
index 111329a..f4c5bf0 100644
--- a/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/FrameTimingQuery.kt
+++ b/benchmark/benchmark-macro/src/main/java/androidx/benchmark/macro/perfetto/FrameTimingQuery.kt
@@ -54,14 +54,13 @@
         ORDER BY ts ASC
     """.trimIndent()
 
-    enum class FrameSubMetric {
-        FrameTime,
-        BasicFrameTime,
-        UiFrameTime,
-        FrameSlackTime;
+    enum class SubMetric {
+        FrameCpuTime,
+        FrameUiTime,
+        FrameNegativeSlackTime;
 
         fun supportedOnApiLevel(apiLevel: Int): Boolean {
-            return apiLevel >= 31 || this != FrameTime && this != FrameSlackTime
+            return apiLevel >= 31 || this != FrameNegativeSlackTime
         }
     }
 
@@ -83,12 +82,11 @@
         val expectedSlice: Slice?,
         val actualSlice: Slice?
     ) {
-        fun get(subMetric: FrameSubMetric): Long {
+        fun get(subMetric: SubMetric): Long {
             return when (subMetric) {
-                FrameSubMetric.FrameTime -> actualSlice!!.dur
-                FrameSubMetric.BasicFrameTime -> rtSlice.endTs - uiSlice.ts
-                FrameSubMetric.UiFrameTime -> uiSlice.dur
-                FrameSubMetric.FrameSlackTime -> expectedSlice!!.endTs - actualSlice!!.endTs
+                SubMetric.FrameCpuTime -> rtSlice.endTs - uiSlice.ts
+                SubMetric.FrameUiTime -> uiSlice.dur
+                SubMetric.FrameNegativeSlackTime -> actualSlice!!.endTs - expectedSlice!!.endTs
             }
         }
         companion object {
@@ -140,7 +138,7 @@
         absoluteTracePath: String,
         captureApiLevel: Int,
         packageName: String,
-    ): Map<FrameSubMetric, List<Long>> {
+    ): Map<SubMetric, List<Long>> {
         val queryResult = PerfettoTraceProcessor.rawQuery(
             absoluteTracePath = absoluteTracePath,
             query = getFullQuery(packageName)
@@ -199,7 +197,7 @@
             }
         }
 
-        return FrameSubMetric.values()
+        return SubMetric.values()
             .filter { it.supportedOnApiLevel(captureApiLevel) }
             .associateWith { subMetric ->
                 frameData.map { frame -> frame.get(subMetric) }
diff --git a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialListScrollBenchmark.kt b/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialListScrollBenchmark.kt
index 605f409..cb24edb 100644
--- a/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialListScrollBenchmark.kt
+++ b/benchmark/integration-tests/macrobenchmark/src/androidTest/java/androidx/benchmark/integration/macrobenchmark/TrivialListScrollBenchmark.kt
@@ -19,8 +19,8 @@
 import android.content.Intent
 import android.graphics.Point
 import androidx.benchmark.macro.CompilationMode
+import androidx.benchmark.macro.FrameTimingGfxInfoMetric
 import androidx.benchmark.macro.FrameTimingMetric
-import androidx.benchmark.macro.FrameTimingTraceMetric
 import androidx.benchmark.macro.junit4.MacrobenchmarkRule
 import androidx.test.filters.LargeTest
 import androidx.test.platform.app.InstrumentationRegistry
@@ -53,7 +53,7 @@
     fun start() {
         benchmarkRule.measureRepeated(
             packageName = PACKAGE_NAME,
-            metrics = listOf(FrameTimingMetric(), FrameTimingTraceMetric()),
+            metrics = listOf(FrameTimingMetric(), FrameTimingGfxInfoMetric()),
             compilationMode = compilationMode,
             iterations = 10,
             setupBlock = {
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/NestedListsScrollBenchmark.kt b/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/NestedListsScrollBenchmark.kt
index 0390523..4b3fe6b 100644
--- a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/NestedListsScrollBenchmark.kt
+++ b/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/NestedListsScrollBenchmark.kt
@@ -19,6 +19,7 @@
 import android.content.Intent
 import android.graphics.Point
 import androidx.benchmark.macro.CompilationMode
+import androidx.benchmark.macro.FrameTimingGfxInfoMetric
 import androidx.benchmark.macro.FrameTimingMetric
 import androidx.benchmark.macro.junit4.MacrobenchmarkRule
 import androidx.test.filters.LargeTest
@@ -53,7 +54,7 @@
     fun start() {
         benchmarkRule.measureRepeated(
             packageName = PACKAGE_NAME,
-            metrics = listOf(FrameTimingMetric()),
+            metrics = listOf(FrameTimingMetric(), FrameTimingGfxInfoMetric()),
             compilationMode = compilationMode,
             iterations = 10,
             setupBlock = {
diff --git a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/TrivialListScrollBenchmark.kt b/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/TrivialListScrollBenchmark.kt
index 08310ca..102d4ee 100644
--- a/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/TrivialListScrollBenchmark.kt
+++ b/compose/integration-tests/macrobenchmark/src/androidTest/java/androidx/compose/integration/macrobenchmark/TrivialListScrollBenchmark.kt
@@ -19,6 +19,7 @@
 import android.content.Intent
 import android.graphics.Point
 import androidx.benchmark.macro.CompilationMode
+import androidx.benchmark.macro.FrameTimingGfxInfoMetric
 import androidx.benchmark.macro.FrameTimingMetric
 import androidx.benchmark.macro.junit4.MacrobenchmarkRule
 import androidx.test.filters.LargeTest
@@ -53,7 +54,7 @@
     fun start() {
         benchmarkRule.measureRepeated(
             packageName = PACKAGE_NAME,
-            metrics = listOf(FrameTimingMetric()),
+            metrics = listOf(FrameTimingMetric(), FrameTimingGfxInfoMetric()),
             compilationMode = compilationMode,
             iterations = 10,
             setupBlock = {