Sie können Benchmarks in Continuous Integration (CI) ausführen, um die Leistung im Zeitverlauf zu verfolgen und Leistungsabfälle oder -verbesserungen zu erkennen, bevor Ihre Anwendung überhaupt veröffentlicht wird. Diese Seite enthält grundlegende Informationen zum Benchmarking in CI.
Bevor Sie mit dem Benchmarking in CI beginnen, sollten Sie sich überlegen, wie sich die Erfassung und Bewertung von Ergebnissen von regulären Tests unterscheidet.
Unscharfe Ergebnisse
Auch wenn es sich bei Benchmarks um instrumentierte Tests handelt, sind die Ergebnisse nicht nur bestanden oder nicht bestanden. Benchmarks liefern zeitliche Messungen für das jeweilige Gerät, auf dem sie ausgeführt werden. Wenn Sie die Ergebnisse im Zeitverlauf grafisch darstellen, können Sie Veränderungen im Messsystem beobachten und Rauschen beobachten.
Echte Geräte verwenden
Benchmarks auf physischen Android-Geräten durchführen Sie können zwar auf Emulatoren ausgeführt werden, es wird jedoch dringend davon abgeraten, da dies keine realistische Nutzererfahrung darstellt und stattdessen Zahlen liefert, die mit dem Hostbetriebssystem und den Hardwarefunktionen verbunden sind. Ziehen Sie die Verwendung von echten Geräten oder einem Dienst in Betracht, mit dem Sie Tests auf echten Geräten wie Firebase Test Lab ausführen können.
Benchmarks durchführen
Die Ausführung der Benchmarks als Teil der CI-Pipeline kann sich von der lokalen Ausführung über Android Studio unterscheiden. Lokal führen Sie die Android-Integrationstests in der Regel mit einer Gradle-Aufgabe connectedCheck
aus. Diese Aufgabe erstellt automatisch Ihr APK und Test-APK und führt die Tests auf den Geräten aus, die mit dem CI-Server verbunden sind. Bei der Ausführung in CI muss dieser Ablauf normalerweise in separate Phasen aufgeteilt werden.
Eine Community
Führen Sie für die MicroBenchmark-Bibliothek die Gradle-Aufgabe assemble[VariantName]AndroidTest
aus. Dadurch wird Ihr Test-APK erstellt, das sowohl Ihren Anwendungscode als auch Ihren getesteten Code enthält.
Alternativ müssen Sie für die MacroBenchmark-Bibliothek Ihr Ziel-APK und Ihr Test-APK separat erstellen. Führen Sie daher die Gradle-Tasks :app:assemble[VariantName]
und :macrobenchmark:assemble[VariantName]
aus.
Installieren und ausführen
Diese Schritte werden in der Regel ohne Ausführung von Gradle-Aufgaben ausgeführt. Hinweis: Sie können abstrahiert sein, je nachdem, ob Sie einen Dienst verwenden, mit dem Sie Tests auf echten Geräten ausführen können.
Verwenden Sie für die Installation den Befehl adb install
und geben Sie das Test-APK oder das Ziel-APK an.
Führen Sie den Befehl adb shell am
aus, um alle Benchmarks auszuführen:
adb shell am instrument -w com.example.benchmark/androidx.benchmark.junit4.AndroidBenchmarkRunner
Verwenden Sie bei Verwendung der MacroBenchmark-Bibliothek den regulären androidx.test.runner.AndroidJUnitRunner
als Instrumentierungs-Runner.
Sie können mit dem Argument -e
dieselben Instrumentierungsargumente wie in der Gradle-Konfiguration übergeben. Informationen zu allen Optionen für Instrumentierungsargumente finden Sie unter MicroBenchmark-Instrumentierungsargumente oder Instrumentierungsargumente hinzufügen für MacroBenchmark.
Sie können beispielsweise das Argument dryRunMode
so festlegen, dass im Rahmen der Überprüfung von Pull-Anfragen Mikro-Benchmarks ausgeführt werden. Wenn dieses Flag aktiviert ist, werden Mikro-Benchmarks nur in einer einzigen Schleife ausgeführt. So wird überprüft, ob sie korrekt ausgeführt werden. Die Ausführung dauert aber nicht zu lange.
adb shell am instrument -w -e "androidx.benchmark.dryRunMode.enable" "true" com.example.benchmark/androidx.benchmark.junit4.AndroidBenchmarkRunner
Weitere Informationen zum Ausführen von Instrumentierungstests über die Befehlszeile finden Sie unter Tests mit ADB ausführen.
Sperruhren
Das Gradle-Plug-in von Microbenchmark bietet den Befehl ./gradlew lockClocks
, um die CPU-Taktung eines gerooteten Geräts zu sperren. Das ist nützlich, um für Stabilität zu sorgen, wenn Sie Zugriff auf gerootete Geräte wie „userdebug“-Builds haben. Sie können dies mit dem Shell-Skript lockClocks.sh
replizieren, das in der Quelle der Bibliothek verfügbar ist.
Sie können das Skript entweder direkt auf einem Linux- oder Mac-Host ausführen oder mit einigen ADB-Befehlen auf das Gerät übertragen:
adb push path/lockClocks.sh /data/local/tmp/lockClocks.sh adb shell /data/local/tmp/lockClocks.sh adb shell rm /data/local/tmp/lockClocks.sh
Wenn Sie das Shell-Skript direkt auf einem Host ausführen, werden die Befehle an ein verbundenes Gerät weitergeleitet.
Weitere Informationen dazu, warum es hilfreich ist, die CPU-Taktung zu sperren, finden Sie unter Konsistente Benchmarks abrufen.
Die Ergebnisse erfassen
Die Benchmarking-Bibliotheken geben Messwerte in JSON aus, zusammen mit Profilerstellungs-Traces in einem Verzeichnis auf dem Android-Gerät nach jeder Benchmarkausführung. Die MacroBenchmark-Bibliothek gibt mehrere Perfetto-Trace-Dateien aus: eine pro gemessener Iteration jeder MacrobenchmarkRule.measureRepeated
-Schleife. Die Mikro-Benchmark erstellt jedoch nur eine Trace-Datei für alle Iterationen einer BenchmarkRule.measureRepeated
. Trace-Dateien für die Profilerstellung werden ebenfalls in dasselbe Verzeichnis ausgegeben.
Dateien speichern und suchen
Wenn du die Benchmarks mit Gradle ausführst, werden diese Dateien automatisch in das Ausgabeverzeichnis deines Hostcomputers unter build/outputs/connected_android_test_additional_output/debugAndroidTest/connected/
kopiert.
Wenn Sie die Dateien direkt mit dem Befehl adb
ausführen, müssen Sie die Dateien manuell abrufen. Die Berichte werden standardmäßig auf dem Gerät im Medienverzeichnis des externen Speichers der getesteten Anwendung gespeichert. Der Einfachheit halber gibt die Bibliothek den Pfad der Datei in Logcat aus. Der Ausgabeordner kann je nach Android-Version, auf der die Benchmarks ausgeführt werden, variieren.
Benchmark: writing results to /storage/emulated/0/Android/media/com.example.macrobenchmark/com.example.macrobenchmark-benchmarkData.json
Sie können auch mit dem Instrumentierungsargument additionalTestOutputDir
den Speicherort konfigurieren, an dem Benchmarkberichte auf dem Gerät gespeichert werden. Ihre Anwendung muss in diesen Ordner schreiben können.
adb shell am instrument -w -e additionalTestOutputDir /sdcard/Download/ com.example.benchmark/androidx.benchmark.junit4.AndroidBenchmarkRunner
Unter Android 10 (API-Level 29) und höher werden die Tests deiner App standardmäßig in einer Speicher-Sandbox ausgeführt. Dadurch wird verhindert, dass deine App auf Dateien außerhalb des app-spezifischen Verzeichnisses zugreift. Übergeben Sie das folgende Instrumentierungsargument, um die Datei in einem globalen Verzeichnis wie /sdcard/Download
speichern zu können:
-e no-isolated-storage true
Außerdem müssen Sie im Manifest Ihrer Benchmark explizit Legacy-Speicheroptionen zulassen:
<application android:requestLegacyExternalStorage="true" ... >
Weitere Informationen finden Sie unter Begrenzten Speicher vorübergehend deaktivieren.
Dateien abrufen
Um die generierten Dateien vom Gerät abzurufen, verwenden Sie den Befehl adb pull
, der die angegebene Datei in das aktuelle Verzeichnis auf Ihrem Host lädt:
adb pull /storage/emulated/0/Android/media/com.example.macrobenchmark/com.example.macrobenchmark-benchmarkData.json
Prüfen Sie das folgende Snippet, um alle benchmarkData
aus einem bestimmten Ordner abzurufen:
# The following command pulls all files ending in -benchmarkData.json from the directory
# hierarchy starting at the root /storage/emulated/0/Android.
adb shell find /sdcard/Download -name "*-benchmarkData.json" | tr -d '\r' | xargs -n1 adb pull
Die Trace-Dateien (.trace
oder .perfetto-trace
) werden im selben Ordner wie benchmarkData.json
gespeichert, sodass Sie sie auf die gleiche Weise erfassen können.
Beispiel für Benchmarkdaten
Die Benchmark-Bibliotheken generieren JSON-Dateien mit Informationen zu dem Gerät, auf dem die Benchmarks ausgeführt wurden, und zu den tatsächlich ausgeführten Benchmarks. Das folgende Snippet stellt die generierte JSON-Datei dar:
{
"context": {
"build": {
"brand": "google",
"device": "blueline",
"fingerprint": "google/blueline/blueline:12/SP1A.210812.015/7679548:user/release-keys",
"model": "Pixel 3",
"version": {
"sdk": 31
}
},
"cpuCoreCount": 8,
"cpuLocked": false,
"cpuMaxFreqHz": 2803200000,
"memTotalBytes": 3753299968,
"sustainedPerformanceModeEnabled": false
},
"benchmarks": [
{
"name": "startup",
"params": {},
"className": "com.example.macrobenchmark.startup.SampleStartupBenchmark",
"totalRunTimeNs": 4975598256,
"metrics": {
"timeToInitialDisplayMs": {
"minimum": 347.881076,
"maximum": 347.881076,
"median": 347.881076,
"runs": [
347.881076
]
}
},
"sampledMetrics": {},
"warmupIterations": 0,
"repeatIterations": 3,
"thermalThrottleSleepSeconds": 0
}
]
}
Weitere Informationen
- Eine Anleitung zum Erkennen von Leistungsabfällen finden Sie unter Regressionen mit Benchmarks in CI bekämpfen.
- Informationen zum Einrichten von GitHub-Aktionen mit Firebase Test Lab finden Sie unter Jetpack-MakroBenchmarks für CI einrichten.
Empfehlungen für dich
- Hinweis: Der Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Best Practices für die SQLite-Leistung
- Baseline-Profile ohne MacroBenchmark erstellen und messen
- Hängende Teil-Wakelocks