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. Sie können jedoch Profile manuell erstellen und Regeln für sie in Ihrer App messen.

Profilregeln manuell definieren

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

Die Datei enthält eine Regel pro Zeile. Jede Regel stellt ein Muster für übereinstimmende Methoden oder Klassen in der App oder Bibliothek dar, die optimiert werden müssen.

Die Syntax dieser Regeln ist ein Superset des menschenlesbaren 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 aber die Verwendung von Platzhaltern, um das Erstellen von Regeln zu vereinfachen.

Das folgende Beispiel zeigt einige Baseline-Profilregeln, die in der Jetpack Compose-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;

Sie können versuchen, Profilregeln in diesem Beispielprojekt im Compiler Explorer zu ändern. Hinweis: Der Compiler Explorer unterstützt nur das visuell lesbare ART-Profilformat (HRF). Platzhalter werden daher nicht unterstützt.

Syntax von Regeln

Diese Regeln können auf zwei Arten erstellt werden, um entweder auf Methoden oder Klassen ausgerichtet zu werden:

[FLAGS][CLASS_DESCRIPTOR]->[METHOD_SIGNATURE]

Eine Klassenregel hat das folgende Muster:

[CLASS_DESCRIPTOR]

Eine detaillierte 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 ist eine „heiße“ Methode, d. h., sie wird während der Lebensdauer der App häufig aufgerufen.

Eine Methode mit dem Flag S ist eine Methode, die beim Start aufgerufen wird.

Eine Methode mit dem Flag P gibt an, dass sie nach dem Start aufgerufen wird.

Eine in dieser Datei vorhandene Klasse gibt an, dass sie beim Start verwendet wird und im Heap vorab zugewiesen werden muss, um die Kosten für das Laden der Klasse zu vermeiden. Der ART-Compiler verwendet verschiedene Optimierungsstrategien, z. B. die AOT-Kompilierung dieser Methoden und die Durchführung von Layoutoptimierungen in der generierten AOT-Datei.
CLASS_DESCRIPTOR Deskriptor für die Klasse der anvisierten Methode. Beispiel: androidx.compose.runtime.SlotTable hat den Descriptor Landroidx/compose/runtime/SlotTable;. L wird hier gemäß dem 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 umfassen kann. Eine Anleitung zum Schreiben mit Regelsyntax in Android Studio finden Sie im Plug-in Android-Baseline-Profile.

Ein Beispiel für eine Platzhalterregel könnte so aussehen:

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

Unterstützte Typen in Regeln für Baseline-Profile

Für Regeln für Baseline-Profile werden die folgenden Typen unterstützt. Weitere Informationen zu diesen Typen finden Sie im Artikel zum Dalvik Executable (DEX)-Format.

Zeichen Eingeben Beschreibung
B Byte Signiertes Byte
C char Unicode-Zeichencodepunkt, codiert in UTF-16
D Doppelt Gleitkommawert mit doppelter Genauigkeit
F float Gleitkommawert mit einfacher Genauigkeit
I int Ganzzahl
J long Ganzzahl mit hoher Präzision
S kurz Signierte Kurzform
V void Ungültig
Z Boolesch Richtig oder falsch?
L (Klassenname) Referenz Eine Instanz eines Klassennamens

Außerdem können Bibliotheken Regeln definieren, die in AAR-Artefakten verpackt sind. Wenn Sie ein APK erstellen, das diese Artefakte enthält, werden die Regeln ähnlich wie beim Zusammenführen von Manifesten zusammengeführt und in ein kompaktes binäres 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-Ebene 28) oder Android 7 (API-Ebene 24) bei Verwendung von ProfileInstaller einen bestimmten Teil der App AOT zu kompilieren.

Baseline-Profile manuell erfassen

Sie können ein Baseline-Profil manuell generieren, ohne die Macrobenchmark-Bibliothek einzurichten, und UI-Automatisierungen für Ihre kritischen User Journeys erstellen. Wir empfehlen zwar die Verwendung von Makrobenchmarks, dies ist jedoch nicht immer möglich. Wenn Sie beispielsweise kein Gradle-Buildsystem 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. Das ist viel einfacher, wenn Sie ein Gerät oder einen Emulator mit API 34 und höher verwenden. Bei niedrigeren API-Ebenen ist dies zwar auch möglich, erfordert aber Root-Zugriff und Sie müssen einen Emulator mit einem AOSP-Image verwenden. So erfassen Sie Regeln direkt:

  1. Installieren Sie eine Releaseversion Ihrer App auf einem Testgerät. Der Buildtyp der App muss für ein genaues Profil R8-optimiert und nicht debugbar sein.
  2. Die Profile dürfen nicht bereits kompiliert sein.

    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 Ihr APK von der Profile Installer-Bibliothek von Jetpack abhängig ist, wird beim ersten Start Ihres APKs ein Profil gestartet. Dies kann die Profilgenerierung beeinträchtigen. Deaktivieren Sie es 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 führen Sie die kritischen User Journeys manuell aus, für die Sie ein Profil erstellen möchten.
  4. ART auffordern, die Profile zu dumpen. Wenn Ihr APK von der Jetpack-Bibliothek „Profile Installer“ abhängig ist, können Sie die Profile damit dumpen:

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

    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 Profilgenerierung abgeschlossen ist.
  6. Konvertieren Sie die generierten Binärprofile in Text:

    API 34 und höher

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

    API 33 und niedriger

    Prüfen Sie, 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 an folgendem Speicherort:

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

    Speicherort des APK ermitteln:

    adb root
    adb shell pm path $PACKAGE_NAME
    

    Führen Sie die Umwandlung aus:

    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. Rufen Sie das gedumpte Profil mit adb vom Gerät ab:

    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 App das nächste Mal erstellen, wird das Baseline-Profil eingeschlossen. Führen Sie dazu die Schritte unter Installationsprobleme aus.

App-Verbesserungen manuell messen

Wir empfehlen Ihnen dringend, App-Verbesserungen durch Benchmarking zu messen. Wenn Sie die Verbesserungen jedoch manuell messen möchten, können Sie als Referenz den Start der nicht optimierten App 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 prü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 wurde:

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

Sie können die Leistung beim Starten der App jetzt wie gewohnt 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 profgen

In diesem Abschnitt wird beschrieben, was das Tool profgen beim Erstellen einer kompakten Binärversion eines Baseline-Profils tut.

Profgen-cli unterstützt die Profilkompilierung, ‑Introspection und ‑Transpilierung von ART-Profilen, damit sie unabhängig von der Ziel-SDK-Version auf Android-Geräten installiert werden können.

Profgen-cli ist eine Befehlszeile, mit der die HRF eines Baseline-Profils in das kompilierte Format kompiliert wird. Die Befehlszeile ist auch im cmdline-tools-Repository als Teil des Android SDK verfügbar.

Diese Funktionen sind in der studio-main-Version verfügbar:

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

Kompakte Binärprofile mit Profgen-cli erstellen

Die mit Profgen-cli verfügbaren Befehle sind bin, validate und dumpProfile. 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 Beispiel für eine Aufrufabfolge:

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 kannst du 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 ist der Pfad zum baseline-prof.txt-HRF.

Profgen-cli benötigt außerdem den Pfad zum Release-Build des APK und eine Obfuscation Map, mit der das APK bei Verwendung von R8 oder Proguard verschleiert wird. So kann profgen beim Erstellen des kompilierten Profils Quellsymbole im HRF in die entsprechenden verschleierten Namen umwandeln.

Da ART-Profilformate nicht vorwärts- oder rückwärtskompatibel sind, geben Sie ein Profilformat an, damit profgen Profilmetadaten (profm) einbettet, mit denen Sie bei Bedarf ein ART-Profilformat in ein anderes umwandeln können.

Profilformate und Plattformversionen

Bei der Auswahl eines Profilformats sind die folgenden Optionen verfügbar:

Profilformat Plattform-Version API-Ebene
v0_1_5_s Android S+ 31+
v0_1_0_p Android P, Q und R 28-30
v0_0_9_omr1 Android O MR1 27
v0_0_5_o Android O 26
v0_0_1_n Android N 24-25

Kopieren Sie die Ausgabedateien baseline.prof und baseline.profm in den Ordner assets oder dexopt im APK.

Verschleierungskarten

Sie müssen die Verschleierungszuordnung nur angeben, wenn im HRF Quellsymbole verwendet werden. Wenn die HRF aus einem Release-Build generiert wird, der bereits verschleiert ist und keine Zuordnung erforderlich ist, können Sie diese Option ignorieren und die Ausgabe in den Ordner assets oder dexopt kopieren.

Traditionelle Installation von Baseline-Profilen

Baseline-Profile werden in der Regel auf eine von zwei Arten auf ein Gerät übertragen.

install-multiple mit DexMetadata verwenden

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

Das APK und das DM werden in einer einzigen Installationssitzung mit einem Befehl wie dem folgenden installiert:

adb install-multiple base.apk base.dm

Jetpack ProfileInstaller

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

Die ProfileInstaller-Bibliothek transkodiert 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.

Baseline-Profil per Sideload installieren

In diesem Abschnitt wird beschrieben, wie Sie ein Baseline-Profil anhand eines APK installieren.

Mit androidx.profileinstaller streamen

Auf Geräten mit API 24 und höher können Sie einen Befehl zum Installieren 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, was etwa 77.000 von 450.000 Apps bei Google Play entspricht. Es ist jedoch in praktisch jeder APK vorhanden, die Compose verwendet. Das liegt daran, dass Bibliotheken Profile bereitstellen können, ohne eine Abhängigkeit von ProfileInstaller anzugeben. Das Hinzufügen einer Abhängigkeit in jeder Bibliothek mit einem Profil gilt ab 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 installieren, ohne dass die ProfileInstaller-Bibliothek in der App vorhanden sein muss.

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ühren Sie die Schritte zum Extrahieren des Profils einmal pro APK aus, um APK-Splits zu unterstützen. Übergeben Sie bei der Installation jedes APK und die zugehörige .dm-Datei. Achten Sie darauf, dass die Namen der APK- und .dm-Dateien übereinstimmen:

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

Bestätigung

Ob das Profil richtig installiert ist, können Sie anhand der Schritte unter App-Verbesserungen manuell messen prüfen.

Inhalt eines Binärprofils dumpen

Wenn Sie den Inhalt einer kompakten Binärversion eines Baseline-Profils prüfen möchten, verwenden Sie die Option dumpProfile der Profgen-CLI:

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 in der kompakten Binärdarstellung nur DEX-Abweichungen gespeichert werden. Daher sind diese erforderlich, um Klassen- und Methodennamen zu rekonstruieren.

Der strenge Modus ist standardmäßig aktiviert. Dabei wird eine Kompatibilitätsprüfung des Profils mit den DEX-Dateien im APK durchgeführt. Wenn Sie versuchen, Profile zu debuggen, die mit einem anderen Tool generiert wurden, kann es zu Kompatibilitätsfehlern kommen, die verhindern, dass Sie einen Dump zur Untersuchung erstellen können. In solchen Fällen können Sie den strengen Modus mit --strict false deaktivieren. In den meisten Fällen sollten Sie den strengen Modus jedoch aktiviert lassen.

Eine Verschlüsselungskarte ist optional. Wenn Sie eine solche Karte angeben, können Sie verschleierte Symbole leichter in ihre visuell lesbaren Versionen umwandeln.