Acquisisci le metriche di Macrobenchmark

Le metriche sono il tipo principale di informazioni estratte dai benchmark. Vengono passati alla funzione measureRepeated come List, il che ti consente di specificare più metriche misurate contemporaneamente. Per eseguire il benchmark è necessario almeno un tipo di metrica.

Il seguente snippet di codice acquisisce le metriche relative alla durata frame e alla sezione di traccia personalizzata per un'interfaccia di layout lazy di Jetpack Compose:

@OptIn(ExperimentalMetricApi::class)
    @Test
    fun scrollComposeList() {
        benchmarkRule.measureRepeated(
            // [START_EXCLUDE]
            packageName = TARGET_PACKAGE,
            metrics = listOf(
                FrameTimingMetric(),
                // Measure power usage. This is supported on Pixel 6 and later.
                PowerMetric(PowerMetric.Type.Power(
                    mapOf(
                        PowerCategory.CPU to PowerCategoryDisplayLevel.TOTAL,
                        PowerCategory.DISPLAY to PowerCategoryDisplayLevel.TOTAL,
                        PowerCategory.GPU to PowerCategoryDisplayLevel.TOTAL,
                        PowerCategory.NETWORK to PowerCategoryDisplayLevel.TOTAL,
                    )
                )),
                // Measure custom trace sections by name EntryRow (which is added to the EntryRow composable).
                // Mode.Sum measures combined duration and also how many times it occurred in the trace.
                // This way, you can estimate whether a composable recomposes more than it should.
                TraceSectionMetric("EntryRowCustomTrace", TraceSectionMetric.Mode.Sum),
                // This trace section takes into account the SQL wildcard character %,
                // which can find trace sections without the full name.
                // This way, you can measure composables produced by the composition tracing
                // and measure how long they took and how many times they recomposed.
                // WARNING: This metric only shows results when running with composition tracing, otherwise it won't be visible in the outputs.
                TraceSectionMetric("%EntryRow%", TraceSectionMetric.Mode.Sum),
            ),
            // Try switching to different compilation modes to see the effect
            // it has on frame timing metrics.
            compilationMode = CompilationMode.None(),
            startupMode = StartupMode.WARM, // restarts activity each iteration
            iterations = DEFAULT_ITERATIONS,
            // [END_EXCLUDE]
            setupBlock = {
                uiAutomator {
                    // Before starting to measure, navigate to the UI to be measured.
                    startIntent(Intent("$packageName.COMPOSE_ACTIVITY"))
                }
            }
        ) {
            uiAutomator {
                onElement { isScrollable }.fling(Direction.DOWN)
            }
        }
    }

Nell'esempio seguente, EntryRowCustomTrace rappresenta una sezione di traccia personalizzata definita all'interno dei livelli degli elementi componibili utilizzando il wrapper di blocchi Kotlin trace(sectionName) { ... } standard. Per fornire i dati per TraceSectionMetric, devi aggregare i componenti dell'interfaccia utente di destinazione all'interno del codebase di produzione della tua applicazione con il wrapper del blocco di runtime Jetpack standard trace:

@Composable
private fun EntryRow(entry: Entry, modifier: Modifier = Modifier) = trace("EntryRowCustomTrace") {
    Card(modifier = modifier) {
        Row(verticalAlignment = Alignment.CenterVertically) {
            Text(
                text = entry.contents,
                modifier = Modifier
                    .padding(16.dp)
                    .wrapContentSize()
            )

            Spacer(modifier = Modifier.weight(1f))

            Checkbox(
                checked = false,
                onCheckedChange = {},
                modifier = Modifier.padding(16.dp)
            )
        }
    }
}

I risultati del benchmark vengono visualizzati direttamente nella scheda del terminale Benchmark all'interno di Android Studio, come mostrato nella Figura 1. Se sono definite più metriche, tutti i relativi punti dati calcolati vengono combinati nella finestra di riepilogo.

Risultati di TraceSectionMetric e FrameTimingMetric.
Figura 1. Risultati combinati della console di TraceSectionMetric e FrameTimingMetric per un layout Compose moderno.

StartupTimingMetric, FrameTimingMetric, TraceSectionMetric e PowerMetric sono trattati in dettaglio di seguito. Per un elenco completo delle metriche di benchmark disponibili, consulta le sottoclassi di Metric nel riferimento API.

StartupTimingMetric

StartupTimingMetric acquisisce le metriche relative ai tempi di avvio dell'app con i seguenti valori:

  • timeToInitialDisplayMs: il tempo che intercorre tra il momento in cui il sistema riceve un intent di avvio e quello in cui esegue il rendering del primo frame della schermata di destinazione.
  • timeToFullDisplayMs: il tempo che intercorre tra la ricezione di un intent di lancio da parte del sistema e la segnalazione da parte dell'app del completamento del disegno utilizzando i meccanismi di reporting della piattaforma interna. La misurazione si interrompe al completamento del rendering del primo frame dopo o contenente l'indicatore di disegno completo.

StartupTimingMetric restituisce i valori minimo, mediano e massimo delle iterazioni di avvio. Per valutare il miglioramento dell'avvio, concentrati sempre sui valori mediani, poiché forniscono la stima migliore dei tempi di avvio tipici degli utenti.

In un'architettura basata su Compose, non tentare di richiamare activity.reportFullyDrawn manualmente. Utilizza invece le utilità asincrone sicure per Compose ReportDrawn, ReportDrawnWhen o ReportDrawnAfter all'interno dei composabili della schermata per segnalare automaticamente a Macrobenchmark quando i dati di rete asincroni o gli stati complessi della UI hanno terminato il rendering.

Per saperne di più sull'analisi e sull'ottimizzazione delle prestazioni di inizializzazione, consulta Tempo di avvio dell'app.

FrameTimingMetric

FrameTimingMetric acquisisce informazioni precise sulla sincronizzazione dai frame prodotti da un percorso di benchmark, ad esempio lo scorrimento di un elenco o un'animazione di layout UI complessa, e restituisce i seguenti valori diagnostici:

  • frameOverrunMs: il tempo di ritardo di un determinato frame rispetto alla scadenza. I numeri positivi indicano un frame saltato accompagnato da jank o stuttering visibili. I numeri negativi indicano quanto più velocemente è stato completato un frame rispetto alla scadenza dell'hardware del sottosistema. Nota: questa metrica è disponibile solo su Android 12 (livello API 31) e versioni successive.
  • frameDurationCpuMs: il tempo impiegato dal frame per essere prodotto attivamente sulla CPU sia nel thread dell'interfaccia utente dell'applicazione principale sia nel RenderThread di Compose.

Queste misurazioni vengono raccolte in una distribuzione di 50°, 90°, 95° e 99° percentile:

frameDurationCpuMs P50 3.5, P90 6.0, P95 6.4, P99 11.0
frameOverrunMs P50 -11.6, P90 -7.2, P95 -7.1, P99 -1.2

Quando ottimizzi le gerarchie di layout di Jetpack Compose, esamina i frame con il rendimento peggiore (i limiti P95 e P99). Se frameOverrunMs raggiunge picchi di numeri interi positivi nei percentili elevati, significa che le ricomposizioni stanno bloccando il thread principale durante le animazioni di scorrimento intenso.

Per informazioni più approfondite sull'identificazione e la risoluzione dei frame lenti, consulta Prestazioni di Jetpack Compose.

TraceSectionMetric

TraceSectionMetric acquisisce il numero di volte in cui si verifica una sezione di traccia specifica e il tempo assoluto necessario per l'esecuzione. Per il monitoraggio del tempo, restituisce i tempi minimo, mediano e massimo in millisecondi. La sezione della traccia target è definita dalla chiamata di funzione trace(sectionName) o dai confini del blocco di livello inferiore tra Trace.beginSection(sectionName) e Trace.endSection() o dalle relative varianti asincrone.

EntryRowCustomTraceCount min 20.0, median 28.0, max 50.0
EntryRowCustomTraceSumMs min 34.9, median 44.4, max 66.6

Per impostazione predefinita, la metrica restituisce solo le sezioni di traccia compilate direttamente dai file binari del pacchetto dell'applicazione. Per includere i processi provenienti dall'esterno del confine del pacchetto della tua app, imposta la proprietà targetPackageOnly = false.

Quando lavori al tracciamento del runtime di Jetpack Compose, puoi mostrare singole funzioni componibili nei grafici di tracciamento del sistema senza scrivere wrapper di tracciamento manuali attivando il tracciamento della composizione.

Sebbene l'aggiunta della dipendenza androidx.compose.runtime:runtime-tracing all'applicazione di destinazione sia sufficiente per le tracce del profiler manuali, l'acquisizione di queste tracce in modo programmatico all'interno di un'esecuzione di Macrobenchmark richiede una configurazione aggiuntiva all'interno del modulo di benchmark.

Per istruzioni complete sulla configurazione, consulta Acquisisci una traccia con Jetpack Macrobenchmark.

PowerMetric

PowerMetric acquisisce la variazione di potenza o energia nel corso della durata dell'esecuzione di Macrobenchmark. Ogni categoria selezionata viene suddivisa nei suoi componenti hardware misurabili, mentre le categorie non selezionate vengono raggruppate in un bucket "Non selezionato".

Requisito hardware: queste metriche misurano il consumo a livello di sistema anziché i calcoli per app. Di conseguenza, la raccolta dei dati è limitata ai dispositivi fisici Google Pixel 6, Pixel 6 Pro e dispositivi fisici più recenti.

La metrica genera due misurazioni per categoria:

  • power<category>Uw: la quantità di energia consumata durante il test in questa categoria (misurata in microwatt).
  • energy<category>Uws: la quantità totale di energia trasferita per unità di tempo per la durata del test in questa categoria (misurata in microwatt-secondi).

Le categorie includono:

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

Con alcune categorie, come CPU, potrebbe essere difficile separare il lavoro svolto da altri processi da quello svolto dalla tua app. Per ridurre al minimo l'interferenza, rimuovi o limita le app e gli account non necessari.

powerCategoryCpuUw min 300.2, median 346.1, max 519.6
powerCategoryDisplayUw min 319.8, median 325.8, max 329.7
powerCategoryGpuUw min 18.8, median 23.3, max 36.9
powerCategoryNetworkUw min 97.3, median 123.3, max 681.3
powerTotalUw min 1234.8, median 1316.6, max 2112.4
powerUnselectedUw       min  483.3,  median  512.6,  max  561.7

Analisi dei sottosistemi principali

PowerMetric acquisisce la variazione di potenza o energia nel corso del test per le categorie di potenza fornite. Ogni categoria selezionata viene suddivisa nei suoi componenti secondari misurabili e le categorie non selezionate vengono aggiunte alla metrica "Non selezionate".

Gli output del terminale vengono mappati alla configurazione richiesta:

  • powerCategoryCpuUw: la quantità di energia consumata dalla CPU durante il test.
  • powerCategoryGpuUw: la quantità di energia consumata dalla GPU durante il test.
  • powerUnselectedUw: la potenza aggregata consumata da tutte le categorie hardware disponibili che non sono state richieste esplicitamente nella mappa di inizializzazione.

Per evitare picchi di dati irregolari sui rail hardware durante un'esecuzione, blocca la luminosità dello schermo su un valore fisso, mantieni una temperatura stabile del dispositivo e chiudi i processi in background in competizione prima di avviare il loop di Macrobenchmark.

Risorse aggiuntive

Visualizza contenuti