Acquisisci le metriche di Macrobenchmark

Le metriche sono il tipo principale di informazioni estratte dai benchmark. Vengono trasmesse alla funzione measureRepeated come List, che ti consente di specificare più metriche misurate contemporaneamente. Per l'esecuzione del benchmark è richiesto almeno un tipo di metrica.

Il seguente snippet di codice acquisisce le metriche relative alla tempistica dei frame e alla sezione di traccia personalizzata per un'interfaccia di layout pigro 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)
            }
        }
    }

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

@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 inviati direttamente alla scheda del terminale Benchmark all'interno di Android Studio, come mostrato nella Figura 1. Se vengono definite più metriche, tutti i 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 nei riferimenti API.

StartupTimingMetric

StartupTimingMetric acquisisce le metriche di temporizzazione dell'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 il momento in cui viene visualizzato il primo frame della schermata di destinazione.
  • timeToFullDisplayMs: il periodo di tempo che intercorre tra il momento in cui il sistema riceve un intent di avvio e il momento in cui l'app segnala di essere stata disegnata completamente utilizzando i meccanismi di generazione di report della piattaforma interni. La misurazione si interrompe al completamento del rendering del primo frame dopo o contenente il segnale completamente disegnato.

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 migliore stima dei tempi di avvio tipici degli utenti.

In un'architettura Compose-first, non tentare di richiamare activity.reportFullyDrawn manualmente. Utilizza invece le utilità asincrone sicure per Compose ReportDrawn, ReportDrawnWhen o ReportDrawnAfter all'interno dei composable dello schermo per segnalare automaticamente a Macrobenchmark quando il rendering dei dati di rete asincroni o degli stati complessi della UI è terminato.

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

FrameTimingMetric

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

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

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

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 aumenta in numeri interi positivi ai percentili elevati, indica che le ricomposizioni stanno bloccando il thread principale durante le animazioni di scorrimento intenso.

Per informazioni più approfondite sull'identificazione e la risoluzione dei problemi relativi ai frame lenti, consulta Jetpack Compose Performance.

TraceSectionMetric

TraceSectionMetric acquisisce il numero di volte in cui si verifica una sezione specifica della traccia e il tempo assoluto necessario per l'esecuzione. Per il monitoraggio del tempo, vengono restituiti i tempi minimo, mediano e massimo in millisecondi. La sezione di traccia di destinazione è definita dalla chiamata di funzione trace(sectionName) o dai limiti dei blocchi di livello inferiore tra Trace.beginSection(sectionName) e Trace.endSection() o dalle loro 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 binari del pacchetto dell'applicazione. Per includere i processi provenienti dall'esterno del limite del pacchetto dell'app, imposta la proprietà targetPackageOnly = false.

Quando lavori sul tracciamento di Jetpack Compose Runtime, puoi visualizzare 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 manuale, l'acquisizione di queste tracce a livello di programmazione all'interno di un'esecuzione di Macrobenchmark richiede una configurazione aggiuntiva all'interno del modulo di benchmark.

Per istruzioni di configurazione complete, vedi Acquisire una traccia con Jetpack Macrobenchmark.

PowerMetric

PowerMetric acquisisce la variazione di potenza o energia durante l'esecuzione di Macrobenchmark. Ogni categoria selezionata viene suddivisa nei suoi componenti hardware misurabili, mentre le categorie non selezionate vengono raggruppate in un bucket "non selezionate".

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 più recenti.

La metrica genera due misurazioni per categoria:

  • power<category>Uw: la quantità di energia consumata durante la durata del 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 le interferenze, rimuovi o limita app e 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 durante la durata del test per le categorie di potenza fornite. Ogni categoria selezionata viene suddivisa nei suoi sottocomponenti misurabili e le categorie non selezionate vengono aggiunte alla metrica "Non selezionate".

L'output del terminale corrisponde alla configurazione richiesta:

  • powerCategoryCpuUw: la quantità di energia consumata dalla CPU durante la durata del test.
  • powerCategoryGpuUw: la quantità di energia consumata dalla GPU durante la durata del 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 binari hardware durante una corsa, 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 iniziare il ciclo Macrobenchmark.

Risorse aggiuntive

Visualizza contenuti