Capturer les métriques Macrobenchmark

Les métriques sont le principal type d'informations extraites de vos analyses comparatives. Elles sont transmises à la measureRepeated fonction en tant que List, ce qui vous permet de préciser plusieurs métriques mesurées à la fois. Au moins un type de métrique est requis pour que l'analyse comparative s'exécute.

L'extrait de code suivant capture les métriques de temps de rendu et de section de trace personnalisée pour une interface de mise en page paresseuse 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)
            }
        }
    }

Dans l'exemple suivant, EntryRowCustomTrace représente une section de trace personnalisée définie dans les couches d'éléments modulables à l'aide du wrapper de bloc Kotlin standard trace(sectionName) { ... }. Pour fournir des données à TraceSectionMetric, vous devez encapsuler les composants d'interface utilisateur cibles dans la base de code de production de votre application avec le wrapper de bloc trace Jetpack Runtime 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)
            )
        }
    }
}

Les résultats de l'analyse comparative sont générés directement dans l'onglet de terminal Benchmark d'Android Studio, comme illustré dans la figure 1. Si plusieurs métriques sont définies, tous leurs points de données calculés sont combinés dans la fenêtre de résumé.

Résultats de TraceSectionMetric et de FrameTimingMetric
Figure 1. Résultats combinés de la console de TraceSectionMetric et FrameTimingMetric pour une mise en page Compose moderne.

StartupTimingMetric, FrameTimingMetric, TraceSectionMetric et PowerMetric sont abordés en détail ci-dessous. Pour obtenir la liste complète des métriques d'analyse comparative disponibles, consultez les sous-classes de Metric dans la documentation de référence de l'API.

StartupTimingMetric

StartupTimingMetric capture les métriques de temps de démarrage de l'application avec les valeurs suivantes :

  • timeToInitialDisplayMs: temps écoulé entre le moment où le système reçoit un intent de lancement et le moment où le premier frame de l'écran de destination est affiché.
  • timeToFullDisplayMs: temps écoulé entre le moment où le système reçoit un intent de lancement et le moment où l'application indique qu'elle est entièrement dessinée à l'aide des mécanismes de création de rapports de plate-forme internes. La mesure s'arrête une fois que le premier frame a été rendu après (ou avec) le signal entièrement dessiné.

StartupTimingMetric génère les valeurs minimale, médiane et maximale des itérations de démarrage. Pour évaluer l'amélioration du démarrage, concentrez-vous toujours sur les valeurs médianes, car elles fournissent la meilleure estimation des temps de démarrage typiques des utilisateurs.

Dans une architecture axée sur Compose, n'essayez pas d'appeler activity.reportFullyDrawn manuellement. Utilisez plutôt les utilitaires asynchrones sécurisés Compose ReportDrawn, ReportDrawnWhen ou ReportDrawnAfter dans vos composants modulables d'écran pour signaler automatiquement à Macrobenchmark lorsque vos données réseau asynchrones ou vos états d'interface utilisateur complexes ont terminé le rendu.

Pour en savoir plus sur l'analyse et l'optimisation des performances d'initialisation, consultez Temps de démarrage de l'application.

FrameTimingMetric

FrameTimingMetric capture des informations de codes temporels précises à partir des frames générés par un parcours d'analyse comparative, comme le défilement d'une liste ou une animation de mise en page d'interface utilisateur complexe, et génère les valeurs de diagnostic suivantes :

  • frameOverrunMs : temps de retard du frame par rapport à son échéance. Les nombres positifs indiquent un abandon du frame accompagné d'un à-coup ou d'une saccade visible. Les nombres négatifs indiquent l'avance d'un frame par rapport à l'échéance matérielle du sous-système. Remarque : Cette métrique n'est disponible que sur Android 12 (niveau d'API 31) ou version ultérieure.
  • frameDurationCpuMs: temps passé par le frame à être produit activement sur le processeur au niveau du thread d'interface utilisateur de l'application principale et du RenderThread Compose.

Ces mesures sont collectées par étapes de 50, 90, 95 et 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

Lorsque vous optimisez les hiérarchies de mise en page Jetpack Compose, examinez les frames les moins performants (limites P95 et P99). Si frameOverrunMs atteint des nombres entiers positifs aux centiles élevés, cela indique que les recompositions bloquent le thread principal lors d'animations de défilement importantes.

Pour en savoir plus sur l'identification et la résolution des frames lents, consultez Performances de Jetpack Compose.

TraceSectionMetric

TraceSectionMetric capture le nombre de fois qu'une section de trace spécifique se produit et le temps absolu nécessaire à son exécution. Pour le suivi du temps, elle renvoie les durées minimale, médiane et maximale en millisecondes. La section de trace cible est définie soit par l'appel de fonction trace(sectionName)ou les limites de bloc de niveau inférieur entreTrace.beginSection(sectionName) et Trace.endSection() ou leursvariantes asynchrones.

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

Par défaut, la métrique ne génère que les sections de trace compilées directement à partir des binaires du package de votre propre application. Pour inclure des processus provenant de l'extérieur de la limite du package de votre application, définissez la propriété targetPackageOnly = false.

Lorsque vous travaillez sur le traçage d'exécution Jetpack Compose, vous pouvez afficher des fonctions modulables individuelles dans vos graphiques de trace système sans écrire de wrappers de trace manuels en activant le traçage de composition.

Bien que l'ajout de la dépendance androidx.compose.runtime:runtime-tracing à votre application cible soit suffisant pour les traces de profileur manuelles, la capture de ces traces par programmation lors d'une exécution Macrobenchmark nécessite une configuration supplémentaire dans votre module d'analyse comparative.

Pour obtenir des instructions de configuration complètes, consultez Capturer une trace avec Jetpack Macrobenchmark.

PowerMetric

PowerMetric capture l'évolution de puissance ou d'énergie pendant la durée de votre exécution Macrobenchmark. Chaque catégorie sélectionnée est divisée en composants matériels mesurables, tandis que les catégories non sélectionnées sont regroupées dans un bucket "non sélectionné".

Exigence matérielle : ces métriques mesurent la consommation à l'échelle du système, et non les calculs par application. Par conséquent, la collecte de données est limitée aux appareils physiques Google Pixel 6, Pixel 6 Pro et plus récents.

La métrique génère deux mesures par catégorie :

  • power<category>Uw : quantité d'énergie consommée pendant la durée de votre test dans cette catégorie (mesurée en microwatts).
  • energy<category>Uws : quantité totale d'énergie transférée par unité de temps pendant la durée de votre test dans cette catégorie (mesurée en microwatt-secondes).

Les catégories suivantes sont incluses :

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

Avec certaines catégories, comme CPU, il peut être difficile de séparer le travail effectué par d'autres processus de celui effectué par votre propre application. Réduisez les interférences en supprimant ou en limitant les applications et les comptes inutiles.

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

Analyse des sous-systèmes principaux

PowerMetric capture l'évolution de puissance ou d'énergie pendant la durée du test pour les catégories d'énergie fournies. Chaque catégorie sélectionnée est divisée en sous-composants mesurables, tandis que les catégories non sélectionnées sont ajoutées à la métrique "non sélectionnée".

Les sorties du terminal correspondent à la configuration que vous demandez :

  • powerCategoryCpuUw: quantité d'énergie consommée par le processeur pendant la durée de votre test.
  • powerCategoryGpuUw: quantité d'énergie consommée par le GPU pendant la durée de votre test.
  • powerUnselectedUw: puissance agrégée consommée par toutes les catégories de matériel disponibles qui n'ont pas été explicitement demandées dans votre carte d'initialisation.

Pour éviter les pics de données erratiques sur les rails matériels lors d'une exécution, verrouillez la luminosité de l'écran sur une valeur fixe, maintenez une température stable de l'appareil et fermez les processus d'arrière-plan concurrents avant de démarrer la boucle Macrobenchmark.

Ressources supplémentaires

Afficher le contenu