Profilgestützte Optimierung ist eine bekannte Compiler-Optimierung, . In PGO werden Laufzeitprofile aus den Ausführungen eines Programms vom um optimale Entscheidungen über Inlining und Code-Layout zu treffen. Dies führt zu verbesserte Leistung und reduzierte Codegröße.
PGO kann mit den folgenden Schritten in Ihrer Anwendung oder Bibliothek bereitgestellt werden: 1. Identifizieren Sie eine repräsentative Arbeitslast. 2. Profile erfassen. 3. Profile in einem Release-Build verwenden
Schritt 1: Repräsentative Arbeitslast identifizieren
Bestimmen Sie zuerst eine repräsentative Benchmark oder Arbeitslast für Ihre Anwendung. Dies ist ein wichtiger Schritt, da die aus der Arbeitslast erfassten Profile die heißen und kalten Regionen im Code enthalten. Bei Verwendung der Profile führt der Compiler aggressive Optimierungen durchzuführen und sich in besonders beliebten Regionen zu positionieren. Der Compiler kann sich auch dafür entscheiden, die Codegröße von selten genutzten Regionen zu reduzieren, die Leistung.
Das Identifizieren einer guten Arbeitslast ist auch hilfreich, um die Leistung in allgemein.
Schritt 2: Profile erfassen
Die Profilerfassung umfasst drei Schritte: – nativen Code mit Instrumentierung erstellen, – die instrumentierte App auf dem Gerät ausführen und Profile generieren – Zusammenführen/Nachverarbeiten der Profile auf dem Host
Instrumentierten Build erstellen
Die Profile werden erfasst, indem die Arbeitslast aus Schritt 1 auf einem
den instrumentierten Build der Anwendung. Um einen instrumentierten Build zu generieren, fügen Sie
-fprofile-generate
zu den Compiler- und Verknüpfungs-Flags. Dieses Flag sollte
gesteuert wird, da das Flag während einer
Standard-Build
Profile erstellen
Führen Sie als Nächstes die instrumentierte App auf dem Gerät aus und generieren Sie Profile.
Profile werden im Arbeitsspeicher erfasst, wenn die instrumentierte Binärdatei ausgeführt wird und
beim Beenden in eine Datei geschrieben. Mit atexit
registrierte Funktionen sind jedoch nicht
in einer Android-App aufgerufen wird – die App bricht ab.
Die Anwendung/Arbeitslast muss zusätzliche Arbeit leisten, um einen Pfad für die Profildatei festzulegen. und dann explizit einen Profilschreibvorgang auslösen.
- Um den Pfad der Profildatei festzulegen, rufen Sie
__llvm_profile_set_filename(PROFILE_DIR "/default-%m.profraw
%m
ist hilfreich wenn es mehrere gemeinsam genutzte Bibliotheken gibt. %m` wird zu einem eindeutigen Modul erweitert. Signatur für diese Bibliothek, was zu einem separaten Profil pro Bibliothek führt. Weitere Informationen finden Sie unter hier für weitere nützliche Musterspezifizierer. PROFILE_DIR ist ein Verzeichnis, die über die App geschrieben werden können. Demo ansehen zur Ermittlung dieses Verzeichnisses während der Laufzeit. - Rufen Sie zum expliziten Auslösen eines Profilschreibvorgangs die Methode
__llvm_profile_write_file
auf. .
extern "C" {
extern int __llvm_profile_set_filename(const char*);
extern int __llvm_profile_write_file(void);
}
#define PROFILE_DIR "<location-writable-from-app>"
void workload() {
// ...
// run workload
// ...
// set path and write profiles after workload execution
__llvm_profile_set_filename(PROFILE_DIR "/default-%m.profraw");
__llvm_profile_write_file();
return;
}
Hinweis: Das Generieren der Profildatei ist einfacher, wenn die Arbeitslast eine eigenständige Binärdatei ist:
legen Sie einfach die Umgebungsvariable LLVM_PROFILE_FILE
auf %t/default-%m.profraw
bevor die Binärdatei ausgeführt wird.
Nachbearbeitung von Profilen
Die Profildateien liegen im .profraw-Format vor. Sie müssen zuerst von
mit adb pull
auf das Gerät. Verwenden Sie nach dem Abruf das Dienstprogramm llvm-profdata
in
NDK zur Konvertierung von .profraw
in .profdata
, das dann an den
Compiler.
$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-profdata \
merge --output=pgo_profile.profdata \
<list-of-profraw-files>
llvm-profdata
und clang
aus demselben NDK-Release verwenden, um Version zu vermeiden
Die Formate der Profildatei stimmen nicht überein.
Schritt 3: Profile zum Erstellen der Anwendung verwenden
Verwenden Sie das Profil aus dem vorherigen Schritt während eines Release-Builds Ihres
-Anwendung hinzu, indem Sie -fprofile-use=<>.profdata
an den Compiler und den Linker übergeben. Die
Profile können auch dann verwendet werden, wenn sich der Code weiterentwickelt – der Clang-Compiler kann diese Funktion tolerieren.
Die Quelle stimmt mit den Profilen leicht nicht überein.
Hinweis: Bei den meisten Bibliotheken werden die Profile in der Regel in allen Architekturen verwendet. Beispielsweise können Profile, die aus dem Arm64-Build der Bibliothek generiert wurden, für alle Architekturen. Allerdings müssen architekturspezifische Codepfade in der Bibliothek (Verzweigung oder x86- oder 32-Bit- oder 64-Bit-Version), separate Profile die für jede Konfiguration verwendet werden sollen.
Zusammenfassung
https://github.com/DanAlbert/ndk-samples/tree/pgo/pgo zeigt eine End-to-End-Demo zur Verwendung von PGO über eine App. Sie bietet zusätzliche die in diesem Dokument bereits überflogen sind.
- Der CMake-Build Regeln wie Sie eine CMake-Variable einrichten, die nativen Code mit Instrumentierung erstellt. Ist keine Build-Variable festgelegt, wird nativer Code mithilfe der bisherigen von PGO-Profilen.
- Bei einem instrumentierten Build pgodemo.cpp schreibt die Profile die Ausführung von Arbeitslasten.
- Ein beschreibbarer Speicherort für die Profile wird zur Laufzeit abgerufen in
Hauptaktivität.kt
mit
applicationContext.cacheDir.toString()
. - Wenn du Profile vom Gerät abrufen möchtest, ohne dass
adb root
erforderlich ist, verwende dieadb
Rezept hier.