Nutzen Sie die profilgesteuerte Optimierung

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:

  1. Erstellen Sie die Bibliothek/ausführbare Datei mit Instrumentierung, indem Sie -fprofile-generate an den Compiler und Linker übergeben.
  2. Sammeln Sie Profile, indem Sie eine repräsentative Arbeitslast auf der instrumentierten Binärdatei ausführen.
  3. Bearbeiten Sie die Profile mit dem Dienstprogramm llvm-profdata nach (Einzelheiten finden Sie unter Umgang mit LLVM-Profildateien ).
  4. 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:

  1. Identifizieren Sie einen Benchmark und die Menge der Bibliotheken, die gemeinsam von diesem Benchmark genutzt werden.
  2. Fügen Sie pgo Eigenschaften zum Benchmark und zu den Bibliotheken hinzu (Details unten).
  3. 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.

  1. Flashen oder synchronisieren Sie den instrumentierten Build auf einem Gerät.
  2. Führen Sie den Benchmark aus, um Profile zu sammeln.
  3. 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
  1. Fügen Sie die folgende pgo Eigenschaft zu dex2oat , libart-compiler.so hinzu:
        pgo: {
            instrumentation: true,
            benchmarks: ["dex2oat",],
            profile_file: "dex2oat.profdata",
        }
  2. Fügen Sie libart.so die folgende pgo Eigenschaft hinzu:
        pgo: {
            instrumentation: true,
            benchmarks: ["art_runtime", "dex2oat",],
            profile_file: "libart.profdata",
        }
  3. Erstellen Sie instrumentierte Builds für die Benchmarks dex2oat und art_runtime mit:
        make ANDROID_PGO_INSTRUMENT=dex2oat
        make ANDROID_PGO_INSTRUMENT=art_runtime
  4. 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.

  5. Führen Sie die Benchmarks mit dex2oat und art_runtime aus, um Folgendes zu erhalten:
    • Drei .profraw Dateien von dex2oat ( dex2oat_exe.profdata , dex2oat_libart-compiler.profdata und dexeoat_libart.profdata ), identifiziert mit der unter Umgang mit LLVM-Profildateien beschriebenen Methode.
    • Eine einzelne art_runtime_libart.profdata .
  6. Erstellen Sie eine gemeinsame Profdata-Datei für die ausführbare Datei dex2oat und libart-compiler.so mit:
    llvm-profdata merge -output=dex2oat.profdata \
        dex2oat_exe.profdata dex2oat_libart-compiler.profdata
  7. 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.

  8. Überprüfen Sie die Profildateien dex2oat.profdata und libart.profdata in toolchain/pgo-profiles zur Verwendung während des Builds.