Acquisisci le metriche di Macrobenchmark

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

Il seguente snippet di codice acquisisce le metriche di tempistica dei frame e della 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 di 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 codebase di produzione dell'applicazione con il wrapper di blocco trace del 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 restituiti direttamente nella 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 trattate 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 di tempistica di avvio dell'app con i seguenti valori:

  • timeToInitialDisplayMs: la quantità di tempo che intercorre tra il momento in cui il sistema riceve un intent di avvio e il momento in cui esegue il rendering del primo frame della schermata di destinazione.
  • timeToFullDisplayMs: la quantità di tempo che intercorre tra il momento in cui il sistema riceve un intent di avvio e il momento in cui l'app segnala il rendering completo utilizzando i meccanismi di reporting della piattaforma interni. La misurazione si interrompe al completamento del rendering del primo frame dopo o contenente il segnale di rendering completo.

StartupTimingMetric restituisce i valori minimi, mediani e massimi delle iterazioni di avvio. Per valutare il miglioramento dell'avvio, concentrati sempre sui valori mediani, in quanto 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 componibili della schermata per segnalare automaticamente a Macrobenchmark quando il rendering dei dati di rete asincroni o degli stati UI complessi è terminato.

Per saperne di più sull'analisi e l'ottimizzazione del rendimento dell'inizializzazione, consulta 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 di layout UI complessa, e restituisce i seguenti valori diagnostici:

  • frameOverrunMs: la quantità di tempo per cui un determinato frame non rispetta la scadenza. I numeri positivi indicano un frame eliminato accompagnato da jank o stuttering visibili. I numeri negativi indicano la velocità con cui un frame è stato completato rispetto alla scadenza dell'hardware del sottosistema. Nota: questa metrica è disponibile solo su Android 12 (livello API 31) e versioni successive.
  • frameDurationCpuMs: la quantità di tempo in cui il frame è stato prodotto attivamente sulla CPU sia nel thread dell'interfaccia utente dell'applicazione principale sia in RenderThread di Compose.

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 raggiunge numeri interi positivi ai percentili elevati, significa che le ricomposizioni bloccano il thread principale durante le animazioni di scorrimento pesanti.

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

TraceSectionMetric

TraceSectionMetric acquisisce il numero di volte in cui si verifica una sezione di traccia specifica e la quantità assoluta di tempo necessaria per l'esecuzione. Per il monitoraggio del tempo, restituisce i tempi minimi, mediani e massimi in millisecondi. La sezione di traccia di destinazione viene definita dalla chiamata di funzione trace(sectionName)o dai limiti di blocco di livello inferiore tra Trace.beginSection(sectionName) e Trace.endSection() o le 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 limite del pacchetto dell'app, imposta la proprietà targetPackageOnly = false.

Quando lavori con la traccia del runtime di Jetpack Compose, puoi visualizzare le singole funzioni componibili nei grafici di traccia del sistema senza scrivere wrapper di traccia manuali attivando la traccia 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 a livello di programmazione all'interno di un'esecuzione di Macrobenchmark richiede una configurazione aggiuntiva nel modulo di benchmark.

Per istruzioni di configurazione complete, consulta 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 relativi componenti hardware misurabili, mentre le categorie non selezionate vengono raggruppate in un bucket "non selezionato".

Requisiti 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 successivi.

La metrica restituisce due misurazioni per categoria:

  • power<category>Uw: la quantità di energia consumata durante il tuo test in questa categoria (misurata in microwatt).
  • energy<category>Uws: la quantità totale di energia trasferita per unità di tempo durante il 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 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

Analizzare i sottosistemi principali

PowerMetric acquisisce la variazione di potenza o energia durante il test per le categorie di potenza fornite. Ogni categoria selezionata viene suddivisa nei relativi sottocomponenti misurabili e le categorie non selezionate vengono aggiunte alla metrica "non selezionata".

L'output del terminale corrisponde 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: l'energia 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 un'esecuzione, blocca la luminosità dello schermo su un valore fisso, mantieni una temperatura stabile del dispositivo e chiudi i processi in background concorrenti prima di avviare il loop di Macrobenchmark.

Risorse aggiuntive

Visualizza i contenuti