Plik zamówienia to nowa metoda optymalizacji kreatora linków. Pliki zamówień to pliki tekstowe zawierające symbole reprezentujące funkcje. Łączniki, np. LLD, wykorzystują pliki zamówień do układania funkcji w określonej kolejności. Te pliki binarne lub biblioteki z uporządkowanymi symbolami zmniejszają liczbę błędów na stronie i skracają czas uruchomienia programu dzięki wydajnemu wczytywaniu symboli podczas uruchamiania programu „na zimno”.
Cechy pliku zamówienia można dodać do aplikacji w 3 krokach:
- Wygeneruj profile i plik mapowania
- Tworzenie pliku zamówienia z profili i plików mapowania
- Użyj pliku zamówienia podczas kompilacji wersji do ułożenia symboli
Generuj plik zamówienia
Generowanie pliku zamówienia składa się z 3 kroków:
- Utwórz instrumentalną wersję aplikacji, która zapisuje plik zamówienia
- Uruchom aplikację, aby wygenerować profile
- Przetwórz profile i plik mapowania.
Utwórz modelową kompilację
Profile są generowane przez uruchomienie instrumentalnej kompilacji aplikacji.
Kompilacja z instruktażem wymaga dodania -forder-file-instrumentation
do flag kompilatora i tagu łączącego, a -mllvm -orderfile-write-mapping=<filename>-mapping.txt
musi być ściśle dodany do flag kompilatora.
Flaga instrumentacji umożliwia instrumentację pliku zamówień na potrzeby profilowania i wczytuje określoną bibliotekę potrzebną do profilowania.
Z drugiej strony flaga mapowania generuje tylko plik mapowania, który pokazuje hasz MD5 dla każdej funkcji w pliku binarnym lub bibliotece.
Pamiętaj też, aby przekazać dowolną flagę optymalizacji, ale -O0
, ponieważ zarówno flaga instrumentacji, jak i flaga mapowania wymagają jednej.
Jeśli nie zostanie przesłana żadna flaga optymalizacji, plik mapowania nie zostanie wygenerowany, a instrumentowana kompilacja może przekazywać do pliku profilu nieprawidłowe hasze.
NK Build
Pamiętaj, aby utworzyć kompilację z użyciem APP_OPTIM=release
, aby ndk-build korzystał z trybu optymalizacji innego niż -O0
. Jeśli tworzysz aplikację z użyciem AGP, dzieje się to automatycznie
w przypadku kompilacji wersji.
LOCAL_CFLAGS += \
-forder-file-instrumentation \
-mllvm -orderfile-write-mapping=mapping.txt \
LOCAL_LDFLAGS += -forder-file-instrumentation
CMake
Pamiętaj, aby używać właściwości CMAKE_BUILD_TYPE
innego niż Debug
, więc CMake używa trybu optymalizacji innego niż -O0
. Gdy tworzysz aplikację z użyciem AGP, dzieje się to automatycznie
w przypadku kompilacji wersji.
target_compile_options(orderfiledemo PRIVATE
-forder-file-instrumentation
-mllvm -orderfile-write-mapping=mapping.txt
)
target_link_options(orderfiledemo PRIVATE -forder-file-instrumentation)
Inne systemy kompilacji
Skompiluj kod za pomocą narzędzia -forder-file-instrumentation -O1 -mllvm
-orderfile-write-mapping=mapping.txt
.
Język -O1
nie jest wymagany, ale nie używaj -O0
.
Pomiń element -mllvm -orderfile-write-mapping=mapping.txt
podczas łączenia.
Wszystkie te flagi nie są potrzebne w przypadku kompilacji Release, więc powinny być zarządzane za pomocą zmiennej kompilacji. Dla uproszczenia możesz to zrobić w pliku CMakeLists.txt tak jak w naszym przykładzie.
Tworzenie biblioteki plików zamówienia
Oprócz flag trzeba skonfigurować plik profilu, a instrumentowany plik binarny musi jawnie aktywować zapis profilu podczas wykonywania.
- Wywołaj
__llvm_profile_set_filename(PROFILE_DIR "/<filename>-%m.profraw")
, aby skonfigurować ścieżkę profilu. Mimo że przekazany argument to<filename>-%m.profraw
, plik profilu zostanie zapisany jako<filename>-%m.profraw.order
. Sprawdź, czy aplikacjaPROFILE_DIR
umożliwia zapis i masz dostęp do katalogu.- Ze względu na profilowanie wielu bibliotek udostępnionych usługa
%m
jest przydatna, ponieważ rozwija się do unikalnego podpisu modułu dla biblioteki, co powoduje utworzenie osobnego profilu dla każdej biblioteki. Więcej specyfikatorów wzorców znajdziesz pod tym linkiem.
- Ze względu na profilowanie wielu bibliotek udostępnionych usługa
- Zadzwoń pod numer
__llvm_profile_initialize_file()
, aby skonfigurować plik profilu - Wywołaj
__llvm_orderfile_dump()
, aby jawnie zapisać plik profilu
Profile są gromadzone w pamięci, a funkcja zrzutu zapisuje je w pliku. Upewnij się, że funkcja zrzutu jest wywoływana na koniec uruchamiania, aby plik profilu zawierał wszystkie symbole do końca uruchamiania.
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;
}
Uruchamianie kompilacji profili
Aby wygenerować profile, uruchom aplikację z instrumentacją na urządzeniu fizycznym lub wirtualnym.
Pliki profilu możesz rozpakować za pomocą narzędzia adb pull
.
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 .
Jak już wspomnieliśmy, upewnij się, że masz dostęp do folderu zawierającego zapisany plik profilu. Jeśli jest to urządzenie wirtualne, lepiej unikać stosowania emulatorów w Sklepie Play, ponieważ nie mają dostępu do wielu folderów.
Przetwarzanie pliku profilu i mapowania
Po pobraniu profili należy znaleźć plik mapowania i przekonwertować każdy profil na format szesnastkowy. Plik mapowania można zwykle znaleźć w folderze kompilacji aplikacji. Jeśli dysponujesz obydwoma plikami, możesz użyć naszego skryptu, aby pobrać plik profilu, a właściwy plik mapowania, aby wygenerować plik zamówienia.
Linux/macOS/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
Więcej informacji o skrypcie znajdziesz w tym README.
Użyj pliku zamówienia do utworzenia aplikacji
Po wygenerowaniu pliku zamówienia usuń wcześniejsze flagi i funkcje pliku zamówienia, ponieważ służą one tylko do generowania.
Wystarczy, że przekażesz -Wl,--symbol-ordering-file=<filename>.orderfile
do flag kompilacji i łącznika.
Czasami symboli nie można znaleźć lub przenieść i generują ostrzeżenia, dzięki czemu możesz omijać te ostrzeżenia -Wl,--no-warn-symbol-ordering
.
NK 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
)
Inne systemy kompilacji
Skompiluj kod za pomocą narzędzia -Wl,--symbol-ordering-file=<filename>.orderfile
-Wl,--no-warn-symbol-ordering
.
Więcej informacji znajdziesz w przykładowym pliku zamówienia.
Szczegóły implementacji pliku zamówienia
Pliki zamówień można tworzyć i wykorzystywać na wiele sposobów. NDK korzysta z metody LLVM, więc jest najbardziej użyteczna w bibliotekach współdzielonych w językach C lub C++, a nie samej aplikacji w Javie czy Kotlin. Clang pobiera nazwę każdej funkcji (symbol) i tworzy jej skrót MD5, a następnie przekazuje tę relację do pliku mapowania. Skrót MD5 funkcji jest zapisywany w pliku profilu (w formacie profraw) podczas pierwszego uruchomienia funkcji. Wszystkie kolejne wykonania tej funkcji nie zapisują skrótu MD5 w pliku profilu, ponieważ chcemy uniknąć duplikatów. W rezultacie w zamówieniu rejestrowane jest tylko pierwsze wykonanie tej funkcji. Przeglądając plik profilu i plik mapowania, możesz zastąpić każdy hasz MD5 odpowiednią funkcją i uzyskać plik zamówienia.
Przykłady plików profilu w formacie szesnastkowym i plików mapowania znajdziesz odpowiednio w formacie example.prof i example-mapping.txt.