Das Android-Buildsystem für Android 13 und niedriger unterstützt die Verwendung der profilbasierten Optimierung (PGO) von Clang in nativen Android-Modulen mit Blueprint-Buildregeln. Auf dieser Seite wird Clang PGO beschrieben, wie Sie Profile für PGO kontinuierlich generieren und aktualisieren und wie Sie PGO in das Build-System einbinden (mit Anwendungsfall).
Hinweis: In diesem Dokument wird die Verwendung von PGO auf der Android-Plattform beschrieben. Auf dieser Seite finden Sie Informationen zur Verwendung von PGO in einer Android-App.
Clang PGO
Clang kann eine profilbasierte Optimierung mit zwei Arten von Profilen ausführen:
- Instrumentierungsbasierte Profile werden aus einem instrumentierten Zielprogramm generiert. Diese Profile sind detailliert und verursachen einen hohen Laufzeitoverhead.
- Sampling-basierte Profile werden in der Regel durch Hardwarezähler erstellt. Sie verursachen einen geringen Laufzeitoverhead und können ohne Instrumentierung oder Modifikation des Binärcodes 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. Clang unterstützt sowohl AST-basiert (-fprofile-instr-generate) als auch LLVM-IR-basiert (-fprofile-generate)). Android unterstützt für die instrumentierungsbasierte PGO jedoch nur LLVM-IR-basiert.
Für die Profilerhebung sind die folgenden Flags erforderlich:
-fprofile-generatefür IR-basierte Instrumente. Bei dieser Option verwendet das Backend einen gewichteten minimalen Spannbaum, um die Anzahl der Instrumentierungsstellen zu reduzieren und ihre Platzierung auf Kanten mit geringem Gewicht zu optimieren. Verwenden Sie diese Option auch für den Verknüpfungsschritt. 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-onlyfür die stichprobenbasierte Profilerhebung, um nur minimale Informationen zur Fehlerbehebung zu generieren.
Ein Profil kann für die automatische Optimierung mit -fprofile-use=pathname oder -fprofile-sample-use=pathname für instrumentierungsbasierte bzw. stichprobenbasierte Profile verwendet werden.
Hinweis:Wenn Clang die Profildaten nach Änderungen am Code nicht mehr verwenden kann, wird eine -Wprofile-instr-out-of-date-Warnung generiert.
PGO verwenden
So verwenden Sie PGO:
- Erstellen Sie die Bibliothek/Ausführbare Datei mit Instrumentierung, indem Sie
-fprofile-generatean den Compiler und Linker übergeben. - Erfassen Sie Profile, indem Sie eine repräsentative Arbeitslast auf der instrumentierten Binärdatei ausführen.
- Bearbeiten Sie die Profile mit dem Dienstprogramm
llvm-profdata. Weitere Informationen finden Sie unter LLVM-Profildateien verarbeiten. - Verwenden Sie die Profile, um PGO anzuwenden, indem Sie
-fprofile-use=<>.profdataan den Compiler und den Linker übergeben.
Für PGO auf Android-Geräten sollten Profile offline erfasst und zusammen mit dem Code eingecheckt werden, um reproduzierbare Builds zu ermöglichen. Die Profile können verwendet werden, während der Code weiterentwickelt wird, müssen aber regelmäßig neu generiert werden (oder immer dann, wenn Clang warnt, dass die Profile veraltet sind).
Profile erfassen
Clang kann Profile verwenden, die durch Ausführen von Benchmarks mit einem instrumentierten Build der Bibliothek oder durch Stichprobenerhebung von Hardwarezählern beim Ausführen des Benchmarks erfasst wurden. Derzeit unterstützt Android keine Stichprobenerhebung von Profilen. Sie müssen Profile daher mit einem instrumentierten Build erfassen:
- Identifizieren Sie einen Benchmark und die Bibliotheken, die von diesem Benchmark gemeinsam genutzt werden.
- Fügen Sie dem Benchmark und den Bibliotheken
pgo-Properties hinzu (Details siehe 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 angibt, die während des Builds instrumentiert wurden. 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 fallen nicht in den Geltungsbereich dieses Dokuments.
- Flashen oder synchronisieren Sie den instrumentierten Build auf einem Gerät.
- Führen Sie den Benchmark aus, um Profile zu erfassen.
- Verwenden Sie das Tool
llvm-profdata(siehe unten), um die Profile nachzubearbeiten und für das Einchecken in den Quellbaum vorzubereiten.
Profile während des Builds verwenden
Überprüfen Sie die Profile in toolchain/pgo-profiles in einem Android-Baum. Der Name muss mit dem in der untergeordneten Property profile_file der Property pgo für die Bibliothek angegebenen Namen übereinstimmen. Das Build-System übergibt die Profildatei beim Erstellen der Bibliothek automatisch an Clang. Sie können die Umgebungsvariable ANDROID_PGO_DISABLE_PROFILE_USE auf true setzen, um PGO vorübergehend zu deaktivieren und den Leistungsvorteil zu messen.
Wenn Sie zusätzliche produktspezifische Profilverzeichnisse angeben möchten, hängen Sie sie an die PGO_ADDITIONAL_PROFILE_DIRECTORIES-Variable in einer BoardConfig.mk an. Wenn zusätzliche Pfade angegeben werden, werden die Profile in diesen Pfaden über die in toolchain/pgo-profiles hinweggeschrieben.
Wenn Sie ein Release-Image mit dem Ziel dist für make generieren, schreibt das Build-System die Namen der fehlenden Profildateien in $DIST_DIR/pgo_profile_file_missing.txt. In dieser Datei können Sie sehen, welche Profildateien versehentlich gelöscht wurden, wodurch PGO stillschweigend deaktiviert wird.
PGO in Android.bp-Dateien aktivieren
Wenn Sie PGO in Android.bp-Dateien für native Module aktivieren möchten, geben Sie einfach das Attribut pgo an. Diese Property hat die folgenden Untereigenschaften:
| Property | Beschreibung |
|---|---|
instrumentation
|
Legen Sie true für PGO mit Instrumentierung fest. Der Standardwert ist false. |
sampling
|
Legen Sie true für PGO mit Stichprobenerhebung fest. Der Standardwert ist false. |
benchmarks
|
Liste mit Strings. Dieses Modul wird für das Profiling verwendet, wenn in der Option ANDROID_PGO_INSTRUMENT build ein Benchmark in der Liste angegeben ist. |
profile_file
|
Profildatei (relativ zu toolchain/pgo-profile), die mit PGO verwendet werden soll. Im Build wird eine Warnung ausgegeben, dass diese Datei nicht existiert, indem sie $DIST_DIR/pgo_profile_file_missing.txt hinzugefügt wird, es sei denn, die Eigenschaft enable_profile_use ist auf false gesetzt ODER die Buildvariable ANDROID_PGO_NO_PROFILE_USE auf true. |
enable_profile_use
|
Legen Sie false fest, wenn Profile beim Build nicht verwendet werden sollen. Kann während des Bootstrappings verwendet werden, um die Profilerhebung zu aktivieren oder PGO vorübergehend zu deaktivieren. Der Standardwert ist true. |
cflags
|
Liste der zusätzlichen Flags, die bei einem instrumentierten Build verwendet werden sollen. |
Beispiel für ein Modul 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 ein repräsentatives Verhalten für die Bibliotheken libstatic1, libstatic2 oder libshared1 zeigen, kann die Eigenschaft pgo dieser Bibliotheken auch die Benchmarks enthalten. Das defaults-Modul 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.
Wenn Sie verschiedene Profildateien auswählen oder PGO für eine Architektur selektiv deaktivieren möchten, geben Sie die Eigenschaften profile_file, enable_profile_use und cflags pro Architektur an. Beispiel (mit fett formatiertem 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", } } } }
Wenn Sie Verweise auf die Laufzeitbibliothek für das Profiling während des instrumentierungsbasierten Profilings auflösen möchten, übergeben Sie dem Linker das Build-Flag -fprofile-generate. Statische Bibliotheken, die mit PGO instrumentiert sind, alle gemeinsam genutzten Bibliotheken und alle Binärdateien, die direkt von der statischen Bibliothek abhängen, müssen ebenfalls für PGO instrumentiert werden. Für solche freigegebenen Bibliotheken oder ausführbaren Dateien müssen jedoch keine PGO-Profile verwendet werden und die enable_profile_use-Eigenschaft kann auf false gesetzt werden.
Abgesehen von dieser Einschränkung können Sie PGO auf jede statische Bibliothek, jede freigegebene Bibliothek oder jede ausführbare Datei anwenden.
LLVM-Profildateien verarbeiten
Wenn Sie eine instrumentierte Bibliothek oder ausführbare Datei ausführen, wird eine Profildatei mit dem Namen default_unique_id_0.profraw in /data/local/tmp erstellt. Dabei ist unique_id ein numerischer Hashwert, der für diese Bibliothek eindeutig ist. Wenn diese Datei bereits vorhanden ist, wird das neue Profil beim Schreiben der Profile von der Laufzeit für das Profiling mit dem alten Profil zusammengeführt. Hinweis: /data/local/tmp ist für App-Entwickler nicht zugänglich. Sie sollten stattdessen eine Adresse wie /storage/emulated/0/Android/data/packagename/files verwenden.
Wenn Sie den Speicherort der Profildatei ändern möchten, legen Sie die Umgebungsvariable LLVM_PROFILE_FILE zur Laufzeit fest.
Mit dem Dienstprogramm llvm-profdata wird dann die .profraw-Datei konvertiert (und gegebenenfalls mehrere .profraw-Dateien zusammengeführt) in eine .profdata-Datei:
llvm-profdata merge -output=profile.profdata <.profraw and/or .profdata files>
profile.profdata kann dann in den Quellbaum für die Verwendung während des Builds 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 in eine einzige .profdata-Datei zusammengeführt und für den PGO-Build verwendet werden. Wenn eine Bibliothek von einem anderen Benchmark genutzt wird, muss sie mithilfe von Profilen aus beiden Benchmarks optimiert werden. In diesem Fall ist die Option show 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
Wenn Sie unique_ids einzelnen Bibliotheken zuordnen möchten, suchen Sie in der show-Ausgabe für jede unique_id nach einem Funktionsnamen, der für die Bibliothek eindeutig ist.
Fallstudie: PGO für ART
In der Fallstudie wird ART als nachvollziehbares Beispiel vorgestellt. Es ist jedoch keine genaue Beschreibung der tatsächlichen Bibliotheken, die für ART profiliert wurden, oder ihrer Abhängigkeiten.
Der dex2oat-Compiler in ART hängt von libart-compiler.so ab, der wiederum von libart.so abhängt. Die ART-Laufzeit wird hauptsächlich in libart.so implementiert. Die Benchmarks für den Compiler und die Laufzeit unterscheiden sich:
| Benchmark | Profilierte Bibliotheken |
|---|---|
dex2oat
|
dex2oat (ausführbar), libart-compiler.so,
libart.so |
art_runtime
|
libart.so
|
- Fügen Sie
dex2oat,libart-compiler.sodie folgendepgo-Property hinzu:pgo: { instrumentation: true, benchmarks: ["dex2oat",], profile_file: "dex2oat.profdata", } - Fügen Sie
libart.sodie folgendepgo-Eigenschaft hinzu:pgo: { instrumentation: true, benchmarks: ["art_runtime", "dex2oat",], profile_file: "libart.profdata", } - Erstellen Sie instrumentierte Builds für die
dex2oat- undart_runtime-Benchmarks mit:make ANDROID_PGO_INSTRUMENT=dex2oat make ANDROID_PGO_INSTRUMENT=art_runtime - Führen Sie die Benchmarks mit
dex2oatundart_runtimeaus, um Folgendes zu erhalten:- Drei
.profraw-Dateien vondex2oat(dex2oat_exe.profdata,dex2oat_libart-compiler.profdataunddexeoat_libart.profdata), die mit der unter LLVM-Profildateien verarbeiten beschriebenen Methode ermittelt wurden. - Eine einzelne
art_runtime_libart.profdata.
- Drei
- Erstellen Sie eine gemeinsame profdata-Datei für die ausführbare Datei
dex2oatundlibart-compiler.somit:llvm-profdata merge -output=dex2oat.profdata \ dex2oat_exe.profdata dex2oat_libart-compiler.profdata - Erstellen Sie das Profil für
libart.so, indem Sie die Profile aus den beiden Benchmarks zusammenführen:llvm-profdata merge -output=libart.profdata \ dex2oat_libart.profdata art_runtime_libart.profdataDie Rohzahlen für
libart.soaus den beiden Profilen können unterschiedlich sein, da sich die Benchmarks in der Anzahl der Testfälle und der Dauer unterscheiden, für die sie ausgeführt werden. 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.profdataMit dem obigen Befehl wird dem Profil von
dex2oatdas doppelte Gewicht zugewiesen. Das tatsächliche Gewicht sollte auf der Grundlage von Fachwissen oder Tests ermittelt werden. - Prüfen Sie die Profildateien
dex2oat.profdataundlibart.profdataintoolchain/pgo-profilesfür die Verwendung während des Builds.
Alternativ können Sie einen einzelnen instrumentierten Build mit allen Bibliotheken erstellen, die mithilfe der folgenden Tools instrumentiert wurden:
make ANDROID_PGO_INSTRUMENT=dex2oat,art_runtime
(or)
make ANDROID_PGO_INSTRUMENT=ALLMit dem zweiten Befehl werden alle PGO-fähigen Module für das Profiling erstellt.