Créer et mesurer manuellement des profils de référence

Nous vous recommandons vivement d'automatiser la génération de règles de profil à l'aide de la bibliothèque Jetpack Macrobenchmark afin de réduire les efforts manuels et d'améliorer l'évolutivité générale. Toutefois, vous pouvez créer et mesurer manuellement des règles de profil dans votre application.

Définir des règles de profil manuellement

Vous pouvez définir manuellement des règles de profil dans une application ou un module de bibliothèque en créant un fichier nommé baseline-prof.txt dans le répertoire src/main. Il s'agit du même dossier que celui contenant le fichier AndroidManifest.xml.

Le fichier spécifie une règle par ligne. Chaque règle représente un modèle de correspondance entre les méthodes ou les classes de l'application ou de la bibliothèque qui doivent être optimisées.

La syntaxe de ces règles correspond à un sur-ensemble du format de profil ART (HRF) intelligible lorsque adb shell profman --dump-classes-and-methods est utilisé. La syntaxe est semblable à la syntaxe des descripteurs et des signatures, mais elle permet d'utiliser des caractères génériques pour simplifier le processus d'écriture des règles.

L'exemple suivant présente quelques règles de profil de référence incluses dans la bibliothèque Jetpack Compose :

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;

Syntaxe des règles

Ces règles prennent l'une des formes suivantes pour cibler les méthodes ou les classes :

[FLAGS][CLASS_DESCRIPTOR]->[METHOD_SIGNATURE]

Une règle de classe utilise le format suivant :

[CLASS_DESCRIPTOR]

Consultez le tableau suivant pour obtenir une description détaillée :

Syntaxe Description
FLAGS Représente un ou plusieurs des caractères H, S et P pour indiquer si cette méthode doit être signalée comme Hot, Startup ou Post Startup par rapport au type de démarrage.

Une méthode avec l'indicateur H indique qu'il s'agit d'une méthode "Hot", ce qui signifie qu'elle est appelée plusieurs fois pendant la durée de vie de l'application.

Une méthode avec l'indicateur S indique qu'il s'agit d'une méthode appelée au démarrage.

Une méthode avec l'indicateur P indique qu'il s'agit d'une méthode appelée après le démarrage.

Une classe présente dans ce fichier indique qu'elle est utilisée au démarrage et doit être préallouée dans le tas de mémoire pour éviter le coût de chargement de la classe. Le compilateur ART utilise différentes stratégies d'optimisation, telles que la compilation anticipée (ou compilation AOT) de ces méthodes et l'optimisation de la mise en page dans le fichier AOT généré.
CLASS_DESCRIPTOR Descripteur de la classe de méthode ciblée. Par exemple, androidx.compose.runtime.SlotTable contient un descripteur de Landroidx/compose/runtime/SlotTable;. Le préfixe L est ajouté ici au format Dalvik Executable (DEX).
METHOD_SIGNATURE Signature de la méthode, y compris son nom, ses types de paramètres et de retour. Par exemple :

// LayoutNode.kt

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

sur LayoutNode a la signature isPlaced()Z.

Ces modèles peuvent avoir des caractères génériques pour qu'une même règle englobe plusieurs méthodes ou classes. Pour obtenir un guide d'écriture avec la syntaxe des règles dans Android Studio, consultez le plug-in Profils de référence Android.

Exemple de règle avec caractères génériques :

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

Types acceptés dans les règles de profil de référence

Les règles de profil de référence sont compatibles avec les types suivants. Pour en savoir plus sur ces types, consultez le format Dalvik Executable (DEX).

Caractère Type Description
B octet Octet signé
C car. Point de code de caractères Unicode encodés en UTF-16
D double Valeur de double précision à virgule flottante
F float Valeur de simple précision à virgule flottante
I int Nombre entier
J long Entier long
S court Signé court
V void Vide
Z booléen Vrai ou faux
L (nom de classe) référence Instance d'un nom de classe

De plus, les bibliothèques peuvent définir des règles qui sont empaquetées dans des artefacts d'archive Android (AAR). Lorsque vous créez un APK pour inclure ces artefacts, les règles sont fusionnées (de la même manière que pour le fichier manifeste) et compilées dans un profil ART binaire compact spécifique à l'APK.

ART exploite ce profil lorsque l'APK est utilisé sur les appareils pour une compilation anticipée d'un sous-ensemble spécifique de l'application au moment de l'installation sur Android 9 (niveau d'API 28) ou Android 7 (niveau d'API 24) avec ProfileInstaller.

Collecter manuellement des profils de référence

Vous pouvez générer manuellement un profil de référence sans configurer la bibliothèque Macrobenchmark et créer des automatisations d'UI pour vos critical user journeys. Bien que l'utilisation des Macrobenchmarks soit recommandée, cela n'est pas toujours possible. Par exemple, si vous utilisez un système de compilation autre que Gradle, vous ne pouvez pas utiliser le plug-in Profil de référence Gradle. Dans ce cas, vous pouvez collecter manuellement les règles du profil de référence. Il est beaucoup plus simple de réaliser cette opération si vous utilisez un appareil ou un émulateur qui exécute le niveau d'API 34 ou supérieur. Bien que cela reste possible avec des niveaux d'API inférieurs, l'opération requiert un accès racine et votre émulateur doit pouvoir exécuter une image AOSP. Pour collecter des règles directement, procédez comme suit :

  1. Installez une version de votre appli sur un appareil de test. Pour obtenir un profil précis, le type de compilation de l'appli doit être optimisé pour R8 et non débogable.
  2. Assurez-vous que les profils ne sont pas déjà compilés.

    Niveau d'API 34 et supérieur

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

    Niveau d'API 33 et inférieur

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

    Si votre APK possède une dépendance sur la bibliothèque Jetpack Profile Installer, celle-ci amorce un profil lors du premier lancement de votre APK. Cela peut interférer avec le processus de génération du profil. Désactivez-le à l'aide de la commande suivante :

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

  3. Exécutez l'appli et parcourez manuellement les critical user journeys pour lesquels vous souhaitez collecter un profil.
  4. Incitez ART à vider les profils. Si votre APK possède une dépendance sur la bibliothèque du programme d'installation de profil Jetpack, utilisez-la pour vider les profils :

    adb shell am broadcast -a androidx.profileinstaller.action.SAVE_FILE $PACKAGE_NAME/androidx.profileinstaller.ProfileInstallReceiver
    adb shell am force-stop $PACKAGE_NAME
    
    Si vous n'utilisez pas le programme d'installation de profil, videz les profils manuellement sur un émulateur à l'aide de la commande suivante:

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

  5. Patientez au moins cinq secondes, jusqu'à ce que la génération du profil se termine.
  6. Convertissez les profils binaires générés au format texte :

    Niveau d'API 34 et supérieur

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

    Niveau d'API 33 et inférieur

    Déterminez si un profil de référence ou un profil actuel a été créé. Les profils de référence se trouvent à l'emplacement suivant :

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

    Les profils actuels se trouvent à l'emplacement suivant :

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

    Déterminez l'emplacement de l'APK :

    adb root
    adb shell pm path $PACKAGE_NAME
    

    Effectuez la conversion :

    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. Utilisez adb pour récupérer le profil vidé de l'appareil :

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

Les règles de profil générées sont alors extraites et installées dans le module de votre appli. La prochaine fois que vous compilerez l'appli, le profil de référence sera inclus. Vérifiez cela en suivant la procédure décrite dans la section Problèmes d'installation.

Mesurer manuellement les améliorations des applis

Nous vous recommandons fortement de mesurer les améliorations d'applications en procédant à une analyse comparative. Toutefois, si vous souhaitez mesurer les améliorations manuellement, vous pouvez commencer par mesurer le démarrage de l'application non optimisé à titre de référence.

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"

Ensuite, téléchargez indépendamment le profil de référence.

# 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

Pour vérifier que le package a été optimisé à l'installation, exécutez la commande suivante :

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

La sortie doit indiquer que le package est compilé :

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

Vous pouvez maintenant mesurer les performances de démarrage de l'application comme vous le faisiez auparavant, mais sans réinitialiser l'état compilé. Veillez à ne pas réinitialiser l'état compilé pour le package.

# 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"

Profils de référence et profgen

Cette section décrit le rôle de l'outil profgen lors de la création d'une version binaire compacte d'un profil de référence.

Profgen-cli facilite la compilation de profils, l'introspection et la transpilation de profils ART, afin qu'ils puissent être installés sur des appareils Android, quelle que soit la version du SDK cible.

Profgen-cli est une CLI qui compile le HRF d'un profil de référence dans son format compilé. La CLI est également fournie dans le dépôt cmdline-tools avec le SDK Android.

Ces fonctionnalités sont disponibles dans la branche studio-main :

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

Créer des profils binaires compacts avec Profgen-cli

Les commandes disponibles avec Profgen-cli sont bin, validate et dumpProfile. Pour afficher les commandes disponibles, utilisez profgen --help :

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

Utilisez la commande bin pour générer le profil binaire compact. Voici un exemple d'appel :

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

Pour afficher les options disponibles, utilisez profgen bin options_list :

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

Le premier argument représente le chemin d'accès au HRF baseline-prof.txt.

Profgen-cli a également besoin du chemin d'accès au build de l'APK et d'un mappage d'obscurcissement qui permet d'obscurcir l'APK lorsque vous utilisez R8 ou ProGuard. De cette façon, profgen peut traduire les symboles sources du HRF en noms obscurcis correspondants lors de la création du profil compilé.

Étant donné que les formats de profil ART ne sont pas compatibles avec les versions futures ou antérieures, fournissez un format de profil permettant à profgen de regrouper les métadonnées de profil (profm) que vous pouvez utiliser pour transcoder un format de profil ART dans un autre format lorsque c'est obligatoire.

Formats de profil et versions de la plate-forme

Les options suivantes sont disponibles lorsque vous choisissez un format de profil :

Format du profil Version de la plate-forme Niveau d'API
v0_1_5_s Android S+ 31 ou +
v0_1_0_p Android P, Q et 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

Copiez les fichiers de sortie baseline.prof et baseline.profm dans le dossier assets ou dexopt de l'APK.

Cartes d'obscurcissement

Vous ne devez fournir la carte d'obscurcissement que si le HRF utilise des symboles sources. Si la HRF est générée à partir d'un build déjà obscurci et qu'aucun mappage n'est nécessaire, vous pouvez ignorer cette option et copier les sorties dans le dossier assets ou dexopt.

Installation classique des profils de référence

Les profils de référence sont traditionnellement distribués sur un appareil de deux manières.

Utiliser install-multiple avec DexMetadata

Sur les appareils exécutant l'API 28 ou une version ultérieure, le client Play télécharge l'APK et la charge utile DexMetadata (DM) pour l'installation d'une version d'APK. La DM contient les informations de profil transmises au gestionnaire de paquets de l'appareil.

L'APK et la DM sont installés dans le cadre d'une seule session d'installation, par exemple à l'aide de l'instruction suivante :

adb install-multiple base.apk base.dm

Jetpack ProfileInstaller

Sur les appareils exécutant le niveau d'API 29 ou ultérieur, la bibliothèque Jetpack ProfileInstaller fournit un mécanisme alternatif pour installer un profil empaqueté dans assets ou dexopt après l'installation de l'APK sur l'appareil. ProfileInstaller est appelé par ProfileInstallReceiver ou directement par l'application.

La bibliothèque ProfileInstaller transcode le profil en fonction de la version du SDK de l'appareil cible et le copie dans le répertoire cur de l'appareil (un répertoire de préproduction spécifique au package pour les profils ART sur l'appareil).

Une fois l'appareil inactif, le profil est récupéré par un processus appelé bg-dexopt sur l'appareil.

Télécharger un profil de référence indépendamment

Cette section explique comment installer un profil de référence à partir d'un APK.

Diffuser avec androidx.profileinstaller

Sur les appareils exécutant l'API 24 ou une version ultérieure, vous pouvez diffuser une commande pour installer le profil :

# 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 n'est pas présent dans la plupart des APK avec des profils de référence, qui sont inclus dans environ 77 000 applications sur 450 000 dans Google Play, bien qu'il soit présent dans chaque APK utilisant Compose. Les bibliothèques peuvent fournir des profils sans déclarer de dépendances sur ProfileInstaller. L'ajout d'une dépendance dans chaque bibliothèque avec un profil s'applique à partir de Jetpack.

Utiliser install-multiple avec profgen ou DexMetaData

Sur les appareils exécutant l'API 28 ou une version ultérieure, vous pouvez télécharger un profil de référence indépendamment, sans avoir à accéder à la bibliothèque ProfileInstaller.

Pour ce faire, utilisez 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

Pour prendre en charge les APK divisés, exécutez les étapes précédentes du profil d'extraction une fois par APK. Au moment de l'installation, transmettez chaque APK et le fichier .dm associé, en vous assurant que les noms de l'APK et de .dm correspondent :

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

Validation

Pour vérifier que le profil est correctement installé, suivez la procédure décrite dans Mesurer manuellement les améliorations d'une application.

Vider le contenu d'un profil binaire

Pour introduire le contenu d'une version binaire compacte d'un profil de référence, utilisez l'option dumpProfile de 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 a besoin de l'APK, car la représentation binaire compacte ne stocke que des décalages DEX. Par conséquent, il a besoin de reconstruire les noms des classes et des méthodes.

Le mode strict est activé par défaut. Il effectue une vérification de compatibilité du profil avec les fichiers DEX de l'APK. Si vous essayez de déboguer des profils générés par un autre outil, vous pouvez obtenir des échecs de compatibilité qui vous empêchent de procéder à une analyse. Dans ce cas, vous pouvez désactiver le mode strict avec --strict false. Toutefois, dans la plupart des cas, vous devez laisser le mode strict activé.

Un plan d'obscurcissement est facultatif. Lorsqu'il est fourni, il permet de remapper les symboles obscurcis vers leurs versions lisibles par l'humain pour faciliter leur utilisation.