Fehlerbehebung bei Referenzprofilen

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">
</ph> Fügen Sie eine benutzerdefinierte Ausführungskonfiguration hinzu, um Baseline-Profile in „Now in Android“ zu erstellen
Abbildung 1: Fügen Sie eine benutzerdefinierte Ausführungskonfiguration hinzu, um eine Referenz zu erstellen Profile in „Now in Android“.

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:

<ph type="x-smartling-placeholder">
</ph> Mit dem APK-Viewer in Android Studio nach einem Baseline-Profil suchen
Abbildung 2: Mit dem APK-Viewer nach einem Baseline-Profil suchen: Android Studio

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. ist RESULT_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
ProfileVerifieris 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 der PackageManager 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.