Pliki zamówień

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:

  1. Wygeneruj profile i plik mapowania
  2. Tworzenie pliku zamówienia z profili i plików mapowania
  3. 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:

  1. Utwórz instrumentalną wersję aplikacji, która zapisuje plik zamówienia
  2. Uruchom aplikację, aby wygenerować profile
  3. 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 aplikacja PROFILE_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.
  • 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.