Le système de compilation Android pour Android 13 et versions antérieures prend en charge l'optimisation guidée par le profil (PGO) de Clang sur les modules Android natifs qui disposent de règles de compilation blueprint. Cette page décrit le PGO Clang, comment générer et mettre à jour en continu les profils utilisés pour le PGO, et comment intégrer le PGO au système de compilation (avec un cas d'utilisation).
Remarque: Ce document décrit l'utilisation de PGO sur la plate-forme Android. Pour en savoir plus sur l'utilisation de PGO à partir d'une application Android, consultez cette page.
À propos de PGO Clang
Clang peut effectuer une optimisation guidée par le profil à l'aide de deux types de profils:
- Les profils basés sur l'instrumentation sont générés à partir d'un programme cible instrumenté. Ces profils sont détaillés et imposent un coût d'exécution élevé.
- Les profils basés sur l'échantillonnage sont généralement produits en échantillonnant les compteurs matériels. Ils imposent un faible coût d'exécution et peuvent être collectés sans instrumentation ni modification du binaire. Ils sont moins détaillés que les profils basés sur l'instrumentation.
Tous les profils doivent être générés à partir d'une charge de travail représentative qui exerce le comportement typique de l'application. Bien que Clang prenne en charge à la fois les profils basés sur l'AST (-fprofile-instr-generate
) et ceux basés sur l'IR LLVM (-fprofile-generate)
), Android n'accepte que les profils basés sur l'IR LLVM pour le PGO basé sur l'instrumentation.
Les indicateurs suivants sont nécessaires pour créer la collecte de profils:
-fprofile-generate
pour l'instrumentation basée sur l'IR Avec cette option, le backend utilise une approche d'arborescence minimale pondérée pour réduire le nombre de points d'instrumentation et optimiser leur emplacement sur les arêtes à faible poids (utilisez également cette option pour l'étape d'association). Le pilote Clang transmet automatiquement l'environnement d'exécution de profilage (libclang_rt.profile-arch-android.a
) au linker. Cette bibliothèque contient des routines permettant d'écrire les profils sur disque à la sortie du programme.-gline-tables-only
pour la collecte de profils basée sur l'échantillonnage afin de générer des informations de débogage minimales.
Un profil peut être utilisé pour PGO à l'aide de -fprofile-use=pathname
ou de -fprofile-sample-use=pathname
pour les profils basés sur l'instrumentation et l'échantillonnage, respectivement.
Remarque:Lorsque des modifications sont apportées au code, si Clang ne peut plus utiliser les données de profil, il génère un avertissement -Wprofile-instr-out-of-date
.
Utiliser PGO
Pour utiliser PGO, procédez comme suit:
- Créez la bibliothèque/l'exécutable avec instrumentation en transmettant
-fprofile-generate
au compilateur et à l'éditeur de liens. - Collectez des profils en exécutant une charge de travail représentative sur le binaire instrumenté.
- Post-traitez les profils à l'aide de l'utilitaire
llvm-profdata
(pour en savoir plus, consultez la section Gérer les fichiers de profil LLVM). - Utilisez les profils pour appliquer PGO en transmettant
-fprofile-use=<>.profdata
au compilateur et à l'outil d'association.
Pour PGO sur Android, les profils doivent être collectés hors connexion et enregistrés avec le code pour garantir la reproductibilité des builds. Les profils peuvent être utilisés à mesure que le code évolue, mais doivent être régénérés régulièrement (ou chaque fois que Clang avertit que les profils sont obsolètes).
Collecter des profils
Clang peut utiliser les profils collectés en exécutant des benchmarks à l'aide d'une version instrumentée de la bibliothèque ou en échantillonnant des compteurs matériels lors de l'exécution du benchmark. Pour le moment, Android n'est pas compatible avec la collecte de profils basée sur l'échantillonnage. Vous devez donc collecter des profils à l'aide d'un build instrumenté:
- Identifiez un benchmark et l'ensemble des bibliothèques exercées collectivement par ce benchmark.
- Ajoutez des propriétés
pgo
au benchmark et aux bibliothèques (détails ci-dessous). - Créez un build Android avec une copie instrumentée de ces bibliothèques à l'aide de:
make ANDROID_PGO_INSTRUMENT=benchmark
benchmark
est un espace réservé qui identifie la collection de bibliothèques instrumentées lors de la compilation. Les entrées représentatives réelles (et éventuellement un autre exécutable qui établit un lien avec une bibliothèque en cours de benchmarking) ne sont pas spécifiques à PGO et sortent du cadre de ce document.
- Flashez ou synchronisez le build instrumenté sur un appareil.
- Exécutez le benchmark pour collecter les profils.
- Utilisez l'outil
llvm-profdata
(décrit ci-dessous) pour post-traiter les profils et les préparer à être intégrés à l'arborescence source.
Utiliser des profils lors de la compilation
Vérifiez les profils dans toolchain/pgo-profiles
dans un arbre Android. Le nom doit correspondre à celui spécifié dans la sous-propriété profile_file
de la propriété pgo
pour la bibliothèque. Le système de compilation transmet automatiquement le fichier de profil à Clang lors de la compilation de la bibliothèque. La variable d'environnement ANDROID_PGO_DISABLE_PROFILE_USE
peut être définie sur true
pour désactiver temporairement PGO et mesurer ses avantages en termes de performances.
Pour spécifier des répertoires de profils spécifiques au produit supplémentaires, ajoutez-les à la variable de création PGO_ADDITIONAL_PROFILE_DIRECTORIES
dans un fichier BoardConfig.mk
. Si des chemins d'accès supplémentaires sont spécifiés, les profils de ces chemins remplacent ceux de toolchain/pgo-profiles
.
Lors de la génération d'une image de version à l'aide de la cible dist
pour make
, le système de compilation écrit les noms des fichiers de profil manquants dans $DIST_DIR/pgo_profile_file_missing.txt
. Vous pouvez consulter ce fichier pour voir quels fichiers de profil ont été supprimés par erreur (ce qui désactive PGO de manière silencieuse).
Activer PGO dans les fichiers Android.bp
Pour activer PGO dans les fichiers Android.bp
pour les modules natifs, spécifiez simplement la propriété pgo
. Cette propriété comporte les sous-propriétés suivantes:
Propriété | Description |
---|---|
instrumentation
|
Défini sur true pour PGO à l'aide de l'instrumentation. La valeur par défaut est false . |
sampling
|
Défini sur true pour l'optimisation PGO à l'aide de l'échantillonnage. La valeur par défaut est false . |
benchmarks
|
Liste de chaînes. Ce module est conçu pour le profilage si un benchmark de la liste est spécifié dans l'option de compilation ANDROID_PGO_INSTRUMENT . |
profile_file
|
Fichier de profil (par rapport à toolchain/pgo-profile ) à utiliser avec PGO. La compilation avertit que ce fichier n'existe pas en l'ajoutant à $DIST_DIR/pgo_profile_file_missing.txt
sauf si la propriété enable_profile_use est définie sur false OU la variable de compilation ANDROID_PGO_NO_PROFILE_USE est définie sur true . |
enable_profile_use
|
Définissez la valeur sur false si les profils ne doivent pas être utilisés lors de la compilation. Peut être utilisé lors du démarrage pour activer la collecte de profils ou pour désactiver temporairement PGO. La valeur par défaut est true . |
cflags
|
Liste d'options supplémentaires à utiliser lors d'une compilation instrumentée. |
Exemple de module avec PGO:
cc_library { name: "libexample", srcs: [ "src1.cpp", "src2.cpp", ], static: [ "libstatic1", "libstatic2", ], shared: [ "libshared1", ] pgo: { instrumentation: true, benchmarks: [ "benchmark1", "benchmark2", ], profile_file: "example.profdata", } }
Si les benchmarks benchmark1
et benchmark2
exercent un comportement représentatif pour les bibliothèques libstatic1
, libstatic2
ou libshared1
, la propriété pgo
de ces bibliothèques peut également inclure les benchmarks. Le module defaults
dans Android.bp
peut inclure une spécification pgo
commune pour un ensemble de bibliothèques afin d'éviter de répéter les mêmes règles de compilation pour plusieurs modules.
Pour sélectionner différents fichiers de profil ou désactiver sélectivement PGO pour une architecture, spécifiez les propriétés profile_file
, enable_profile_use
et cflags
par architecture. Exemple (avec la cible d'architecture en gras):
cc_library { name: "libexample", srcs: [ "src1.cpp", "src2.cpp", ], static: [ "libstatic1", "libstatic2", ], shared: [ "libshared1", ], pgo: { instrumentation: true, benchmarks: [ "benchmark1", "benchmark2", ], } target: { android_arm: { pgo: { profile_file: "example_arm.profdata", } }, android_arm64: { pgo: { profile_file: "example_arm64.profdata", } } } }
Pour résoudre les références à la bibliothèque d'exécution de profilage lors du profilage basé sur l'instrumentation, transmettez l'indicateur de compilation -fprofile-generate
au linker. Les bibliothèques statiques instrumentées avec PGO, toutes les bibliothèques partagées et tout binaire qui dépend directement de la bibliothèque statique doivent également être instrumentées pour PGO. Toutefois, ces bibliothèques partagées ou exécutables n'ont pas besoin d'utiliser de profils PGO, et leur propriété enable_profile_use
peut être définie sur false
.
En dehors de cette restriction, vous pouvez appliquer PGO à n'importe quelle bibliothèque statique, bibliothèque partagée ou exécutable.
Gérer les fichiers de profil LLVM
L'exécution d'une bibliothèque ou d'un exécutable instrumentés génère un fichier de profil nommé default_unique_id_0.profraw
dans /data/local/tmp
(où unique_id
est un hachage numérique propre à cette bibliothèque). Si ce fichier existe déjà, le runtime de profilage fusionne le nouveau profil avec l'ancien lors de l'écriture des profils. Notez que /data/local/tmp
n'est pas accessible aux développeurs d'applications. Ils doivent utiliser /storage/emulated/0/Android/data/packagename/files
à la place.
Pour modifier l'emplacement du fichier de profil, définissez la variable d'environnement LLVM_PROFILE_FILE
au moment de l'exécution.
L'utilitaire llvm-profdata
permet ensuite de convertir le fichier .profraw
(et éventuellement de fusionner plusieurs fichiers .profraw
) en fichier .profdata
:
llvm-profdata merge -output=profile.profdata <.profraw and/or .profdata files>
profile.profdata
peut ensuite être enregistré dans l'arborescence source pour être utilisé lors de la compilation.
Si plusieurs binaires/bibliothèques instrumentés sont chargés lors d'un benchmark, chaque bibliothèque génère un fichier .profraw
distinct avec un identifiant unique distinct. En règle générale, tous ces fichiers peuvent être fusionnés dans un seul fichier .profdata
et utilisés pour la compilation PGO. Lorsqu'une bibliothèque est utilisée par un autre benchmark, elle doit être optimisée à l'aide des profils des deux benchmarks. Dans ce cas, l'option show
de llvm-profdata
est utile:
llvm-profdata merge -output=default_unique_id.profdata default_unique_id_0.profraw llvm-profdata show -all-functions default_unique_id.profdata
Pour mapper des unique_id à des bibliothèques individuelles, recherchez dans la sortie show
pour chaque unique_id un nom de fonction propre à la bibliothèque.
Étude de cas: PGO pour l'ART
L'étude de cas présente ART comme un exemple pertinent. Toutefois, elle ne constitue pas une description précise de l'ensemble réel de bibliothèques profilées pour ART ni de leurs interdépendances.
Le compilateur AART dex2oat
dans ART dépend de libart-compiler.so
, qui dépend à son tour de libart.so
. L'environnement d'exécution ART est implémenté principalement dans libart.so
. Les benchmarks du compilateur et de l'environnement d'exécution seront différents:
Benchmark | Bibliothèques profilées |
---|---|
dex2oat
|
dex2oat (exécutable), libart-compiler.so ,
libart.so |
art_runtime
|
libart.so
|
- Ajoutez la propriété
pgo
suivante àdex2oat
,libart-compiler.so
:pgo: { instrumentation: true, benchmarks: ["dex2oat",], profile_file: "dex2oat.profdata", }
- Ajoutez la propriété
pgo
suivante àlibart.so
:pgo: { instrumentation: true, benchmarks: ["art_runtime", "dex2oat",], profile_file: "libart.profdata", }
- Créez des builds instrumentés pour les benchmarks
dex2oat
etart_runtime
à l'aide des éléments suivants:make ANDROID_PGO_INSTRUMENT=dex2oat make ANDROID_PGO_INSTRUMENT=art_runtime
- Exécutez les benchmarks qui utilisent
dex2oat
etart_runtime
pour obtenir :- Trois fichiers
.profraw
dedex2oat
(dex2oat_exe.profdata
,dex2oat_libart-compiler.profdata
etdexeoat_libart.profdata
), identifiés à l'aide de la méthode décrite dans Gérer les fichiers de profil LLVM. - Un seul
art_runtime_libart.profdata
.
- Trois fichiers
- Générez un fichier profdata commun pour l'exécutable
dex2oat
etlibart-compiler.so
à l'aide de:llvm-profdata merge -output=dex2oat.profdata \ dex2oat_exe.profdata dex2oat_libart-compiler.profdata
- Obtenez le profil de
libart.so
en fusionnant les profils des deux benchmarks:llvm-profdata merge -output=libart.profdata \ dex2oat_libart.profdata art_runtime_libart.profdata
Les nombres bruts de
libart.so
des deux profils peuvent être différents, car les benchmarks diffèrent en termes de nombre de cas de test et de durée d'exécution. Dans ce cas, vous pouvez utiliser une fusion pondérée:llvm-profdata merge -output=libart.profdata \ -weighted-input=2,dex2oat_libart.profdata \ -weighted-input=1,art_runtime_libart.profdata
La commande ci-dessus attribue deux fois le poids au profil à partir de
dex2oat
. Le poids réel doit être déterminé en fonction des connaissances du domaine ou de l'expérimentation. - Vérifiez les fichiers de profil
dex2oat.profdata
etlibart.profdata
danstoolchain/pgo-profiles
pour les utiliser lors de la compilation.
Vous pouvez également créer une seule compilation instrumentée avec toutes les bibliothèques instrumentées à l'aide de:
make ANDROID_PGO_INSTRUMENT=dex2oat,art_runtime (or) make ANDROID_PGO_INSTRUMENT=ALL
La deuxième commande compile tous les modules compatibles avec PGO pour le profilage.