Das Android-Build-System für Android 13 und niedriger unterstützt die Verwendung der profilgesteuerten Optimierung (PGO) von Clang auf nativen Android-Modulen, die über Blueprint- Build-Regeln verfügen. Auf dieser Seite wird Clang PGO beschrieben, wie für PGO verwendete Profile kontinuierlich generiert und aktualisiert werden und wie PGO in das Build-System integriert wird (mit Anwendungsfall).
Hinweis: Dieses Dokument beschreibt die Verwendung von PGO in der Android-Plattform. Um mehr über die Verwendung von PGO über eine Android-App zu erfahren, besuchen Sie diese Seite .
Über Clang PGO
Clang kann eine profilgesteuerte Optimierung mithilfe von zwei Profiltypen durchführen:
- Instrumentierungsbasierte Profile werden aus einem instrumentierten Zielprogramm generiert. Diese Profile sind detailliert und verursachen einen hohen Laufzeitaufwand.
- Sampling-basierte Profile werden typischerweise durch Sampling-Hardwarezähler erstellt. Sie verursachen einen geringen Laufzeitaufwand und können ohne Instrumentierung oder Änderung der Binärdatei erfasst werden. Sie sind weniger detailliert als instrumentierungsbasierte Profile.
Alle Profile sollten aus einer repräsentativen Arbeitslast generiert werden, die das typische Verhalten der App ausübt. Während Clang sowohl AST-basiert ( -fprofile-instr-generate
) als auch LLVM IR-basiert ( -fprofile-generate)
unterstützt, unterstützt Android für instrumentierungsbasiertes PGO nur LLVM IR-basiert.
Zum Erstellen der Profilsammlung sind die folgenden Flags erforderlich:
-
-fprofile-generate
für IR-basierte Instrumentierung. Mit dieser Option verwendet das Backend einen gewichteten Minimal-Spanning-Tree-Ansatz, um die Anzahl der Instrumentierungspunkte zu reduzieren und ihre Platzierung an Kanten mit geringem Gewicht zu optimieren (verwenden Sie diese Option auch für den Link-Schritt). Der Clang-Treiber übergibt die Profiling-Laufzeit (libclang_rt.profile- arch -android.a
) automatisch an den Linker. Diese Bibliothek enthält Routinen zum Schreiben der Profile auf die Festplatte beim Beenden des Programms. -
-gline-tables-only
für die stichprobenbasierte Profilerfassung, um minimale Debug-Informationen zu generieren.
Ein Profil kann für PGO mit -fprofile-use= pathname
oder -fprofile-sample-use= pathname
für instrumentierungsbasierte bzw. stichprobenbasierte Profile verwendet werden.
Hinweis: Wenn Änderungen am Code vorgenommen werden und Clang die Profildaten nicht mehr verwenden kann, wird eine Warnung -Wprofile-instr-out-of-date
generiert.
Verwenden Sie PGO
Die Verwendung von PGO umfasst die folgenden Schritte:
- Erstellen Sie die Bibliothek/ausführbare Datei mit Instrumentierung, indem Sie
-fprofile-generate
an den Compiler und Linker übergeben. - Sammeln Sie Profile, indem Sie eine repräsentative Arbeitslast auf der instrumentierten Binärdatei ausführen.
- Bearbeiten Sie die Profile mit dem Dienstprogramm
llvm-profdata
nach (Einzelheiten finden Sie unter Umgang mit LLVM-Profildateien ). - Verwenden Sie die Profile, um PGO anzuwenden, indem Sie
-fprofile-use=<>.profdata
an den Compiler und Linker übergeben.
Für PGO in Android sollten Profile offline gesammelt und zusammen mit dem Code eingecheckt werden, um reproduzierbare Builds sicherzustellen. Die Profile können im Zuge der Weiterentwicklung des Codes verwendet werden, müssen jedoch regelmäßig neu generiert werden (oder immer dann, wenn Clang warnt, dass die Profile veraltet sind).
Sammeln Sie Profile
Clang kann Profile verwenden, die durch das Ausführen von Benchmarks mithilfe eines instrumentierten Builds der Bibliothek oder durch das Abtasten von Hardware-Zählern beim Ausführen des Benchmarks gesammelt wurden. Derzeit unterstützt Android die Verwendung einer auf Stichproben basierenden Profilsammlung nicht. Daher müssen Sie Profile mithilfe eines instrumentierten Builds sammeln:
- Identifizieren Sie einen Benchmark und die Menge der Bibliotheken, die gemeinsam von diesem Benchmark genutzt werden.
- Fügen Sie
pgo
Eigenschaften zum Benchmark und zu den Bibliotheken hinzu (Details unten). - Erstellen Sie einen Android-Build mit einer instrumentierten Kopie dieser Bibliotheken mit:
make ANDROID_PGO_INSTRUMENT=benchmark
benchmark
ist ein Platzhalter, der die Sammlung von Bibliotheken identifiziert, die während des Builds instrumentiert werden. Die tatsächlichen repräsentativen Eingaben (und möglicherweise eine andere ausführbare Datei, die mit einer Bibliothek verknüpft ist, die einem Benchmarking unterzogen wird) sind nicht spezifisch für PGO und liegen außerhalb des Rahmens dieses Dokuments.
- Flashen oder synchronisieren Sie den instrumentierten Build auf einem Gerät.
- Führen Sie den Benchmark aus, um Profile zu sammeln.
- Verwenden Sie das Tool
llvm-profdata
(siehe unten), um die Profile nachzubearbeiten und sie für das Einchecken in den Quellbaum vorzubereiten.
Verwenden Sie Profile während des Builds
Checken Sie die Profile in toolchain/pgo-profiles
in einem Android-Baum ein. Der Name sollte mit dem übereinstimmen, der in der Untereigenschaft profile_file
der Eigenschaft pgo
für die Bibliothek angegeben ist. Das Build-System übergibt die Profildatei beim Erstellen der Bibliothek automatisch an Clang. Die Umgebungsvariable ANDROID_PGO_DISABLE_PROFILE_USE
kann auf true
gesetzt werden, um PGO vorübergehend zu deaktivieren und seinen Leistungsvorteil zu messen.
Um zusätzliche produktspezifische Profilverzeichnisse anzugeben, hängen Sie diese an die Make-Variable PGO_ADDITIONAL_PROFILE_DIRECTORIES
in einer BoardConfig.mk
an. Wenn zusätzliche Pfade angegeben werden, überschreiben die Profile in diesen Pfaden diejenigen in toolchain/pgo-profiles
.
Beim Generieren eines Release-Images mit dem Ziel dist
to make
schreibt das Build-System die Namen fehlender Profildateien in $DIST_DIR/pgo_profile_file_missing.txt
. Sie können diese Datei überprüfen, um zu sehen, welche Profildateien versehentlich gelöscht wurden (wodurch PGO stillschweigend deaktiviert wird).
Aktivieren Sie PGO in Android.bp-Dateien
Um PGO in Android.bp
-Dateien für native Module zu aktivieren, geben Sie einfach die pgo
Eigenschaft an. Diese Eigenschaft verfügt über die folgenden Untereigenschaften:
Eigentum | Beschreibung |
---|---|
instrumentation | Wird für PGO mit Instrumentierung auf true gesetzt. Der Standardwert ist false . |
sampling | Für PGO mit Sampling auf true setzen. Der Standardwert ist false . |
benchmarks | Liste der Zeichenfolgen. Dieses Modul wird für die Profilerstellung erstellt, wenn in der Build-Option ANDROID_PGO_INSTRUMENT ein Benchmark in der Liste angegeben ist. |
profile_file | Profildatei (relativ zu toolchain/pgo-profile ) zur Verwendung mit PGO. Der Build warnt, dass diese Datei nicht existiert, indem er diese Datei zu $DIST_DIR/pgo_profile_file_missing.txt hinzufügt , es sei denn, die Eigenschaft enable_profile_use ist auf false gesetzt ODER die Build-Variable ANDROID_PGO_NO_PROFILE_USE ist auf „ true gesetzt. |
enable_profile_use | Auf false setzen, wenn Profile während des Builds nicht verwendet werden sollen. Kann während des Bootstrap verwendet werden, um die Profilerfassung zu aktivieren oder PGO vorübergehend zu deaktivieren. Der Standardwert ist true . |
cflags | Liste zusätzlicher Flags, die während eines instrumentierten Builds verwendet werden sollen. |
Beispiel eines Moduls mit 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", } }
Wenn die Benchmarks benchmark1
und benchmark2
repräsentatives Verhalten für die Bibliotheken libstatic1
, libstatic2
oder libshared1
ausüben, kann die pgo
Eigenschaft dieser Bibliotheken auch die Benchmarks enthalten. Das defaults
in Android.bp
kann eine gemeinsame pgo
Spezifikation für eine Reihe von Bibliotheken enthalten, um zu vermeiden, dass dieselben Build-Regeln für mehrere Module wiederholt werden.
Um verschiedene Profildateien auszuwählen oder PGO für eine Architektur selektiv zu deaktivieren, geben Sie die Eigenschaften profile_file
, enable_profile_use
und cflags
pro Architektur an. Beispiel (mit fettgedrucktem Architekturziel):
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", } } } }
Um Verweise auf die Profiling-Laufzeitbibliothek während der instrumentierungsbasierten Profilerstellung aufzulösen, übergeben Sie das Build-Flag -fprofile-generate
an den Linker. Mit PGO instrumentierte statische Bibliotheken, alle gemeinsam genutzten Bibliotheken und alle Binärdateien, die direkt von der statischen Bibliothek abhängig sind, müssen ebenfalls für PGO instrumentiert werden. Allerdings müssen solche gemeinsam genutzten Bibliotheken oder ausführbaren Dateien keine PGO-Profile verwenden und ihre Eigenschaft enable_profile_use
kann auf false
gesetzt werden. Außerhalb dieser Einschränkung können Sie PGO auf jede statische Bibliothek, gemeinsam genutzte Bibliothek oder ausführbare Datei anwenden.
Behandeln Sie LLVM-Profildateien
Das Ausführen einer instrumentierten Bibliothek oder ausführbaren Datei erzeugt eine Profildatei mit dem Namen default_ unique_id _0.profraw
in /data/local/tmp
(wobei unique_id
ein numerischer Hash ist, der für diese Bibliothek eindeutig ist). Wenn diese Datei bereits vorhanden ist, führt die Profilerstellungslaufzeit beim Schreiben der Profile das neue Profil mit dem alten zusammen. Beachten Sie, dass /data/local/tmp
für App-Entwickler nicht zugänglich ist. Sie sollten stattdessen etwas wie /storage/emulated/0/Android/data/ packagename /files
verwenden. Um den Speicherort der Profildatei zu ändern, legen Sie zur Laufzeit die Umgebungsvariable LLVM_PROFILE_FILE
fest.
Das Dienstprogramm llvm-profdata
wird dann verwendet, um die .profraw
Datei (und möglicherweise mehrere .profraw
Dateien zusammenzuführen) in eine .profdata
Datei zu konvertieren:
llvm-profdata merge -output=profile.profdata <.profraw and/or .profdata files>
profile.profdata
kann dann zur Verwendung während des Builds in den Quellbaum eingecheckt werden.
Wenn während eines Benchmarks mehrere instrumentierte Binärdateien/Bibliotheken geladen werden, generiert jede Bibliothek eine separate .profraw
-Datei mit einer separaten eindeutigen ID. Normalerweise können alle diese Dateien zu einer einzigen .profdata
Datei zusammengeführt und für die PGO-Erstellung verwendet werden. In Fällen, in denen eine Bibliothek von einem anderen Benchmark beansprucht wird, muss diese Bibliothek mithilfe von Profilen aus beiden Benchmarks optimiert werden. In dieser Situation ist die show
Option von llvm-profdata
nützlich:
llvm-profdata merge -output=default_unique_id.profdata default_unique_id_0.profraw llvm-profdata show -all-functions default_unique_id.profdata
Um unique_id s einzelnen Bibliotheken zuzuordnen, durchsuchen Sie die show
Ausgabe für jede unique_id nach einem Funktionsnamen, der für die Bibliothek eindeutig ist.
Fallstudie: PGO für ART
Die Fallstudie präsentiert ART als ein nachvollziehbares Beispiel; Es handelt sich jedoch nicht um eine genaue Beschreibung der tatsächlichen Gruppe von Bibliotheken, die für ART profiliert wurden, oder ihrer gegenseitigen Abhängigkeiten.
Der dex2oat
Ahead-of-Time-Compiler in ART hängt von libart-compiler.so
ab, das wiederum von libart.so
abhängt. Die ART-Laufzeit ist hauptsächlich in libart.so
implementiert. Die Benchmarks für den Compiler und die Laufzeit unterscheiden sich:
Benchmark | Profilierte Bibliotheken |
---|---|
dex2oat | dex2oat (ausführbare Datei), libart-compiler.so , libart.so |
art_runtime | libart.so |
- Fügen Sie die folgende
pgo
Eigenschaft zudex2oat
,libart-compiler.so
hinzu:pgo: { instrumentation: true, benchmarks: ["dex2oat",], profile_file: "dex2oat.profdata", }
- Fügen Sie
libart.so
die folgendepgo
Eigenschaft hinzu:pgo: { instrumentation: true, benchmarks: ["art_runtime", "dex2oat",], profile_file: "libart.profdata", }
- Erstellen Sie instrumentierte Builds für die Benchmarks
dex2oat
undart_runtime
mit:make ANDROID_PGO_INSTRUMENT=dex2oat make ANDROID_PGO_INSTRUMENT=art_runtime
- Führen Sie die Benchmarks mit
dex2oat
undart_runtime
aus, um Folgendes zu erhalten:- Drei
.profraw
Dateien vondex2oat
(dex2oat_exe.profdata
,dex2oat_libart-compiler.profdata
unddexeoat_libart.profdata
), identifiziert mit der unter Umgang mit LLVM-Profildateien beschriebenen Methode. - Eine einzelne
art_runtime_libart.profdata
.
- Drei
- Erstellen Sie eine gemeinsame Profdata-Datei für die ausführbare Datei
dex2oat
undlibart-compiler.so
mit:llvm-profdata merge -output=dex2oat.profdata \ dex2oat_exe.profdata dex2oat_libart-compiler.profdata
- Erhalten Sie das Profil für
libart.so
indem Sie die Profile der beiden Benchmarks zusammenführen:llvm-profdata merge -output=libart.profdata \ dex2oat_libart.profdata art_runtime_libart.profdata
Die Rohzahlen für
libart.so
aus den beiden Profilen können unterschiedlich sein, da sich die Benchmarks in der Anzahl der Testfälle und der Dauer ihrer Ausführung unterscheiden. In diesem Fall können Sie eine gewichtete Zusammenführung verwenden:llvm-profdata merge -output=libart.profdata \ -weighted-input=2,dex2oat_libart.profdata \ -weighted-input=1,art_runtime_libart.profdata
Der obige Befehl weist dem Profil von
dex2oat
die doppelte Gewichtung zu. Das tatsächliche Gewicht sollte auf der Grundlage von Domänenkenntnissen oder Experimenten ermittelt werden. - Überprüfen Sie die Profildateien
dex2oat.profdata
undlibart.profdata
intoolchain/pgo-profiles
zur Verwendung während des Builds.
Alternativ können Sie einen einzigen instrumentierten Build erstellen, bei dem alle Bibliotheken instrumentiert sind, indem Sie Folgendes verwenden:
make ANDROID_PGO_INSTRUMENT=dex2oat,art_runtime (or) make ANDROID_PGO_INSTRUMENT=ALL
Der zweite Befehl erstellt alle PGO-fähigen Module für die Profilerstellung.