Messwerte sind die wichtigste Art von Informationen, die aus Ihren Benchmarks extrahiert werden. Sie werden als List an die Funktion measureRepeated übergeben. So können Sie mehrere gemessene Messwerte gleichzeitig angeben. Damit der Benchmark ausgeführt werden kann, ist mindestens ein Messwerttyp erforderlich.
Im folgenden Code-Snippet werden Messwerte für das Frame-Timing und benutzerdefinierte Trace-Abschnitte für eine Lazy-Layout-Schnittstelle 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 in den zusammensetzbaren Elementen mit dem standardmäßigen Kotlin-Block-Wrapper trace(sectionName) { ... } definiert ist. Damit Sie Daten für TraceSectionMetric bereitstellen können, 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)
)
}
}
}
Benchmark-Ergebnisse werden direkt auf dem Terminaltab 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 den Unterklassen von Metric in der API-Referenz.
StartupTimingMetric
StartupTimingMetric erfasst Messwerte für das Timing des App-Starts 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 Zeit, die vergeht, bis das System eine Startabsicht empfängt und die App über die internen Berichtsmechanismen der Plattform meldet, dass sie vollständig gerendert wurde. Die Messung wird beendet, wenn der erste Frame nach dem oder mit dem vollständig gezeichneten Signal gerendert wird.
StartupTimingMetric gibt die Minimal-, Median- und Maximalwerte der Startiterationen aus. Konzentrieren Sie sich bei der Bewertung von Verbesserungen beim Start immer auf die Medianwerte, da sie die beste Schätzung der typischen Startzeiten für Nutzer darstellen.
In einer Compose-First-Architektur sollten Sie nicht versuchen, activity.reportFullyDrawn manuell aufzurufen. Verwenden Sie stattdessen die Compose-kompatiblen asynchronen Hilfsprogramme ReportDrawn, ReportDrawnWhen oder ReportDrawnAfter in Ihren Screen-Composables, um Macrobenchmark automatisch zu signalisieren, wenn Ihre asynchronen Netzwerkdaten oder komplexen UI-Zustände gerendert wurden.
Weitere Informationen zum Analysieren und Optimieren der Initialisierungsleistung finden Sie unter App-Startzeit.
FrameTimingMetric
FrameTimingMetric erfasst genaue Zeitinformationen von Frames, die von einem Benchmark-Ablauf generiert werden, z. B. beim Scrollen einer Liste oder einer komplexen Animation des UI-Layouts, und gibt die folgenden Diagnosewerte aus:
frameOverrunMs: Die Zeitspanne, um die ein bestimmter Frame seine Deadline verpasst. Positive Zahlen weisen auf einen ausgelassenen Frame hin, der zu sichtbaren Rucklern oder Stottern führt. Negative Zahlen geben an, wie viel schneller ein Frame im Vergleich zur Hardware-Deadline des Subsystems fertiggestellt wurde. Hinweis: Dieser Messwert ist nur für Android 12 (API-Level 31) und höher verfügbar.frameDurationCpuMs: Die Zeit, die der Frame aktiv auf der CPU verbracht hat, sowohl im Haupt-UI-Thread der Anwendung als auch im Compose-RenderThread.
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-Grenzwerte). Wenn frameOverrunMs in den oberen Perzentilen in positive Ganzzahlen ansteigt, deutet das darauf hin, dass Recompositionen den Hauptthread bei intensiven 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 die absolute Zeit, die für die Ausführung benötigt wird. Für die Zeitmessung werden die Mindest-, Median- und Höchstzeiten in Millisekunden ausgegeben. Der Zielabschnitt des Traces wird entweder durch den Funktionsaufruf trace(sectionName) oder die Blockgrenzen auf niedrigerer Ebene zwischen Trace.beginSection(sectionName) und Trace.endSection() oder deren asynchronen 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 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 die Property targetPackageOnly = false fest.
Wenn Sie an 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 aufzeichnen.
PowerMetric
Mit PowerMetric wird die Änderung der Leistung oder Energie während der Ausführung des Makrobenchmarks erfasst. Jede ausgewählte Kategorie wird in ihre messbaren Hardwarekomponenten unterteilt, während nicht ausgewählte Kategorien in einem Bucket „Nicht ausgewählt“ zusammengefasst werden.
Hardwareanforderung: Bei diesen Messwerten wird der systemweite Verbrauch gemessen und nicht der Verbrauch pro App. Die Datenerhebung ist daher 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 in dieser Kategorie während des Tests verbrauchte Leistung (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, ist es möglicherweise schwierig, die Arbeit anderer Prozesse von der Arbeit Ihrer eigenen App zu trennen. Um Störungen zu minimieren, sollten Sie unnötige Apps und Konten entfernen oder einschränken.
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
Kernsubsysteme 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 Terminalausgabe entspricht der angeforderten Konfiguration:
powerCategoryCpuUw: Die von der CPU während des Tests verbrauchte Leistung.powerCategoryGpuUw: Die von der GPU während des Tests verbrauchte Strommenge.powerUnselectedUw: Die aggregierte Leistung, die von allen verfügbaren Hardwarekategorien verbraucht wird, die in Ihrer Initialisierungszuordnung nicht explizit angefordert wurden.
Um unregelmäßige Datenspitzen auf den Hardware-Rails während eines Laufs zu vermeiden, solltest du die Helligkeit des Sperrbildschirms auf einen festen Wert einstellen, eine stabile Gerätetemperatur aufrechterhalten und konkurrierende Hintergrundprozesse schließen, bevor du die Macrobenchmark-Schleife startest.
Zusätzliche Ressourcen
Inhalte ansehen
Empfehlungen für Sie
- Hinweis: Linktext wird angezeigt, wenn JavaScript deaktiviert ist
- Baseline-Profile erstellen {:#creating-profile-rules}
- Makrobenchmark schreiben
- Analyse und Optimierung des App-Starts {:#app-startup-analysis-optimization}