Dateien bestellen

Die Bestelldatei ist ein neues Verfahren zur Optimierung von Verknüpfungen. Diese Reihenfolgedateien sind Textdateien, die Symbole für Funktionen enthalten. Verknüpfungstools wie lld verwenden Bestelldateien, um Funktionen in einer bestimmten Reihenfolge anzuordnen. Diese Binärprogramme oder Bibliotheken mit geordneten Symbolen reduzieren Seitenfehler und verbessern die Startzeit eines Programms aufgrund des effizienten Ladens von Symbolen während des Kaltstarts eines Programms.

Zum Hinzufügen von Features für Bestelldateien können Sie Ihrer Anwendung in drei Schritten hinzufügen:

  1. Profile und Zuordnungsdatei generieren
  2. Bestelldatei aus der Profil- und Zuordnungsdatei erstellen
  3. Verwenden Sie die Bestelldatei während des Release-Builds, um das Layout der Symbole zu erstellen.

Bestelldatei generieren

Das Erstellen einer Bestelldatei erfordert drei Schritte:

  1. Instrumentierte Version der App erstellen, die die Bestelldatei schreibt
  2. App ausführen, um die Profile zu generieren
  3. Profile und Zuordnungsdatei nachbearbeiten

Instrumentierten Build erstellen

Die Profile werden durch Ausführen eines instrumentierten Builds der Anwendung generiert. Bei einem instrumentierten Build muss -forder-file-instrumentation sowohl dem Compiler- als auch dem Verknüpfungs-Flag hinzugefügt werden, wobei -mllvm -orderfile-write-mapping=<filename>-mapping.txt streng zu den Compiler-Flags hinzugefügt wird. Das Instrumentierungs-Flag aktiviert die Instrumentierung von Bestelldateien für die Profilerstellung und lädt die spezifische Bibliothek, die für die Profilerstellung benötigt wird. Das Zuordnungs-Flag gibt hingegen nur die Zuordnungsdatei aus, die den MD5-Hash für jede Funktion in der Binärdatei oder der Bibliothek anzeigt.

Außerdem müssen Sie alle Optimierungs-Flags außer -O0 übergeben, da sowohl das Instrumentierungs-Flag als auch das Zuordnungs-Flag eins erfordern. Wenn kein Optimierungs-Flag übergeben wird, wird die Zuordnungsdatei nicht generiert und der instrumentierte Build gibt möglicherweise falsche Hashes an die Profildatei aus.

NDK-Build

Achten Sie darauf, dass Sie mit APP_OPTIM=release erstellen, damit „ndk-build“ einen anderen Optimierungsmodus als -O0 verwendet. Bei der Entwicklung mit AGP ist dies bei Release-Builds automatisch.

LOCAL_CFLAGS += \
    -forder-file-instrumentation \
    -mllvm -orderfile-write-mapping=mapping.txt \

LOCAL_LDFLAGS += -forder-file-instrumentation

CMake

Verwenden Sie einen anderen CMAKE_BUILD_TYPE als Debug, damit CMake einen anderen Optimierungsmodus als -O0 verwendet. Wenn Sie mit AGP arbeiten, ist das bei Release-Builds automatisch.

target_compile_options(orderfiledemo PRIVATE
    -forder-file-instrumentation
    -mllvm -orderfile-write-mapping=mapping.txt
)
target_link_options(orderfiledemo PRIVATE -forder-file-instrumentation)

Andere Build-Systeme

Kompilieren Sie Ihren Code mit -forder-file-instrumentation -O1 -mllvm -orderfile-write-mapping=mapping.txt.

-O1 ist nicht erforderlich, du solltest aber -O0 nicht verwenden.

Lassen Sie -mllvm -orderfile-write-mapping=mapping.txt beim Verknüpfen weg.

Diese Flags werden für einen Release-Build nicht benötigt und sollten daher durch eine Build-Variable gesteuert werden. Der Einfachheit halber können Sie dies alles in der CMakeLists.txt-Datei einrichten, wie in unserem Beispiel.

Bestelldateibibliothek erstellen

Zusätzlich zu den Flags muss die Profildatei eingerichtet werden und das instrumentierte Binärprogramm muss während der Ausführung explizit einen Schreibvorgang für ein Profil auslösen.

  • Rufen Sie __llvm_profile_set_filename(PROFILE_DIR "/<filename>-%m.profraw") auf, um den Profilpfad einzurichten. Obwohl als Argument <filename>-%m.profraw übergeben wird, wird die Profildatei als <filename>-%m.profraw.order gespeichert. Achten Sie darauf, dass die Anwendung PROFILE_DIR beschreibbar ist und Sie Zugriff auf das Verzeichnis haben.
    • Da für viele gemeinsam genutzte Bibliotheken Profile erstellt werden, ist %m nützlich, da sie zu einer eindeutigen Modulsignatur für die Bibliothek erweitert wird. Dadurch entsteht pro Bibliothek ein separates Profil. Weitere Musterspezifizierer finden Sie unter diesem Link.
  • __llvm_profile_initialize_file() aufrufen, um die Profildatei einzurichten
  • __llvm_orderfile_dump() aufrufen, um explizit in die Profildatei zu schreiben

Die Profile werden im Arbeitsspeicher erfasst und von der Dump-Funktion in die Datei geschrieben. Die Dump-Funktion muss am Ende des Startvorgangs aufgerufen werden, damit Ihre Profildatei bis zum Ende des Starts alle Symbole enthält.

extern "C" {
extern int __llvm_profile_set_filename(const char*);
extern int __llvm_profile_initialize_file(void);
extern int __llvm_orderfile_dump(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_initialize_file();
  __llvm_orderfile_dump();
  return;
}

Build für Profile ausführen

Führen Sie die instrumentierte Anwendung entweder auf einem physischen oder virtuellen Gerät aus, um die Profile zu generieren. Sie können die Profildateien mit adb pull extrahieren.

adb shell "run-as <package-name> sh -c 'cat /data/user/0/<package-name>/cache/default-%m.profraw.order' | cat > /data/local/tmp/default-%m.profraw.order"
adb pull /data/local/tmp/default-%m.profraw.order .

Wie bereits erwähnt, müssen Sie auf den Ordner mit der geschriebenen Profildatei zugreifen können. Wenn es sich um ein virtuelles Gerät handelt, sollten Sie die Emulatoren mit dem Play Store vermeiden, da Sie keinen Zugriff auf viele Ordner haben.

Profil- und Zuordnungsdatei nachbearbeiten

Wenn Sie die Profile abrufen, müssen Sie die Zuordnungsdatei finden und jedes Profil in ein Hexadezimalformat konvertieren. In der Regel finden Sie die Zuordnungsdatei im Build-Ordner der Anwendung. Wenn Sie beides haben, können Sie mit unserem Skript eine Profildatei und die richtige Zuordnungsdatei zum Generieren einer Bestelldatei verwenden.

Linux/Mac/ChromeOS

hexdump -C default-%m.profraw.order > default-%m.prof
python3 create_orderfile.py --profile-file default-%m.prof --mapping-file <filename>-mapping.txt

Windows

certutil -f -encodeHex default-%m.profraw.order default-%m.prof
python3 create_orderfile.py --profile-file default-%m.prof --mapping-file <filename>-mapping.txt

Weitere Informationen zum Skript finden Sie in dieser Readme-Datei.

Bestellungsdatei zum Erstellen einer Anwendung verwenden

Nachdem Sie eine Bestellungsdatei generiert haben, sollten Sie die früheren Flags und die Funktionen für die Reihenfolgesdatei entfernen, da diese nur für Generierungsschritte gedacht sind. Sie müssen nur -Wl,--symbol-ordering-file=<filename>.orderfile an die Kompilierungs- und Verknüpfungs-Flags übergeben. Manchmal werden Symbole nicht gefunden oder können nicht verschoben werden. Daher werden Warnungen ausgegeben, sodass Sie -Wl,--no-warn-symbol-ordering übergeben können, um diese Warnungen zu unterdrücken.

NDK-Build

LOCAL_CFLAGS += \
    -Wl,--symbol-ordering-file=<filename>.orderfile \
    -Wl,--no-warn-symbol-ordering \

LOCAL_LDFLAGS += \
    -Wl,--symbol-ordering-file=<filename>.orderfile \
    -Wl,--no-warn-symbol-ordering \

CMake

target_compile_options(orderfiledemo PRIVATE
    -Wl,--symbol-ordering-file=<filename>.orderfile
    -Wl,--no-warn-symbol-ordering
)
target_link_options(orderfiledemo PRIVATE
    -Wl,--symbol-ordering-file=<filename>.orderfile
    -Wl,--no-warn-symbol-ordering
)

Andere Build-Systeme

Kompilieren Sie Ihren Code mit -Wl,--symbol-ordering-file=<filename>.orderfile -Wl,--no-warn-symbol-ordering.

Weitere Informationen finden Sie im Beispiel für eine Bestelldatei.

Details zur Implementierung der Bestelldatei

Es gibt viele Möglichkeiten, Auftragsdateien zu generieren und für die Erstellung zu verwenden. Das NDK verwendet die LLVM-Methode, sodass sie für Ihre freigegebenen C- oder C++-Bibliotheken im Vergleich zur tatsächlichen Java- oder Kotlin-App am nützlichsten ist. Clang verwendet jeden Funktionsnamen (Symbol) und erstellt einen MD5-Hash davon und gibt diese Beziehung zu einer Zuordnungsdatei aus. Der MD5-Hash einer Funktion wird bei der ersten Ausführung der Funktion in die Profildatei (Profraw-Format) geschrieben. Bei nachfolgenden Ausführungen der Funktion wird der MD5-Hash nicht in die Profildatei geschrieben, um Duplikate zu vermeiden. Daher wird nur die erste Ausführung der Funktion in der Reihenfolge aufgezeichnet. Sie können die Profil- und Zuordnungsdatei durchgehen, um jeden MD5-Hash durch die entsprechende Funktion zu ersetzen und eine Bestelldatei zu erhalten.

Beispiele für eine Profildatei im Hexadezimalformat und eine Zuordnungsdatei finden Sie als example.prof bzw. example-mapping.txt.