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:
- Profile und Zuordnungsdatei generieren
- Bestelldatei aus der Profil- und Zuordnungsdatei erstellen
- 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:
- Instrumentierte Version der App erstellen, die die Bestelldatei schreibt
- App ausführen, um die Profile zu generieren
- 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 AnwendungPROFILE_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.
- Da für viele gemeinsam genutzte Bibliotheken Profile erstellt werden, ist
__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.