Dieses Dokument enthält Best Practices zur Diagnose von Problemen und dass Ihre Baseline-Profile einwandfrei funktionieren, um den größten Nutzen zu bieten.
Build-Probleme
Wenn Sie das Baseline-Profile-Beispiel in das Feld Now in Android kopiert haben: Beispielanwendung können Testfehler während der Baseline-Profilaufgabe auftreten. dass die Tests nicht auf einem Emulator ausgeführt werden können:
./gradlew assembleDemoRelease
Starting a Gradle Daemon (subsequent builds will be faster)
Calculating task graph as no configuration cache is available for tasks: assembleDemoRelease
Type-safe project accessors is an incubating feature.
> Task :benchmarks:pixel6Api33DemoNonMinifiedReleaseAndroidTest
Starting 14 tests on pixel6Api33
com.google.samples.apps.nowinandroid.foryou.ScrollForYouFeedBenchmark > scrollFeedCompilationNone[pixel6Api33] FAILED
java.lang.AssertionError: ERRORS (not suppressed): EMULATOR
WARNINGS (suppressed):
...
Die Fehler treten auf, weil Now in Android Generierung von Referenzprofilen. Die Fehler sind zu erwarten, da Sie keine Leistungs-Benchmarks in einem Emulator ausführen. Da Sie sich jedoch nicht zum Erfassen von Leistungsmesswerten beim Generieren von Basisprofilen können Sie Folgendes ausführen: Die Referenzprofilerfassung in Emulatoren erleichtern. So verwenden Sie Baseline Profile mit einem Emulator erstellen, führen Sie den Build und die Installation über die und legen Sie ein Argument fest, um Baseline-Profile-Regeln zu aktivieren:
installDemoRelease -Pandroid.testInstrumentationRunnerArguments.androidx.benchmark.enabledRules=BaselineProfile
Alternativ können Sie eine benutzerdefinierte Ausführungskonfiguration in Android Studio erstellen, Aktivieren Sie Baseline-Profile in Emulatoren, indem Sie Ausführen > Konfigurationen bearbeiten:
<ph type="x-smartling-placeholder">Installationsprobleme
Prüfen Sie, ob das APK oder AAB, das Sie erstellen, von einer Build-Variante stammt, die Folgendes beinhaltet:
Referenzprofile. Am einfachsten kannst du das überprüfen, indem du das APK in
Android Studio, indem Sie Build > APK analysieren, öffnen Sie Ihr
APK und die Suche nach dem Profil in der /assets/dexopt/baseline.prof
Datei:
Referenzprofile müssen auf dem Gerät kompiliert werden, auf dem die App ausgeführt wird. Für beide
App Store-Installationen und Apps, die über
PackageInstaller
, die Kompilierung auf dem Gerät erfolgt im Rahmen der App
Installationsprozess. Wenn die App jedoch über Android Studio per Sideload übertragen wird oder
ist die Jetpack-Bibliothek ProfileInstaller
die Profile für die Kompilierung während der nächsten
DEX-Optimierungsprozess im Hintergrund. Wenn Sie in diesen Fällen sicherstellen möchten,
Referenzprofile werden verwendet. Möglicherweise müssen Sie
Erzwingen der Kompilierung von Referenzprofilen. Mit ProfileVerifier
können Sie
fragen Sie den Status der Profilinstallation und -kompilierung ab, wie in
im folgenden Beispiel:
Kotlin
private const val TAG = "MainActivity" class MainActivity : ComponentActivity() { ... override fun onResume() { super.onResume() lifecycleScope.launch { logCompilationStatus() } } private suspend fun logCompilationStatus() { withContext(Dispatchers.IO) { val status = ProfileVerifier.getCompilationStatusAsync().await() when (status.profileInstallResultCode) { RESULT_CODE_NO_PROFILE -> Log.d(TAG, "ProfileInstaller: Baseline Profile not found") RESULT_CODE_COMPILED_WITH_PROFILE -> Log.d(TAG, "ProfileInstaller: Compiled with profile") RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION -> Log.d(TAG, "ProfileInstaller: Enqueued for compilation") RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING -> Log.d(TAG, "ProfileInstaller: App was installed through Play store") RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST -> Log.d(TAG, "ProfileInstaller: PackageName not found") RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ -> Log.d(TAG, "ProfileInstaller: Cache file exists but cannot be read") RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE -> Log.d(TAG, "ProfileInstaller: Can't write cache file") RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION -> Log.d(TAG, "ProfileInstaller: Enqueued for compilation") else -> Log.d(TAG, "ProfileInstaller: Profile not compiled or enqueued") } } }
Java
public class MainActivity extends ComponentActivity { private static final String TAG = "MainActivity"; @Override protected void onResume() { super.onResume(); logCompilationStatus(); } private void logCompilationStatus() { ListeningExecutorService service = MoreExecutors.listeningDecorator( Executors.newSingleThreadExecutor()); ListenableFuture<ProfileVerifier.CompilationStatus> future = ProfileVerifier.getCompilationStatusAsync(); Futures.addCallback(future, new FutureCallback<>() { @Override public void onSuccess(CompilationStatus result) { int resultCode = result.getProfileInstallResultCode(); if (resultCode == RESULT_CODE_NO_PROFILE) { Log.d(TAG, "ProfileInstaller: Baseline Profile not found"); } else if (resultCode == RESULT_CODE_COMPILED_WITH_PROFILE) { Log.d(TAG, "ProfileInstaller: Compiled with profile"); } else if (resultCode == RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION) { Log.d(TAG, "ProfileInstaller: Enqueued for compilation"); } else if (resultCode == RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING) { Log.d(TAG, "ProfileInstaller: App was installed through Play store"); } else if (resultCode == RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST) { Log.d(TAG, "ProfileInstaller: PackageName not found"); } else if (resultCode == RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ) { Log.d(TAG, "ProfileInstaller: Cache file exists but cannot be read"); } else if (resultCode == RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE) { Log.d(TAG, "ProfileInstaller: Can't write cache file"); } else if (resultCode == RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION) { Log.d(TAG, "ProfileInstaller: Enqueued for compilation"); } else { Log.d(TAG, "ProfileInstaller: Profile not compiled or enqueued"); } } @Override public void onFailure(Throwable t) { Log.d(TAG, "ProfileInstaller: Error getting installation status: " + t.getMessage()); } }, service); } }
Die folgenden Ergebniscodes enthalten Hinweise auf die Ursache einiger Probleme:
RESULT_CODE_COMPILED_WITH_PROFILE
- Das Profil wird installiert, kompiliert und bei jeder Ausführung der App verwendet. Dieses ist das Ergebnis, das Sie sehen möchten.
RESULT_CODE_ERROR_NO_PROFILE_EMBEDDED
- Im ausgeführten APK oder AAB wurde kein Profil gefunden. Stellen Sie sicher, dass Sie eine Erstellen Sie eine Variante, die Baseline-Profile enthält, wenn dieser Fehler auftritt und die enthält das APK ein Profil.
RESULT_CODE_NO_PROFILE
- Bei der Installation der App über die App wurde kein Profil für diese App installiert
Store- oder Paketmanager. Der Hauptgrund für den Fehlercode ist,
Installationsprogramm konnte nicht ausgeführt werden, da
ProfileInstallerInitializer
deaktiviert war. Wenn dieser Fehler gemeldet wird, wurde ein eingebettetes Profil dennoch im App-APK. Wenn ein eingebettetes Profil nicht gefunden wird, wird der Fehlercode zurückgegeben. istRESULT_CODE_ERROR_NO_PROFILE_EMBEDDED
. RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION
- Ein Profil befindet sich im APK oder AAB und wird zur Kompilierung in die Warteschlange gestellt. Wenn ein
Profil von
ProfileInstaller
installiert, wird es zur Kompilierung in die Warteschlange gestellt. das nächste Mal, wenn die Hintergrund-DEX-Optimierung vom System ausgeführt wird. Das Profil ist nicht bis die Kompilierung abgeschlossen ist. Versuchen Sie nicht, Ihre Baseline zu vergleichen Profile, bis die Kompilierung abgeschlossen ist. Möglicherweise müssen Sie Erzwingen der Kompilierung von Referenzprofilen. Dieser Fehler tritt nicht auf, wenn Die App wird über den App-Shop oder den Paketmanager auf Geräten installiert, auf denen Android 9 (API 28) und höher, da die Kompilierung die Sie während der Installation ausführen. RESULT_CODE_COMPILED_WITH_PROFILE_NON_MATCHING
- Ein nicht übereinstimmendes Profil wird installiert und die App damit kompiliert.
Dies ist das Ergebnis der Installation über den Google Play Store oder den Paketmanager.
Dieses Ergebnis unterscheidet sich von
RESULT_CODE_COMPILED_WITH_PROFILE
, weil werden im nicht übereinstimmenden Profil nur Methoden kompiliert, die noch freigegeben werden zwischen dem Profil und der App. Das Profil ist effektiv kleiner als erwartet und es werden weniger Methoden kompiliert, als in der Baseline enthalten waren Profil RESULT_CODE_ERROR_CANT_WRITE_PROFILE_VERIFICATION_RESULT_CACHE_FILE
ProfileVerifier
kann die Cache-Datei für Überprüfungsergebnisse nicht schreiben. Dies kann weil etwas mit den App-Ordnerberechtigungen nicht stimmt Auf dem Gerät ist nicht genügend freier Speicherplatz vorhanden.RESULT_CODE_ERROR_UNSUPPORTED_API_VERSION
- ProfileVerifier
is running on an unsupported API version of Android. ProfileVerifier
unterstützt nur Android 9 (API-Level 28) und höher. RESULT_CODE_ERROR_PACKAGE_NAME_DOES_NOT_EXIST
PackageManager.NameNotFoundException
wird bei der Abfrage derPackageManager
für das App-Paket. Das sollte nur selten der Fall sein. Ausprobieren die App deinstallieren und sie anschließend neu installieren.RESULT_CODE_ERROR_CACHE_FILE_EXISTS_BUT_CANNOT_BE_READ
- Es ist eine frühere Cache-Datei für Überprüfungsergebnisse vorhanden, die aber nicht gelesen werden kann. Dieses eher selten eintreten. Versuche, die App zu deinstallieren und anschließend alles neu zu installieren.
ProfileVerifier in Produktion verwenden
In der Produktion können Sie ProfileVerifier
in Verbindung mit
Analysebibliotheken wie Google Analytics for Firebase, um
Analytics-Ereignisse generieren, die den Profilstatus angeben. Zum Beispiel
werden Sie schnell benachrichtigt, wenn eine neue App-Version veröffentlicht wird, die
Referenzprofile.
Kompilierung von Referenzprofilen erzwingen
Wenn der Kompilierungsstatus Ihrer Referenzprofile wie folgt lautet:
RESULT_CODE_PROFILE_ENQUEUED_FOR_COMPILATION
, Sie können ein sofortiges Ergebnis erzwingen
Kompilierung mit adb
:
adb shell cmd package compile -r bg-dexopt PACKAGE_NAME
Kompilierungsstatus ohne ProfileVerifier überprüfen
Wenn Sie ProfileVerifier
nicht verwenden, können Sie den Kompilierungsstatus mit
adb
, auch wenn sie nicht so tiefgehende Erkenntnisse wie ProfileVerifier
liefert:
adb shell dumpsys package dexopt | grep -A 2 PACKAGE_NAME
Die Verwendung von adb
liefert in etwa Folgendes:
[com.google.samples.apps.nowinandroid.demo]
path: /data/app/~~dzJiGMKvp22vi2SsvfjkrQ==/com.google.samples.apps.nowinandroid.demo-7FR1sdJ8ZTy7eCLwAnn0Vg==/base.apk
arm64: [status=speed-profile] [reason=bg-dexopt] [primary-abi]
[location is /data/app/~~dzJiGMKvp22vi2SsvfjkrQ==/com.google.samples.apps.nowinandroid.demo-7FR1sdJ8ZTy7eCLwAnn0Vg==/oat/arm64/base.odex]
Der Statuswert gibt den Kompilierungsstatus des Profils an und ist einer der folgende Werte:
Kompilierungsstatus | Bedeutung |
---|---|
speed‑profile |
Ein kompiliertes Profil ist vorhanden und wird verwendet. |
verify |
Kein kompiliertes Profil vorhanden. |
Der Status verify
bedeutet nicht, dass das APK oder AAB kein Profil enthält.
da er von der nächsten DEX-Optimierung im Hintergrund zur Kompilierung in die Warteschlange gestellt werden kann
für die Aufgabe.
Der Wert für den Grund gibt an, was die Kompilierung des Profils auslöst, und einer der folgenden Werte:
Grund | Bedeutung |
---|---|
install‑dm
|
Ein Baseline-Profil wurde manuell oder von Google kompiliert Wiedergabe, wenn die App installiert ist. |
bg‑dexopt
|
Es wurde ein Profil erstellt, während dein Gerät inaktiv war. Dies kann ein Baseline-Profil oder ein Profil, das während der App-Nutzung erfasst wurde. |
cmdline
|
Die Kompilierung wurde mit ADB ausgelöst. Dies kann ein Baseline-Profil oder ein Profil, das während der App-Nutzung erfasst wurde. |
Leistungsprobleme
Dieser Abschnitt enthält einige Best Practices für die richtige Definition und das richtige Benchmarking. Ihre Baseline-Profile, um sie optimal zu nutzen.
Start-up-Messwerte korrekt vergleichen
Ihre Baseline-Profile sind effektiver, wenn Ihre Startmesswerte folgende sind: klar definiert sind. Die beiden wichtigsten Messwerte sind Zeit bis zur ersten Anzeige (TTID) und Zeit bis zur vollständigen Anzeige (TTFD).
Über die TTID wird der erste Frame der App gezeichnet. Es ist wichtig, den Text so kurz zu halten, da die Anzeige dem Nutzer zeigt, dass die App ausgeführt wird. Sie können sogar eine unbestimmte Fortschrittsanzeige anzeigen, um anzuzeigen, dass die App reaktionsschnell ist.
Bei TTFD kann tatsächlich mit der App interagiert werden. Es ist wichtig, so kurz wie möglich halten, um die Nutzenden nicht zu frustrieren. Wenn Sie das richtige Signal TTFD, teilen Sie dem System mit, dass der Code, der auf dem Weg zu TTFD ausgeführt wird, Teil des App-Starts ist. Es ist wahrscheinlicher, dass das System diesen Code im Profil platziert als Ergebnis.
Halte sowohl TTID als auch TTFD so niedrig wie möglich, damit deine App responsiv wirkt.
Das System kann die TTID erkennen, in Logcat anzeigen und als Teil
Benchmarks für Start-ups. Das System kann TTFD jedoch nicht finden und es wird
ist es der Aufgabe der App, zu melden, wenn sie eine vollständig interaktive
Bundesstaat. Rufen Sie dazu reportFullyDrawn()
auf oder
ReportDrawn
, wenn Sie Jetpack Compose verwenden. Wenn Sie mehrere
Hintergrundaufgaben, die alle erledigt werden müssen, bevor die App als vollständig betrachtet wird.
gezeichnet haben, können Sie FullyDrawnReporter
verwenden, wie unter Verbesserungen
Genauigkeit beim Startzeitpunkt.
Bibliotheksprofile und benutzerdefinierte Profile
Beim Benchmarking der Auswirkungen von Profilen kann es schwierig sein, Vorteile der Profile Ihrer Anwendung aus Profilen, die von Bibliotheken bereitgestellt werden, z. B. Jetpack-Bibliotheken. Beim Erstellen Ihres APK fügt das Android-Gradle-Plug-in in Bibliotheksabhängigkeiten sowie in Ihrem benutzerdefinierten Profil verwenden. Das ist gut zur Optimierung der Gesamtleistung und wird für Ihre Release-Builds empfohlen. Allerdings lässt sich nur schwer messen, inwieweit die zusätzliche Leistungssteigerung aus Ihrem benutzerdefinierten Profil.
Eine schnelle Möglichkeit, die zusätzliche Optimierung durch Ihre benutzerdefinierte entfernen und Benchmarks erstellen. Ersetzen Sie sie dann die Benchmarks. Ein Vergleich dieser beiden Modelle zeigt die Optimierungen und die Bibliotheksprofile sowie Ihr benutzerdefiniertes Profil.
Eine automatisierte Methode zum Vergleichen von Profilen ist das Erstellen einer neuen Build-Variante, die
enthält nur die Bibliotheksprofile und nicht Ihr benutzerdefiniertes Profil. Vergleichen
von dieser Variante bis zur Release-Variante, die sowohl das
Bibliotheksprofile und Ihre benutzerdefinierten Profile. Das folgende Beispiel zeigt,
um die Variante einzurichten,
die nur Bibliotheksprofile enthält. Neue Variante hinzufügen
dem Nutzermodul in Ihrem Profil den Namen releaseWithoutCustomProfile
,
ist normalerweise dein App-Modul:
Kotlin
android { ... buildTypes { ... // Release build with only library profiles. create("releaseWithoutCustomProfile") { initWith(release) } ... } ... } ... dependencies { ... // Remove the baselineProfile dependency. // baselineProfile(project(":baselineprofile")) } baselineProfile { variants { create("release") { from(project(":baselineprofile")) } } }
Cool
android { ... buildTypes { ... // Release build with only library profiles. releaseWithoutCustomProfile { initWith(release) } ... } ... } ... dependencies { ... // Remove the baselineProfile dependency. // baselineProfile ':baselineprofile"' } baselineProfile { variants { release { from(project(":baselineprofile")) } } }
Mit dem vorherigen Codebeispiel wird die baselineProfile
-Abhängigkeit aus allen
und wendet sie selektiv nur auf die Variante release
an. Vielleicht scheint es
nicht offensichtlich, dass die Bibliotheksprofile immer noch hinzugefügt werden, wenn der
Die Abhängigkeit vom Profilerstellermodul wird entfernt. Dieses Modul ist jedoch
sind nur für die Erstellung des benutzerdefinierten Profils verantwortlich. Der Android-Gradle-Plug-in
noch für alle Varianten ausgeführt wird und dafür verantwortlich ist,
Bibliotheksprofile.
Außerdem müssen Sie die neue Variante zum Profilgeneratormodul hinzufügen. In dieser
Beispiel für das Producer-Modul :baselineprofile
.
Kotlin
android { ... buildTypes { ... // Release build with only library profiles. create("releaseWithoutCustomProfile") {} ... } ... }
Cool
android { ... buildTypes { ... // Release build with only library profiles. releaseWithoutCustomProfile {} ... } ... }
Wenn Sie die Benchmark in Android Studio ausführen, wählen Sie
releaseWithoutCustomProfile
Variante, um die Leistung nur mit Bibliothek zu messen
Profilen oder wählen Sie eine release
-Variante aus, um die Leistung mit der Bibliothek zu messen
und benutzerdefinierte Profile.
I/O-gebundenen Start von Anwendungen vermeiden
Führt Ihre App während des Starts viele E/A- oder Netzwerkaufrufe aus, Dies kann sich negativ auf die Startzeit der App und die Genauigkeit des Startvorgangs auswirken. und Benchmarking durchführen. Solche Anrufe können unbestimmte Zeit in Anspruch nehmen die sich im Laufe der Zeit und sogar zwischen Iterationen derselben Benchmark ändern können. E/A sind in der Regel besser als Netzwerkaufrufe, da letztere die durch externe Faktoren und das Gerät selbst beeinflusst werden. Vermeiden Netzwerkaufrufe während des Starts. Wenn eine Verwendung unvermeidbar ist, nutzen Sie die E/A.
Wir empfehlen, dass Ihre App-Architektur das Start-up von Apps ohne Netzwerk- oder E/A-Aufrufe, auch wenn sie nur beim Benchmarking von Start-ups verwendet werden sollen. Dies trägt dazu bei, die geringstmögliche Variabilität zwischen verschiedenen Iterationen Ihrer Benchmarks.
Wenn Ihre App Hilt verwendet, können Sie eine gefälschte E/A-gebunden bereitstellen. beim Benchmarking in MicroBenchmark und Hilt.
Alle wichtigen User Journeys abdecken
Es ist wichtig, alle wichtigen User Journeys in Ihrem Generierung von Referenzprofilen. Nicht abgedeckte User Journeys werden nicht durch Baseline Profiles verbessert. Die effektivsten Basisprofile umfassen alle gängige User Journeys bei Start-ups und leistungsempfindliche In-App-Nutzer wie das Scrollen durch Listen.