Capture Macrobenchmark metrics

Metrics are the main type of information extracted from your benchmarks. They are passed to the measureRepeated function as a List, which lets you specify multiple measured metrics at once. At least one type of metric is required for the benchmark to run.

The following code snippet captures frame timing and custom trace section metrics:

Kotlin

benchmarkRule.measureRepeated(
    packageName = TARGET_PACKAGE,
    metrics = listOf(
        FrameTimingMetric(),
        TraceSectionMetric("RV CreateView"),
        TraceSectionMetric("RV OnBindView"),
    ),
    iterations = 5,
    // ...
)

Java

benchmarkRule.measureRepeated(
    TARGET_PACKAGE,     // packageName
    Arrays.asList(      // metrics
        new StartupTimingMetric(),
        new TraceSectionMetric("RV CreateView"),
        new TraceSectionMetric("RV OnBindView"),
    ),
    5,                  // Iterations
    // ...
);

In this example, RV CreateView and RV OnBindView are the IDs of traceable blocks that are defined in RecyclerView. The source code for the createViewHolder() method is an example of how you can define traceable blocks within your own code.

StartupTimingMetric, TraceSectionMetric, FrameTimingMetric, and PowerMetric, are covered in detail later in this document.

Benchmark results are output to Android Studio, as shown in figure 1. If multiple metrics are defined, all of them are combined in the output.

Results of TraceSectionMetric and FrameTimingMetric.
Figure 1. Results of TraceSectionMetric and FrameTimingMetric.

StartupTimingMetric

StartupTimingMetric captures app startup timing metrics with the following values:

  • timeToInitialDisplayMs: The amount of time from when the system receives a launch intent to when it renders the first frame of the destination Activity.
  • timeToFullDisplayMs: The amount of time from when the system receives a launch intent to when the app reports fully drawn using the reportFullyDrawn() method. The measurement stops at the completion of rendering the first frame after—or containing—the reportFullyDrawn() call. This measurement might not be available on Android 10 (API level 29) and earlier.

For more information about what contributes to app startup time, see App startup time.

StartupTimingMetric results
Figure 2. StartupTimingMetric results.

Improve startup timing accuracy

The two key metrics for measuring app startup times are time to initial display (TTID) and time to full display (TTFD). TTID is the time it takes to display the first frame of the application UI. TTFD also includes the time to display any content that loads asynchronously after the initial frame is displayed.

TTFD is reported once the reportFullyDrawn() method of the ComponentActivity is called. If reportFullyDrawn() is never called, the TTID is reported instead. You might need to delay when reportFullyDrawn() is called until after the asynchronous loading is complete. For example, if the UI contains a dynamic list, such as a RecyclerView or lazy list, this might be populated by a background task that completes after the list is first drawn and, therefore, after the UI is marked as fully drawn. In such cases, the list population isn't included in the benchmarking.

To include the list population as part of your benchmark timing, get the FullyDrawnReporter by using getFullyDrawnReporter(), and add a reporter to it in your app code. You must release the reporter once the background task finishes populating the list.

The FullyDrawnReporter doesn't call the reportFullyDrawn() method until all added reporters are released. By adding a reporter until the background process completes, the timings also include the amount of time it takes to populate the list in the startup timing data. This doesn't change the app's behavior for the user, but it lets the timing startup data include the time it takes to populate the list.

If your app uses Jetpack Compose, you can use the following APIs to indicate fully drawn state:

  • ReportDrawn: indicates that your composable is immediately ready for interaction.
  • ReportDrawnWhen: takes a predicate, such as list.count > 0, to indicate when your composable is ready for interaction.
  • ReportDrawnAfter: takes a suspending method that, once completed, indicates that your composable is ready for interaction.

FrameTimingMetric

FrameTimingMetric captures timing information from frames produced by a benchmark, such as a scrolling or animation, and outputs the following values:

  • frameOverrunMs: the amount of time a given frame misses its deadline by. Positive numbers indicate a dropped frame and visible jank or stutter. Negative numbers indicate how much faster a frame is than the deadline. Note: This is available only on Android 12 (API level 31) and higher.
  • frameDurationCpuMs: the amount of time the frame takes to be produced on the CPU on both the UI thread and the RenderThread.

These measurements are collected in a distribution of 50th, 90th, 95th, and 99th percentile.

For more information on how to identify and improve slow frames, see Slow rendering.

FrameTimingMetric results
Figure 3. FrameTimingMetric results.

TraceSectionMetric

TraceSectionMetric captures the number of times a trace section matching the provided sectionName occurs and the amount of time it takes. For the time, it outputs the minimum, median, and maximum times in milliseconds. The trace section is defined either by the function call trace(sectionName) or the code between Trace.beginSection(sectionName) and Trace.endSection() or their async variants. It always selects the first instance of a trace section captured during a measurement. It only outputs trace sections from your package by default; to include processes outside your package, set targetPackageOnly = false.

For more information about tracing, see Overview of system tracing and Define custom events.

TraceSectionMetric
Figure 4. TraceSectionMetric results.

PowerMetric

PowerMetric captures the change in power or energy over the duration of your test for the provided power categories. Each selected category is broken down into its measurable subcomponents, and unselected categories are added to the "unselected" metric.

These metrics measure system-wide consumption, not the consumption on a per-app basis, and are limited to Pixel 6, Pixel 6 Pro, and later devices:

  • power<category>Uw: the amount of power consumed over the duration of your test in this category.
  • energy<category>Uws: the amount of energy transferred per unit of time for the duration of your test in this category.

Categories include the following:

  • CPU
  • DISPLAY
  • GPU
  • GPS
  • MEMORY
  • MACHINE_LEARNING
  • NETWORK
  • UNCATEGORIZED

With some categories, like CPU, it might be difficult to separate work done by other processes from work done by your own app. To minimize the interference, remove or restrict unnecessary apps and accounts.

PowerMetric results
Figure 5. PowerMetric results.