Messwerte sind die wichtigsten Informationen, die aus Ihren Benchmarks extrahiert werden. Sie werden als List an die Funktion measureRepeated übergeben, sodass Sie mehrere gemessene Messwerte gleichzeitig angeben können. Für die Ausführung des Benchmarks ist mindestens ein Messwerttyp erforderlich.
Im folgenden Code-Snippet werden Frame-Timing- und benutzerdefinierte Trace-Abschnittsmesswerte für eine Lazy-Layout-Oberfläche von Jetpack Compose erfasst:
@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)
}
}
}
Im folgenden Beispiel steht EntryRowCustomTrace für einen benutzerdefinierten Trace-Abschnitt, der innerhalb der Ebenen des zusammensetzbaren Elements mit dem standardmäßigen Kotlin-Block-Wrapper trace(sectionName) { ... } definiert ist. Wenn Sie Daten für TraceSectionMetric bereitstellen möchten, müssen Sie die Ziel-UI-Komponenten in der Produktionscodebasis Ihrer Anwendung mit dem Standard-Jetpack-Laufzeit-trace-Block-Wrapper umschließen:
@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)
)
}
}
}
Die Benchmark-Ergebnisse werden direkt auf dem Terminal-Tab Benchmark in Android Studio ausgegeben, wie in Abbildung 1 dargestellt. Wenn mehrere Messwerte definiert sind, werden alle berechneten Datenpunkte im Zusammenfassungsfenster kombiniert.
TraceSectionMetric und FrameTimingMetric für ein modernes Compose-Layout.StartupTimingMetric, FrameTimingMetric, TraceSectionMetric und PowerMetric werden unten ausführlich behandelt. Eine vollständige Liste der verfügbaren Benchmark-Messwerte finden Sie in der API-Referenz unter den abgeleiteten Klassen von Metric.
StartupTimingMetric
StartupTimingMetric erfasst Zeitmesswerte für den App-Start mit den folgenden Werten:
timeToInitialDisplayMs: Die Zeitspanne zwischen dem Empfang eines Start-Intents durch das System und dem Rendern des ersten Frames des Zielbildschirms.timeToFullDisplayMs: Die Zeitspanne zwischen dem Empfang eines Start-Intents durch das System und dem Zeitpunkt, an dem die App über die internen Berichtsmechanismen der Plattform meldet, dass sie vollständig gerendert wurde. Die Messung endet, wenn das Rendern des ersten Frames nach dem Signal „Vollständig gezeichnet“ oder mit diesem Signal abgeschlossen ist.
StartupTimingMetric gibt die Minimal-, Median- und Maximalwerte aus den Startiterationen aus. Konzentrieren Sie sich bei der Bewertung der Startverbesserung immer auf die Medianwerte, da diese die beste Schätzung der typischen Startzeiten für Nutzer liefern.
In einer Compose-First-Architektur sollten Sie nicht versuchen, activity.reportFullyDrawn manuell aufzurufen. Verwenden Sie stattdessen die Compose-sicheren asynchronen Dienstprogramme ReportDrawn, ReportDrawnWhen oder ReportDrawnAfter in Ihren Bildschirm-Composables, um Macrobenchmark automatisch zu signalisieren, wenn das Rendern Ihrer asynchronen Netzwerkdaten oder komplexen UI-Zustände abgeschlossen ist.
Weitere Informationen zum Analysieren und Optimieren der Initialisierungsleistung finden Sie unter Startzeit der App.
FrameTimingMetric
FrameTimingMetric erfasst genaue Zeitinformationen aus Frames, die von einer Benchmark-Journey erzeugt werden, z. B. beim Scrollen durch eine Liste oder bei einer komplexen UI-Layout-Animation, und gibt die folgenden Diagnosewerte aus:
frameOverrunMs: die Zeitspanne, um die ein bestimmter Frame seine Frist verpasst. Positive Zahlen weisen auf einen ausgelassenen Frame hin, der mit sichtbarem Ruckeln oder Stottern einhergeht. Negative Zahlen geben an, wie viel schneller ein Frame im Vergleich zur Hardware-Frist des Subsystems abgeschlossen wurde. Hinweis: Dieser Messwert ist nur ab Android 12 (API-Level 31) verfügbar.frameDurationCpuMs: die Zeit, die der Frame aktiv auf der CPU sowohl im Haupt-UI-Thread der Anwendung als auch im Compose-RenderThreadproduziert wurde.
Diese Messwerte werden in einer Verteilung des 50., 90., 95. und 99. Perzentils erfasst:
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
Wenn Sie Jetpack Compose-Layouthierarchien optimieren, sollten Sie sich die Frames mit der schlechtesten Leistung ansehen (die P95- und P99-Grenzen). Wenn frameOverrunMs bei den hohen Perzentilen in positive Ganzzahlen steigt, deutet das darauf hin, dass Neuzusammensetzungen den Hauptthread während starker Scrollanimationen blockieren.
Weitere Informationen zum Identifizieren und Beheben langsamer Frames finden Sie unter Jetpack Compose-Leistung.
TraceSectionMetric
TraceSectionMetric erfasst, wie oft ein bestimmter Trace-Abschnitt auftritt und wie lange die Ausführung absolut dauert. Für die Zeiterfassung werden die Mindest-, Median- und Höchstzeiten in Millisekunden ausgegeben. Der Ziel-Trace-Abschnitt wird entweder durch den Funktionsaufruf trace(sectionName) oder die untergeordneten Blockgrenzen zwischen Trace.beginSection(sectionName) und Trace.endSection() oder deren asynchrone Varianten definiert.
EntryRowCustomTraceCount min 20.0, median 28.0, max 50.0
EntryRowCustomTraceSumMs min 34.9, median 44.4, max 66.6
Standardmäßig werden im Messwert nur Trace-Abschnitte ausgegeben, die direkt aus den Binärdateien Ihres eigenen Anwendungspakets kompiliert wurden. Wenn Sie Prozesse einbeziehen möchten, die von außerhalb der Paketgrenze Ihrer App stammen, legen Sie das Attribut targetPackageOnly = false fest.
Wenn Sie mit Jetpack Compose Runtime Tracing arbeiten, können Sie einzelne zusammensetzbare Funktionen in Ihren System-Trace-Diagrammen anzeigen lassen, ohne manuelle Trace-Wrapper schreiben zu müssen. Aktivieren Sie dazu Composition Tracing.
Das Hinzufügen der androidx.compose.runtime:runtime-tracing-Abhängigkeit zu Ihrer Zielanwendung reicht für manuelle Profiler-Traces aus. Wenn Sie diese Traces jedoch programmatisch in einem Macrobenchmark-Lauf erfassen möchten, ist eine zusätzliche Konfiguration in Ihrem Benchmark-Modul erforderlich.
Eine vollständige Anleitung zur Einrichtung finden Sie unter Trace mit Jetpack Macrobenchmark erfassen.
PowerMetric
PowerMetric erfasst die Änderung der Leistung oder Energie während der Ausführung des Makrobenchmarks. Jede ausgewählte Kategorie wird in ihre messbaren Hardwarekomponenten aufgeschlüsselt, während nicht ausgewählte Kategorien in einem „Nicht ausgewählt“-Bucket zusammengefasst werden.
Hardwareanforderung: Mit diesen Messwerten wird der systemweite Verbrauch gemessen, nicht der Verbrauch pro App. Daher ist die Datenerhebung auf physische Google Pixel 6-, Pixel 6 Pro- und neuere physische Geräte beschränkt.
Der Messwert gibt zwei Messungen pro Kategorie aus:
power<category>Uw: die Menge an Strom, die während des Tests in dieser Kategorie verbraucht wurde (gemessen in Mikrowatt).energy<category>Uws: die Gesamtmenge an Energie, die pro Zeiteinheit während des Tests in dieser Kategorie übertragen wurde (gemessen in Mikrowattsekunden).
Dazu gehören folgende Kategorien:
CPUDISPLAYGPUGPSMEMORYMACHINE_LEARNINGNETWORKUNCATEGORIZED
Bei einigen Kategorien, z. B. CPU, kann es schwierig sein, die von anderen Prozessen ausgeführten Aufgaben von den Aufgaben Ihrer eigenen App zu trennen. Um die Beeinträchtigung zu minimieren, entfernen oder beschränken Sie unnötige Apps und Konten.
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
Wichtige Subsysteme analysieren
PowerMetric erfasst die Änderung der Leistung oder Energie über die Dauer des Tests für die angegebenen Leistungskategorien. Jede ausgewählte Kategorie wird in ihre messbaren Unterkomponenten aufgeschlüsselt. Nicht ausgewählte Kategorien werden dem Messwert „Nicht ausgewählt“ hinzugefügt.
Die Terminalausgaben entsprechen der von Ihnen angeforderten Konfiguration:
powerCategoryCpuUw: Die von der CPU während des Tests verbrauchte Energie.powerCategoryGpuUw: Die von der GPU während des Tests verbrauchte Strommenge.powerUnselectedUw: Die Gesamtleistung, die von allen verfügbaren Hardwarekategorien verbraucht wird, die nicht explizit in Ihrer Initialisierungszuordnung angefordert wurden.
Um unregelmäßige Datenspitzen auf den Hardwareschienen während eines Laufs zu vermeiden, sperre die Bildschirmhelligkeit auf einen festen Wert, halte die Gerätetemperatur stabil und schließe konkurrierende Hintergrundprozesse, bevor du die Macrobenchmark-Schleife startest.
Zusätzliche Ressourcen
Inhalte ansehen
Empfehlungen für Sie
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Baseline-Profile erstellen {:#creating-profile-rules}
- Makro-Benchmark schreiben
- Analyse und Optimierung des App-Starts {:#app-startup-analysis-optimization}