Basisprofile manuell erstellen und messen

Wir empfehlen dringend, die Generierung von Profilregeln mit der Jetpack MacroBenchmark-Bibliothek zu automatisieren, um den manuellen Aufwand zu reduzieren und die allgemeine Skalierbarkeit zu erhöhen. Es ist jedoch möglich, Profilregeln in Ihrer Anwendung manuell zu erstellen und zu messen.

Profilregeln manuell definieren

Sie können Profilregeln manuell in einer Anwendung oder einem Bibliotheksmodul definieren. Dazu erstellen Sie eine Datei namens baseline-prof.txt im Verzeichnis src/main. Dies ist der Ordner, der auch die Datei AndroidManifest.xml enthält.

In der Datei ist eine Regel pro Zeile angegeben. Jede Regel stellt ein Muster für Abgleichmethoden oder Klassen in der App oder Bibliothek dar, das optimiert werden muss.

Die Syntax für diese Regeln ist eine Obermenge des von Menschen lesbaren ART-Profilformats (HRF), wenn adb shell profman --dump-classes-and-methods verwendet wird. Die Syntax ähnelt der Syntax für Deskriptoren und Signaturen, ermöglicht jedoch die Verwendung von Platzhaltern, um das Schreiben von Regeln zu vereinfachen.

Das folgende Beispiel zeigt einige Baseline-Profilregeln, die in der Jetpack Composer-Bibliothek enthalten sind:

HSPLandroidx/compose/runtime/ComposerImpl;->updateValue(Ljava/lang/Object;)V
HSPLandroidx/compose/runtime/ComposerImpl;->updatedNodeCount(I)I
HLandroidx/compose/runtime/ComposerImpl;->validateNodeExpected()V
PLandroidx/compose/runtime/CompositionImpl;->applyChanges()V
HLandroidx/compose/runtime/ComposerKt;->findLocation(Ljava/util/List;I)I
Landroidx/compose/runtime/ComposerImpl;

Regelsyntax

Für die Ausrichtung auf Methoden oder Klassen gibt es zwei Arten dieser Regeln:

[FLAGS][CLASS_DESCRIPTOR]->[METHOD_SIGNATURE]

Eine Klassenregel verwendet das folgende Muster:

[CLASS_DESCRIPTOR]

Eine ausführliche Beschreibung finden Sie in der folgenden Tabelle:

Syntax Beschreibung
FLAGS Stellt eines oder mehrere der Zeichen H, S und P dar, um anzugeben, ob diese Methode in Bezug auf den Starttyp als Hot, Startup oder Post Startup gekennzeichnet werden muss.

Eine Methode mit dem Flag H gibt an, dass es sich um eine „heiße“ Methode handelt, die während der Lebensdauer der App mehrmals aufgerufen wird.

Eine Methode mit dem Flag S gibt an, dass es sich um eine Methode handelt, die beim Start aufgerufen wird.

Eine Methode mit dem Flag P gibt an, dass es sich um eine Methode handelt, die nach dem Start aufgerufen wird.

Eine in dieser Datei vorhandene Klasse gibt an, dass sie beim Start verwendet wird und im Heap zugewiesen werden muss, um Kosten für das Laden der Klasse zu vermeiden. Der ART-Compiler verwendet verschiedene Optimierungsstrategien, z. B. die AOT-Kompilierung dieser Methoden und die Layoutoptimierung in der generierten AOT-Datei.
CLASS_DESCRIPTOR Deskriptor für die Klasse der Zielmethode. Beispielsweise hat androidx.compose.runtime.SlotTable den Deskriptor Landroidx/compose/runtime/SlotTable;. L wird hier im Dalvik Executable (DEX)-Format vorangestellt.
METHOD_SIGNATURE Signatur der Methode, einschließlich Name, Parametertypen und Rückgabetypen der Methode. Beispiel:

// LayoutNode.kt

fun isPlaced():Boolean {
// ...
}

auf LayoutNode hat die Signatur isPlaced()Z.

Diese Muster können Platzhalter enthalten, damit eine einzelne Regel mehrere Methoden oder Klassen umfasst. Eine Anleitung zum Schreiben mit Regelsyntax in Android Studio finden Sie im Plug-in Android Baseline Profiles (Android-Baseline-Profile).

Eine Platzhalterregel könnte beispielsweise so aussehen:

HSPLandroidx/compose/ui/layout/**->**(**)**

Unterstützte Typen in Regeln für das Referenzprofil

Regeln für Referenzprofile unterstützen die folgenden Typen. Weitere Informationen zu diesen Typen finden Sie im Dalvik Executable-Format (DEX).

Zeichen Typ Beschreibung
B Byte Signiertes Byte
C Zeichen Unicode-Zeichencodepunkt mit UTF-16-Codierung
D Doppelt Gleitkommawert mit doppelter Genauigkeit
F schweben Gleitkommawert mit einfacher Genauigkeit
I int Ganzzahl
J lang Lange Ganzzahl
S kurz Kurzes signiertes Element
V void Ungültig
Z boolean Richtig oder falsch?
L (Kursname) Referenz Instanz eines Klassennamens

Außerdem können Bibliotheken Regeln definieren, die in AAR-Artefakte gepackt sind. Wenn du ein APK erstellst, das diese Artefakte enthält, werden die Regeln zusammengeführt – ähnlich wie beim Zusammenführen von Manifesten – und zu einem kompakten binären ART-Profil kompiliert, das für das APK spezifisch ist.

ART nutzt dieses Profil, wenn das APK auf Geräten verwendet wird, um bei der Installation unter Android 9 (API-Level 28) oder Android 7 (API-Level 24) bei Verwendung von ProfileInstaller eine bestimmte Teilmenge der App zu kompilieren.

Referenzprofile manuell erfassen

Sie können manuell ein Baseline-Profil generieren, ohne die MacroBenchmark-Bibliothek einzurichten, und UI-Automatisierungen für Ihre kritischen Nutzerpfade erstellen. Auch wenn wir die Verwendung von Makro-Benchmarks empfehlen, ist dies nicht immer möglich. Wenn Sie beispielsweise ein Nicht-Gradle-Build-System verwenden, können Sie das Gradle-Plug-in für das Baseline-Profil nicht verwenden. In solchen Fällen können Sie Baseline-Profilregeln manuell erfassen. Dies ist viel einfacher, wenn Sie ein Gerät oder einen Emulator mit API 34 und höher verwenden. Auch wenn dies mit niedrigeren API-Ebenen immer noch möglich ist, ist dafür Root-Zugriff erforderlich. Außerdem müssen Sie einen Emulator verwenden, der ein AOSP-Image ausführt. So können Sie Regeln direkt erfassen:

  1. Installiere eine Release-Version deiner App auf einem Testgerät. Der Build-Typ der Anwendung muss für ein genaues Profil R8-optimiert und nicht Debug-fähig sein.
  2. Achten Sie darauf, dass die Profile nicht bereits kompiliert sind.

    API 34 und höher

    adb shell cmd package compile -f -m verify $PACKAGE_NAME
    adb shell pm art clear-app-profiles $PACKAGE_NAME
    

    API 33 und niedriger

    adb root
    adb shell cmd package compile --reset $PACKAGE_NAME
    

    Wenn dein APK eine Abhängigkeit von der Jetpack-Bibliothek Profile Installer hat, startet die Bibliothek beim ersten Start des APK ein Profil. Dies kann den Prozess der Profilerstellung beeinträchtigen. Deaktivieren Sie ihn daher mit dem folgenden Befehl:

    adb shell am broadcast -a androidx.profileinstaller.action.SKIP_FILE $PACKAGE_NAME/androidx.profileinstaller.ProfileInstallReceiver
    

  3. Führen Sie die App aus und gehen Sie manuell durch Ihre kritischen User Journeys, für die Sie ein Profil erstellen möchten.
  4. Fordere ART auf, die Profile auszuwerfen. Wenn Ihr APK eine Abhängigkeit von der Jetpack Profile Installer-Bibliothek hat, verwenden Sie diese zum Dump der Profile:

    adb shell am broadcast -a androidx.profileinstaller.action.SAVE_FILE $PACKAGE_NAME/androidx.profileinstaller.ProfileInstallReceiver
    adb shell am force-stop $PACKAGE_NAME
    
    Wenn Sie Profile Installer nicht verwenden, sichern Sie die Profile mit dem folgenden Befehl manuell in einem Emulator:

    adb root
    adb shell killall -s SIGUSR1 $PACKAGE_NAME
    adb shell am force-stop $PACKAGE_NAME
    

  5. Warten Sie mindestens fünf Sekunden, bis die Profilerstellung abgeschlossen ist.
  6. Konvertieren Sie die generierten binären Profile in Text:

    API 34 und höher

    adb shell pm dump-profiles --dump-classes-and-methods $PACKAGE_NAME
    

    API 33 und niedriger

    Feststellen, ob ein Referenzprofil oder ein aktuelles Profil erstellt wurde. Ein Referenzprofil befindet sich an folgendem Speicherort:

    /data/misc/profiles/ref/$$PACKAGE_NAME/primary.prof
    

    Ein aktuelles Profil befindet sich am folgenden Speicherort:

    /data/misc/profiles/cur/0/$PACKAGE_NAME/primary.prof
    

    So ermitteln Sie den Speicherort des APK:

    adb root
    adb shell pm path $PACKAGE_NAME
    

    Führen Sie die Umwandlung durch:

    adb root
    adb shell profman --dump-classes-and-methods --profile-file=$PROFILE_PATH --apk=$APK_PATH > /data/misc/profman/$PACKAGE_NAME-primary.prof.txt
    

  7. Verwenden Sie adb, um das Dumpprofil vom Gerät abzurufen:

    adb pull /data/misc/profman/$PACKAGE_NAME-primary.prof.txt PATH_TO_APP_MODULE/src/main/
    

Dadurch werden die generierten Profilregeln abgerufen und in Ihrem App-Modul installiert. Wenn Sie die Anwendung das nächste Mal erstellen, wird das Baseline-Profil eingefügt. Prüfen Sie dies anhand der Schritte unter Probleme bei der Installation.

App-Verbesserungen manuell messen

Wir empfehlen dringend, App-Verbesserungen durch Benchmarking zu messen. Wenn Sie Verbesserungen jedoch manuell messen möchten, können Sie damit beginnen, den nicht optimierten Anwendungsstart zu Referenzzwecken zu messen.

PACKAGE_NAME=com.example.app
# Force Stop App
adb shell am force-stop $PACKAGE_NAME
# Reset compiled state
adb shell cmd package compile --reset $PACKAGE_NAME
# Measure App startup
# This corresponds to `Time to initial display` metric.
adb shell am start-activity -W -n $PACKAGE_NAME/.ExampleActivity \
 | grep "TotalTime"

Laden Sie als Nächstes das Baseline-Profil per Sideload herunter.

# Unzip the Release APK first.
unzip release.apk
# Create a ZIP archive.
# The name should match the name of the APK.
# Copy `baseline.prof{m}` and rename it `primary.prof{m}`.
cp assets/dexopt/baseline.prof primary.prof
cp assets/dexopt/baseline.profm primary.profm
# Create an archive.
zip -r release.dm primary.prof primary.profm
# Confirm that release.dm only contains the two profile files:
unzip -l release.dm
# Archive:  release.dm
#   Length      Date    Time    Name
# ---------  ---------- -----   ----
#      3885  1980-12-31 17:01   primary.prof
#      1024  1980-12-31 17:01   primary.profm
# ---------                     -------
#                               2 files
# Install APK + Profile together.
adb install-multiple release.apk release.dm

Führen Sie den folgenden Befehl aus, um zu überprüfen, ob das Paket bei der Installation optimiert wurde:

# Check dexopt state.
adb shell dumpsys package dexopt | grep -A 1 $PACKAGE_NAME

Die Ausgabe muss angeben, dass das Paket kompiliert ist:

[com.example.app]
  path: /data/app/~~YvNxUxuP2e5xA6EGtM5i9A==/com.example.app-zQ0tkJN8tDrEZXTlrDUSBg==/base.apk
  arm64: [status=speed-profile] [reason=install-dm]

Jetzt können Sie die Startleistung von Anwendungen wie zuvor messen, ohne den kompilierten Status zurückzusetzen. Achten Sie darauf, den kompilierten Status für das Paket nicht zurückzusetzen.

# Force stop app
adb shell am force-stop $PACKAGE_NAME
# Measure app startup
adb shell am start-activity -W -n $PACKAGE_NAME/.ExampleActivity \
 | grep "TotalTime"

Baseline-Profile und Vermittlung

In diesem Abschnitt wird beschrieben, wie das Tool profgen eine kompakte Binärversion eines Baseline-Profils erstellt.

Profgen-cli hilft bei der Profilkompilierung, Selbstprüfung und Übersetzung von ART-Profilen, sodass sie unabhängig von der SDK-Zielversion auf Android-Geräten installiert werden können.

Profgen-cli ist eine Befehlszeile, die die HRF eines Baseline-Profils in sein kompiliertes Format kompiliert. Die Befehlszeile wird als Teil des Android SDK auch im cmdline-tools-Repository enthalten.

Diese Features sind im studio-main-Zweig verfügbar:

➜ ../cmdline-tools/latest/bin
apkanalyzer
avdmanager
lint
profgen
retrace
screenshot2
sdkmanager

Kompakte Binärprofile mit Profgen-cli erstellen

In Profgen-cli sind die Befehle bin, validate und dumpProfile verfügbar. Mit profgen --help können Sie die verfügbaren Befehle aufrufen:

profgen --help
Usage: profgen options_list
Subcommands:
    bin - Generate Binary Profile
    validate - Validate Profile
    dumpProfile - Dump a binary profile to a HRF

Options:
    --help, -h -> Usage info

Verwenden Sie den Befehl bin, um das kompakte Binärprofil zu generieren. Hier ein Beispielaufruf:

profgen bin ./baseline-prof.txt \
  --apk ./release.apk \
  --map ./obfuscation-map.txt \
  --profile-format v0_1_0_p \
  --output ./baseline.prof \

Mit profgen bin options_list können Sie die verfügbaren Optionen aufrufen:

Usage: profgen bin options_list
Arguments:
    profile -> File path to Human Readable profile { String }
Options:
    --apk, -a -> File path to apk (always required) { String }
    --output, -o -> File path to generated binary profile (always required)
    --map, -m -> File path to name obfuscation map { String }
    --output-meta, -om -> File path to generated metadata output { String }
    --profile-format, -pf [V0_1_0_P] -> The ART profile format version
      { Value should be one of [
         v0_1_5_s, v0_1_0_p, v0_0_9_omr1, v0_0_5_o, v0_0_1_n
        ]
      }
    --help, -h -> Usage info

Das erste Argument stellt den Pfad zum baseline-prof.txt-HRF dar.

Außerdem benötigt Profgen-cli den Pfad zum Release-Build des APK und eine Verschleierungskarte, mit der das APK bei Verwendung von R8 oder Proguard verschleiert wird. Auf diese Weise kann profgen beim Erstellen des kompilierten Profils Quellsymbole im HRF in die entsprechenden verschleierten Namen übersetzen.

Da ART-Profileformate nicht vorwärts- oder abwärtskompatibel sind, solltest du ein Profilformat angeben, damit profgen Profilmetadaten (profm) verpackt, die du bei Bedarf zum Transcodieren eines ART-Profilformats in ein anderes verwenden kannst.

Profilformate und Plattformversionen

Die folgenden Optionen sind bei der Auswahl eines Profilformats verfügbar:

Profilformat Plattform-Version API-Ebene
v0_1_5_s Android S oder höher 31+
V0_1_0_p Android P, Q und R 28-30
v0_0_9_omr1 (Version 0_0_9_Omr1) Android O MR1 27
v0_0_5_o Android O 26
v0_0_1_n Android N 24-25

Kopiere die Ausgabedateien baseline.prof und baseline.profm in den Ordner assets oder dexopt des APK.

Verschleierungskarten

Sie müssen die Verschleierungskarte nur dann bereitstellen, wenn das HRF Quellsymbole verwendet. Wenn die HRF aus einem bereits verschleierten Release-Build generiert wird und keine Zuordnung erforderlich ist, können Sie diese Option ignorieren und die Ausgaben in den Ordner assets oder dexopt kopieren.

Herkömmliche Installation von Baseline-Profilen

Referenzprofile werden normalerweise auf eine von zwei Arten an ein Gerät gesendet.

install-multiple mit DexMetadata verwenden

Auf Geräten mit API 28 und höher lädt der Play-Client die APK- und DesMetadata- (DM)-Nutzlast für eine APK-Version herunter, die installiert wird. Die DM enthält die Profilinformationen, die auf dem Gerät an den Paketmanager übergeben werden.

Das APK und die DM werden im Rahmen einer einzelnen Installationssitzung installiert. Dies geschieht in etwa so:

adb install-multiple base.apk base.dm

Jetpack ProfileInstaller

Auf Geräten mit API-Level 29 und höher bietet die Bibliothek Jetpack ProfileInstaller einen alternativen Mechanismus zur Installation eines in assets oder dexopt gepackten Profils, nachdem das APK auf dem Gerät installiert wurde. ProfileInstaller wird von ProfileInstallReceiver oder direkt von der Anwendung aufgerufen.

Die ProfileInstaller-Bibliothek transcodiert das Profil basierend auf der SDK-Version des Zielgeräts und kopiert es in das Verzeichnis cur auf dem Gerät (ein paketspezifisches Staging-Verzeichnis für ART-Profile auf dem Gerät).

Sobald das Gerät inaktiv ist, wird das Profil von einem Prozess namens bg-dexopt auf dem Gerät übernommen.

Referenzprofil per Sideload übertragen

In diesem Abschnitt wird beschrieben, wie ein Baseline-Profil für ein APK installiert wird.

Nachricht an alle mit androidx.profileinstaller

Auf Geräten mit API 24 und höher können Sie einen Befehl zur Installation des Profils senden:

# Broadcast the install profile command - moves binary profile from assets
#     to a location where ART uses it for the next compile.
#     When successful, the following command prints "1":
adb shell am broadcast \
    -a androidx.profileinstaller.action.INSTALL_PROFILE \
    <pkg>/androidx.profileinstaller.ProfileInstallReceiver

# Kill the process
am force-stop <pkg>

# Compile the package based on profile
adb shell cmd package compile -f -m speed-profile <pkg>

ProfileInstaller ist in den meisten APKs mit Baseline-Profilen nicht vorhanden. Diese befindet sich in etwa 77.000 von 450.000 Apps bei Google Play, obwohl es praktisch in jedem APK mit Compose vorhanden ist. Das liegt daran, dass Bibliotheken Profile bereitstellen können, ohne eine Abhängigkeit von ProfileInstaller zu deklarieren. Das Hinzufügen einer Abhängigkeit in jeder Bibliothek mit einem Profil gilt beginnend mit Jetpack.

install-multiple mit profgen oder DexMetaData verwenden

Auf Geräten mit API 28 und höher können Sie ein Baseline-Profil per Sideload übertragen, ohne dass in der App die ProfileInstaller-Bibliothek vorhanden ist.

Verwenden Sie dazu Profgen-cli:

profgen extractProfile \
        --apk app-release.apk \
        --output-dex-metadata app-release.dm \
        --profile-format V0_1_5_S # Select based on device and the preceding table.

# Install APK and the profile together
adb install-multiple appname-release.apk appname-release.dm

Führe die vorherigen Schritte zum Extrahieren des Profils einmal pro APK aus, um APK-Aufteilungen zu unterstützen. Übergib bei der Installation jedes APK und die zugehörige .dm-Datei und achte darauf, dass die Namen des APK und der .dm übereinstimmen:

adb install-multiple appname-base.apk appname-base.dm \
appname-split1.apk appname-split1.dm

Bestätigung

Mit den Schritten unter App-Verbesserungen manuell messen können Sie prüfen, ob das Profil korrekt installiert ist.

Inhalt eines Binärprofils auslesen

Verwenden Sie die Profgen-cli-Option dumpProfile, um den Inhalt einer kompakten Binärversion eines Referenzprofils selbst zu prüfen:

Usage: profgen dumpProfile options_list
Options:
    --profile, -p -> File path to the binary profile (always required)
    --apk, -a -> File path to apk (always required) { String }
    --map, -m -> File path to name obfuscation map { String }
    --strict, -s [true] -> Strict mode
    --output, -o -> File path for the HRF (always required) { String }
    --help, -h -> Usage info

dumpProfile benötigt das APK, da die kompakte binäre Darstellung nur DEX-Offsets speichert und sie daher benötigt, um Klassen- und Methodennamen zu rekonstruieren.

Der strikte Modus ist standardmäßig aktiviert. Dadurch wird eine Kompatibilitätsprüfung des Profils mit den DEX-Dateien im APK durchgeführt. Wenn Sie Fehler in Profilen beheben, die von einem anderen Tool generiert wurden, treten möglicherweise Kompatibilitätsfehler auf, die verhindern, dass Sie einen Dump für die Prüfung erstellen können. In solchen Fällen können Sie den strikten Modus mit --strict false deaktivieren. In den meisten Fällen sollten Sie den strikten Modus jedoch aktiviert lassen.

Eine Verschleierungskarte ist optional. Wenn sie bereitgestellt wird, hilft sie dabei, verschleierte Symbole der einfacheren Verwendung für Menschen lesbar zu machen.