Utiliser l'optimisation guidée par le profil

Le système de construction Android pour Android 13 et versions antérieures prend en charge l'optimisation guidée par profil (PGO) de Clang sur les modules Android natifs dotés de règles de construction de modèles . Cette page décrit Clang PGO, comment générer et mettre à jour en permanence les profils utilisés pour PGO, et comment intégrer PGO au système de build (avec cas d'utilisation).

NB : Ce document décrit l'utilisation de PGO dans la plateforme Android. Pour en savoir plus sur l'utilisation de PGO à partir d'une application Android, visitez cette page .

À propos de Clang PGO

Clang peut effectuer une optimisation guidée par profil à l'aide de deux types de profils :

  • Des 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 une surcharge d'exécution élevée.
  • Les profils basés sur l'échantillonnage sont généralement produits par des compteurs matériels d'échantillonnage. Ils imposent une faible surcharge d'exécution et peuvent être collectés sans aucune 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. Alors que Clang prend en charge à la fois les versions AST ( -fprofile-instr-generate ) et LLVM IR ( -fprofile-generate) , Android ne prend en charge que les versions LLVM IR pour les PGO basés sur l'instrumentation.

Les indicateurs suivants sont nécessaires pour créer la collection de profils :

  • -fprofile-generate pour l'instrumentation basée sur l'IR. Avec cette option, le backend utilise une approche d'arbre couvrant minimal pondéré pour réduire le nombre de points d'instrumentation et optimiser leur placement sur des bords de faible poids (utilisez également cette option pour l'étape de liaison). Le pilote Clang transmet automatiquement le runtime de profilage ( libclang_rt.profile- arch -android.a ) à l'éditeur de liens. Cette bibliothèque contient des routines pour écrire les profils sur le disque à la sortie du programme.
  • -gline-tables-only pour la collecte de profils basée sur l'échantillonnage afin de générer un minimum d'informations de débogage.

Un profil peut être utilisé pour PGO en utilisant -fprofile-use= pathname ou -fprofile-sample-use= pathname pour les profils basés sur l'instrumentation et basés sur l'échantillonnage respectivement.

Remarque : au fur et à mesure que 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

L'utilisation de PGO implique les étapes suivantes :

  1. Construisez la bibliothèque/l'exécutable avec l'instrumentation en passant -fprofile-generate au compilateur et à l'éditeur de liens.
  2. Collectez des profils en exécutant une charge de travail représentative sur le binaire instrumenté.
  3. Post-traitez les profils à l'aide de l'utilitaire llvm-profdata (pour plus de détails, voir Gestion des fichiers de profil LLVM ).
  4. Utilisez les profils pour appliquer PGO en transmettant -fprofile-use=<>.profdata au compilateur et à l'éditeur de liens.

Pour PGO sur Android, les profils doivent être collectés hors ligne et enregistrés avec le code pour garantir des versions reproductibles. Les profils peuvent être utilisés au fur et à mesure de l'évolution du code, mais doivent être régénérés périodiquement (ou chaque fois que Clang avertit que les profils sont obsolètes).

Collecter des profils

Clang peut utiliser des profils collectés en exécutant des tests de performance à l'aide d'une version instrumentée de la bibliothèque ou en échantillonnant des compteurs matériels lors de l'exécution du test de performance. Pour le moment, Android ne prend pas en charge l'utilisation de la collecte de profils basée sur l'échantillonnage. Vous devez donc collecter des profils à l'aide d'une version instrumentée :

  1. Identifiez un benchmark et l’ensemble des bibliothèques exercées collectivement par ce benchmark.
  2. Ajoutez des propriétés pgo au benchmark et aux bibliothèques (détails ci-dessous).
  3. Produisez une version Android avec une copie instrumentée de ces bibliothèques en utilisant :
    make ANDROID_PGO_INSTRUMENT=benchmark

benchmark est un espace réservé qui identifie la collection de bibliothèques instrumentées lors de la construction. Les entrées représentatives réelles (et éventuellement un autre exécutable lié à une bibliothèque en cours d'évaluation) ne sont pas spécifiques à PGO et dépassent la portée de ce document.

  1. Flashez ou synchronisez la version instrumentée sur un appareil.
  2. Exécutez le benchmark pour collecter des profils.
  3. Utilisez l'outil llvm-profdata (discuté ci-dessous) pour post-traiter les profils et les préparer à être archivés dans l'arborescence source.

Utiliser des profils pendant la construction

Vérifiez les profils dans toolchain/pgo-profiles dans une arborescence Android. Le nom doit correspondre à ce qui est spécifié dans la sous-propriété profile_file de la propriété pgo de la bibliothèque. Le système de construction transmet automatiquement le fichier de profil à Clang lors de la construction 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 supplémentaires spécifiques au produit, ajoutez-les à la variable make PGO_ADDITIONAL_PROFILE_DIRECTORIES dans un BoardConfig.mk . Si des chemins 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 à make , le système de construction écrit les noms des fichiers de profil manquants dans $DIST_DIR/pgo_profile_file_missing.txt . Vous pouvez vérifier ce fichier pour voir quels fichiers de profil ont été accidentellement supprimés (ce qui désactive silencieusement PGO).

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é possède 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 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 construction ANDROID_PGO_INSTRUMENT .
profile_file Fichier de profil (relatif à toolchain/pgo-profile ) à utiliser avec PGO. La build avertit que ce fichier n'existe pas en ajoutant ce fichier à $DIST_DIR/pgo_profile_file_missing.txt à moins que la propriété enable_profile_use soit définie sur false OU que la variable de build ANDROID_PGO_NO_PROFILE_USE soit définie sur true .
enable_profile_use Définissez sur false si les profils ne doivent pas être utilisés pendant la construction. Peut être utilisé pendant le bootstrap pour activer la collecte de profils ou pour désactiver temporairement PGO. La valeur par défaut est true .
cflags Liste des indicateurs supplémentaires à utiliser lors d'une build 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 construction 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 architecture cible 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 build -fprofile-generate à l'éditeur de liens. Les bibliothèques statiques instrumentées avec PGO, toutes les bibliothèques partagées et tout binaire dépendant directement de la bibliothèque statique doivent également être instrumentés pour PGO. Cependant, ces bibliothèques partagées ou exécutables n'ont pas besoin d'utiliser des 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 instrumentée ou d'un exécutable produit un fichier de profil nommé default_ unique_id _0.profraw dans /data/local/tmp (où unique_id est un hachage numérique unique à 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 devraient plutôt utiliser quelque part comme /storage/emulated/0/Android/data/ packagename /files . 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 est ensuite utilisé pour convertir le fichier .profraw (et éventuellement fusionner plusieurs fichiers .profraw ) en un fichier .profdata :

  llvm-profdata merge -output=profile.profdata <.profraw and/or .profdata files>

profile.profdata peut ensuite être archivé dans l'arborescence source pour être utilisé pendant la construction.

Si plusieurs binaires/bibliothèques instrumentés sont chargés lors d'un test, chaque bibliothèque génère un fichier .profraw distinct avec un ID unique distinct. En règle générale, tous ces fichiers peuvent être fusionnés en un seul fichier .profdata et utilisés pour la construction de PGO. Dans les cas où une bibliothèque est exercée par un autre benchmark, cette bibliothèque doit être optimisée à l'aide des profils des deux benchmarks. Dans cette situation, 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 les unique_id à des bibliothèques individuelles, recherchez dans la sortie show pour chaque unique_id un nom de fonction unique à la bibliothèque.

Étude de cas : PGO pour ART

L'étude de cas présente ART comme un exemple pertinent ; cependant, il ne s'agit pas d'une description précise de l'ensemble réel de bibliothèques profilées pour ART ou de leurs interdépendances.

Le compilateur avancé dex2oat dans ART dépend de libart-compiler.so , qui à son tour dépend de libart.so . Le runtime ART est implémenté principalement dans libart.so . Les benchmarks pour le compilateur et le runtime seront différents :

Référence Bibliothèques profilées
dex2oat dex2oat (exécutable), libart-compiler.so , libart.so
art_runtime libart.so
  1. Ajoutez la propriété pgo suivante à dex2oat , libart-compiler.so :
        pgo: {
            instrumentation: true,
            benchmarks: ["dex2oat",],
            profile_file: "dex2oat.profdata",
        }
  2. Ajoutez la propriété pgo suivante à libart.so :
        pgo: {
            instrumentation: true,
            benchmarks: ["art_runtime", "dex2oat",],
            profile_file: "libart.profdata",
        }
  3. Créez des builds instrumentés pour les benchmarks dex2oat et art_runtime en utilisant :
        make ANDROID_PGO_INSTRUMENT=dex2oat
        make ANDROID_PGO_INSTRUMENT=art_runtime
  4. Vous pouvez également créer une seule version 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 crée tous les modules compatibles PGO pour le profilage.

  5. Exécutez les benchmarks en exerçant dex2oat et art_runtime pour obtenir :
    • Trois fichiers .profraw de dex2oat ( dex2oat_exe.profdata , dex2oat_libart-compiler.profdata et dexeoat_libart.profdata ), identifiés à l'aide de la méthode décrite dans Gestion des fichiers de profil LLVM .
    • Un seul art_runtime_libart.profdata .
  6. Produisez un fichier profdata commun pour l'exécutable dex2oat et libart-compiler.so en utilisant :
    llvm-profdata merge -output=dex2oat.profdata \
        dex2oat_exe.profdata dex2oat_libart-compiler.profdata
  7. Obtenez le profil pour libart.so en fusionnant les profils des deux benchmarks :
    llvm-profdata merge -output=libart.profdata \
        dex2oat_libart.profdata art_runtime_libart.profdata

    Les décomptes bruts pour libart.so des deux profils peuvent être disparates car les tests diffèrent par le nombre de cas de test et la durée pendant laquelle ils s'exécutent. 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 de dex2oat . Le poids réel doit être déterminé en fonction des connaissances du domaine ou de l'expérimentation.

  8. Vérifiez les fichiers de profil dex2oat.profdata et libart.profdata dans toolchain/pgo-profiles pour les utiliser pendant la construction.