排序檔案

排序檔案是最新的一項連接器最佳化技術。這些排序檔案是文字檔案,內含代表函式的符號。lld 等連接器會使用排序檔案,以特定順序來配置函式。這些二進位檔或程式庫含有已排序的符號,可在程式冷啟動期間有效載入符號,進而減少網頁錯誤,並縮短程式的啟動時間。

您可以按照下列三個步驟,將排序檔案功能新增到應用程式中:

  1. 產生設定檔和對應檔案
  2. 透過設定檔和對應檔案建立排序檔案
  3. 在發布子版本期間使用排序檔案來配置符號

產生排序檔案

產生排序檔案需要三個步驟:

  1. 建構可編寫排序檔案的檢測版應用程式
  2. 執行應用程式,產生設定檔
  3. 為設定檔和對應檔案進行後置處理

建立檢測版本

藉由執行應用程式的檢測版本,系統會產生設定檔。檢測版本需要將 -forder-file-instrumentation 同時新增至編譯器和連結器標記,-mllvm -orderfile-write-mapping=<filename>-mapping.txt 也需嚴謹地新增至編譯器標記上。檢測標記會啟用排序檔案檢測功能來剖析,並載入剖析所需的特定程式庫。另一方面,對應標記只會輸出對應檔案,其中顯示二進位檔或程式庫中每個函式的 MD5 雜湊。

此外,請務必傳遞除 -O0 以外的所有最佳化標記,因為檢測標記和對應標記都需要這個標記。如果您未傳遞最佳化標記,系統就不會產生對應檔案,而檢測版本可能會將錯誤的雜湊輸出到設定檔中。

ndk-build

請務必使用 APP_OPTIM=release 建構,讓 ndk-build 使用 -O0 以外的最佳化模式。您使用 AGP 建構時,系統會對發布子版本自動執行此操作。

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

LOCAL_LDFLAGS += -forder-file-instrumentation

CMake

請務必使用 Debug 以外的 CMAKE_BUILD_TYPE,讓 CMake 使用 -O0 以外的最佳化模式。您使用 AGP 建構時,系統會對發布子版本自動執行此操作。

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

其他建構系統

使用 -forder-file-instrumentation -O1 -mllvm -orderfile-write-mapping=mapping.txt 編譯程式碼。

具體而言,-O1 並非必要,但請勿使用 -O0

請在連結時省略 -mllvm -orderfile-write-mapping=mapping.txt

發布子版本不需要這些標記,因此應由建構變化版本控管。為了方便起見,您可以在 CMakeLists.txt 中完成上述所有設定,如範例所示。

建立排序檔案程式庫

除了標記之外,您還需要調整設定檔,檢測的二進位檔也需在執行期間明確觸發設定檔寫入作業。

  • 呼叫 __llvm_profile_set_filename(PROFILE_DIR "/<filename>-%m.profraw") 來調整設定檔路徑。雖然傳遞的引數是 <filename>-%m.profraw,但設定檔會儲存為 <filename>-%m.profraw.order。請確保 PROFILE_DIR 可由應用程式寫入,且您有權存取該目錄。
    • 由於要剖析的共用程式庫很多,%m 就能派上用場,因為它可以展開成為程式庫的唯一模組簽名,從而為每個程式庫產生獨立的設定檔。如需更多模式指定碼,請點選這個連結
  • 呼叫 __llvm_profile_initialize_file() 即可調整設定檔
  • 呼叫 __llvm_orderfile_dump() 即可明確寫入設定檔

系統會在記憶體中收集設定檔,然後交由轉儲函式將其寫入檔案之中。您需要確保在啟動程序結束時呼叫轉儲函式,讓設定檔納入啟動程序結束前的所有符號。

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;
}

執行版本以產生設定檔

請在實體或虛擬裝置上執行檢測應用程式,藉此產生設定檔。您可以使用 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 .

如前所述,請先確認您可以存取包含寫入設定檔的資料夾。如果您採用虛擬裝置,則可能需要避免使用 Play 商店的模擬器,因為該模擬器無法存取許多資料夾。

為設定檔和對應檔案進行後置處理

取得設定檔後,您需要找出對應檔案,並將每個設定檔轉換為十六進制格式。一般而言,您可以在應用程式的建構資料夾中找到對應檔案。當您取得設定檔和對應檔案後,可以使用我們的指令碼擷取設定檔和正確的對應檔案,進而產生排序檔案。

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

如要進一步瞭解指令碼,請查看這個 README 檔案。

使用排序檔案建構應用程式

產生排序檔案後,您應移除先前的標記和排序檔案函式,因為這些內容僅適用於產生步驟階段。您只需將 -Wl,--symbol-ordering-file=<filename>.orderfile 傳遞至編譯和連結器標記即可。有時,您可能會找不到符號,或無法移動符號來發出警告,因此不妨傳遞 -Wl,--no-warn-symbol-ordering 隱抑這些警告。

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
)

其他建構系統

使用 -Wl,--symbol-ordering-file=<filename>.orderfile -Wl,--no-warn-symbol-ordering 編譯程式碼。

詳情請參閱排序檔案範例

排序檔案實作詳情

您可以透過許多方法產生排序檔案並用於建構。NDK 採用 LLVM 方法,因此最適合用於 C 或 C++ 共用程式庫,而非實際的 Java 或 Kotlin 應用程式。Clang 接受各種函式名稱 (符號),會為其建立 MD5 雜湊,並將這個關係輸出至對應檔案。當函式首次執行時,系統會將函式的 MD5 雜湊寫入設定檔中 (profraw 格式)。但函式的任何後續執行作業,都不會將其 MD5 雜湊寫入至設定檔,因為這樣可避免重複。因此,系統只會依序記錄函式的首次執行作業。透過瀏覽設定檔和對應檔案,您可以擷取各個 MD5 雜湊,將其替換為對應的函式,並取得排序檔案。

十六進制格式設定檔和對應檔案的範例分別為 example.profexample-mapping.txt