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 gleiche Ordner, in dem sich auch die Datei AndroidManifest.xml befindet.

In der Datei ist eine Regel pro Zeile angegeben. Jede Regel stellt ein Muster für den Abgleich von Methoden oder Klassen in der App oder Bibliothek dar, die optimiert werden müssen.

Die Syntax dieser Regeln ist eine Obermenge des menschenlesbaren ART-Profilformats (HRF) bei Verwendung von adb shell profman --dump-classes-and-methods. 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 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;

Regelsyntax

Es gibt zwei Arten von Regeln für das Targeting auf Methoden oder Klassen:

[FLAGS][CLASS_DESCRIPTOR]->[METHOD_SIGNATURE]

Eine Klassenregel verwendet das folgende Muster:

[CLASS_DESCRIPTOR]

In der folgenden Tabelle finden Sie eine detaillierte Beschreibung:

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 „Hot“-Methode handelt, d. h. sie wird während der Lebensdauer der App mehrmals aufgerufen.

Eine Methode mit dem Flag S gibt an, dass sie 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 weist darauf hin, 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 Zielmethode. Beispiel: androidx.compose.runtime.SlotTable hat den Deskriptor Landroidx/compose/runtime/SlotTable;. Im Format Dalvik Executable (DEX) wird hier L 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, sodass eine einzelne Regel mehrere Methoden oder Klassen umfasst. Interaktive Hilfe beim Schreiben mit der Regelsyntax in Android Studio finden Sie unter Android-Baseline-Profile.

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

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

Unterstützte Typen in Ausgangsprofilregeln

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

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

Darüber hinaus können Bibliotheken Regeln definieren, die in AAR-Artefakten gepackt sind. Wenn Sie ein APK erstellen, das diese Artefakte enthält, werden die Regeln – ähnlich wie bei der Zusammenführung von Manifesten – zusammengeführt 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 AOT eine bestimmte Teilmenge der App bei der Installation unter Android 9 (API-Level 28) oder Android 7 (API-Level 24) mit ProfileInstaller zu kompilieren.

Baseline-Profile manuell erfassen

Sie können manuell ein Baseline-Profil generieren, ohne die MacroBenchmark-Bibliothek einzurichten, und UI-Automatisierungen Ihrer kritischen Nutzerpfade erstellen. Obwohl wir 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 „Baseline Profile“ 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 verwenden, auf dem API 34 und höher ausgeführt wird. Mit niedrigeren API-Levels ist dies zwar noch möglich, erfordert jedoch Root-Zugriff und Sie müssen einen Emulator verwenden, der ein AOSP-Image ausführt. So können Sie Regeln direkt erfassen:

  1. Installiere eine veröffentlichte Version deiner App auf einem Testgerät. Der App-Build-Typ muss R8-optimiert und nicht Debug-fähig sein, um ein genaues Profil zu erhalten.
  2. Stellen Sie sicher, 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 Ihr APK von der Jetpack-Bibliothek Profile Installer abhängig ist, führt die Bibliothek beim ersten Start Ihres APKs ein Profil per Bootstrapping durch. Dies kann die Profilgenerierung 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. Fordern Sie ART an, die Profile zu speichern. Wenn Ihr APK von der Jetpack Profile Installer-Bibliothek abhängig ist, verwenden Sie diese, um die Profile zu speichern:

    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, speichern 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

    Ermittle, ob ein Referenzprofil oder ein aktuelles Profil erstellt wurde. Ein Referenzprofil befindet sich hier:

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

    Ein aktuelles Profil befindet sich an folgendem Ort:

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

    Bestimmen 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 Dump-Profil 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 App das nächste Mal erstellen, ist das Baseline-Profil enthalten. Prüfen Sie dies anhand der Schritte unter Probleme bei der Installation.

App-Verbesserungen manuell messen

Wir empfehlen Ihnen dringend, die App-Verbesserungen durch Benchmarking zu messen. Wenn Sie Verbesserungen jedoch manuell messen möchten, können Sie zuerst den nicht optimierten Start von Anwendungen 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"

Übertragen Sie als Nächstes das Baseline-Profil per Sideload.

# 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

Aus der Ausgabe muss hervorgehen, 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]

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 Kompetenz

In diesem Abschnitt wird beschrieben, welche Aufgaben das profgen-Tool beim Erstellen einer kompakten Binärversion eines Baseline-Profils ausführt.

Profgen-cli unterstützt die Profilkompilierung, Selbstprüfung und Transpilation von ART-Profilen, sodass sie unabhängig von der SDK-Zielversion auf Android-Geräten installiert werden können.

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

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

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

Kompakte binäre Profile mit Profgen-cli erstellen

Die mit Profgen-cli verfügbaren Befehle sind bin, validate und dumpProfile. Verwenden Sie profgen --help, um die verfügbaren Befehle aufzurufen:

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 \

Verwenden Sie profgen bin options_list, um die verfügbaren Optionen aufzurufen:

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 gibt den Pfad zur baseline-prof.txt-HRF an.

Profgen-cli benötigt außerdem 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 Quellsymbole in der HRF in die entsprechenden verschleierten Namen beim Erstellen des kompilierten Profils übersetzen.

Da ART-Profilformate nicht vorwärts oder abwärtskompatibel sind, solltest du ein Profilformat bereitstellen, damit profgen Profilmetadaten (profm) bündelt, die du bei Bedarf verwenden kannst, um ein ART-Profilformat in ein anderes zu transcodieren.

Profilformate und Plattformversionen

Die folgenden Optionen sind verfügbar, wenn Sie ein Profilformat auswählen:

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

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

Verschleierungskarten

Du musst die Verschleierungskarte nur angeben, wenn für die HRF Quellsymbole verwendet werden. 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

Baseline-Profile werden üblicherweise auf 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 das APK und die DM-Nutzlast (APK) für eine zu installierende APK-Version herunter. 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. Beispiel:

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, um ein in assets oder dexopt verpacktes Profil zu installieren, nachdem das APK auf dem Gerät installiert wurde. ProfileInstaller wird von ProfileInstallReceiver oder direkt von der Anwendung aufgerufen.

Die ProfileInstaller-Bibliothek transkodiert das Profil basierend auf der SDK-Version des Zielgeräts und kopiert das Profil auf dem Gerät in das Verzeichnis cur (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.

Sideload eines Baseline-Profils

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

Nachricht an alle mit androidx.profileinstaller

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 in etwa 77.000 von 450.000 Apps bei Google Play ausmacht –, obwohl es praktisch in allen APKs mit Composer vorhanden ist. Dies 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 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 übertragen, 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

Damit das Aufteilen von APKs unterstützt wird, führen Sie die vorherigen Schritte zum Extrahieren des Profils einmal pro APK aus. Übergeben Sie bei der Installation jedes APK und die zugehörige .dm-Datei und achten Sie darauf, dass die Namen des APK und .dm übereinstimmen:

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

Bestätigung

Mithilfe der Schritte unter Anwendungsverbesserungen manuell messen können Sie prüfen, ob das Profil korrekt installiert ist.

Inhalt eines binären Profils sichern

Verwenden Sie die Profgen-cli-Option dumpProfile, um sich den Inhalt einer kompakten Binärversion eines Baseline-Profils anzusehen:

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ärdarstellung nur DEX-Offsets speichert und diese daher zur Rekonstruktion von Klassen- und Methodennamen benötigt.

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 versuchen, Fehler in Profilen zu beheben, die von einem anderen Tool generiert wurden, treten möglicherweise Kompatibilitätsfehler auf, die verhindern, dass Sie einen Dump für die Untersuchung erstellen können. In solchen Fällen können Sie den strikten Modus mit --strict false deaktivieren. In den meisten Fällen sollte der strikte Modus jedoch aktiviert bleiben.

Eine Verschleierungskarte ist optional. Wenn sie bereitgestellt wird, können verschleierte Symbole zur einfacheren Verwendung ihren für Menschen lesbaren Versionen neu zugeordnet werden.