Android 13 以下版本的 Android 建構系統支援在具有藍圖建構規則的原生 Android 模組上使用 Clang 的設定檔導向最佳化 (PGO)。本頁面說明 Clang PGO、如何持續產生及更新用於 PGO 的設定檔,以及如何將 PGO 與建構系統整合 (附上用途)。
注意:本文件說明如何在 Android 平台上使用 PGO。如要瞭解如何在 Android 應用程式中使用 PGO,請參閱 這個頁面。
關於 Clang PGO
Clang 可以使用兩種類型的設定檔執行設定檔引導最佳化:
- 以檢測為準的設定檔會從檢測過的目標程式產生。這些設定檔相當詳細,因此會造成大量的執行階段額外負擔。
- 以取樣為基礎的設定檔通常是由取樣硬體計數器產生。這類事件的執行階段負擔較低,且無須對二進位檔進行任何檢測或修改,即可收集。但比起以檢測為基礎的設定檔,它們提供的詳細資料較少。
所有設定檔都應從代表性工作負載產生,以便執行應用程式的一般行為。雖然 Clang 同時支援以 AST 為基礎 (-fprofile-instr-generate
) 和以 LLVM IR 為基礎 (-fprofile-generate)
) 的設定檔,但 Android 僅支援以 LLVM IR 為基礎的設定檔,用於以檢測為基礎的 PGO。
如要建構設定檔收集功能,您需要加入下列旗標:
-fprofile-generate
:用於以 IR 為基礎的檢測。使用這個選項時,後端會使用加權最小生成樹方法,減少檢測點數量,並將檢測點放置在低權重邊緣,以利最佳化 (連結步驟也要使用這個選項)。Clang 驅動程式會自動將剖析執行階段 (libclang_rt.profile-arch-android.a
) 傳遞至連結器。這個程式庫包含例行程序,可在程式結束時將設定檔寫入磁碟。-gline-tables-only
:用於以取樣方式收集設定檔,以產生最少的偵錯資訊。
您可以使用 -fprofile-use=pathname
或 -fprofile-sample-use=pathname
分別為以檢測為基礎和以取樣為基礎的設定檔使用 PGO。
注意:如果 Clang 無法再使用設定檔資料,就會在程式碼變更後產生 -Wprofile-instr-out-of-date
警告。
使用 PGO
使用 PGO 的步驟如下:
- 將
-fprofile-generate
傳遞至編譯器和連結器,藉此建構含有檢測功能的程式庫/可執行檔。 - 在檢測二進位檔上執行代表性工作負載,藉此收集設定檔。
- 使用
llvm-profdata
公用程式對設定檔進行後置處理 (詳情請參閱「處理 LLVM 設定檔檔案」)。 - 將
-fprofile-use=<>.profdata
傳遞給編譯器和連結器,藉此使用設定檔套用 PGO。
針對 Android 中的 PGO,應在離線狀態下收集設定檔,並與程式碼一併簽入,以確保可重現的版本。設定檔可在程式碼演進時使用,但必須定期重新產生 (或在 Clang 警告設定檔過時時重新產生)。
收集設定檔
Clang 可以使用設定檔,這些設定檔是透過執行基準測試時,使用檢測版本的程式庫或硬體計數器取樣所收集到的。目前 Android 不支援使用以取樣為基礎的設定檔收集作業,因此您必須使用檢測版本收集設定檔:
- 找出基準測試和該基準測試共同執行的一組程式庫。
- 將
pgo
屬性新增至基準和程式庫 (詳情請見下文)。 - 使用以下工具,產生 Android 版本,其中包含這些程式庫的檢測副本:
make ANDROID_PGO_INSTRUMENT=benchmark
benchmark
是用來識別建構期間用於檢測的程式庫集合的預留位置。實際的代表性輸入內容 (以及可能與基準測試程式庫連結的其他可執行檔) 並非 PGO 專屬,且超出本文的範圍。
- 在裝置上刷新或同步檢測版本。
- 執行基準測試以收集設定檔。
- 使用
llvm-profdata
工具 (詳見下文) 對設定檔進行後處理,並準備將其簽入來源樹狀結構。
在建構期間使用設定檔
將設定檔檢查至 Android 樹狀結構中的 toolchain/pgo-profiles
。名稱應與程式庫 pgo
屬性的 profile_file
子屬性中指定的名稱相符。建構系統在建構程式庫時,會自動將設定檔傳遞至 Clang。您可以將 ANDROID_PGO_DISABLE_PROFILE_USE
環境變數設為 true
,暫時停用 PGO,並評估其效能優勢。
如要指定其他產品專屬設定檔目錄,請將這些目錄附加至 BoardConfig.mk
中的 PGO_ADDITIONAL_PROFILE_DIRECTORIES
製作變數。如果指定其他路徑,這些路徑中的設定檔會覆寫 toolchain/pgo-profiles
中的設定檔。
當您使用 dist
目標至 make
產生發布映像檔時,建構系統會將缺少的設定檔名稱寫入 $DIST_DIR/pgo_profile_file_missing.txt
。您可以查看這個檔案,瞭解哪些設定檔意外遺失 (這會在背景停用 PGO)。
在 Android.bp 檔案中啟用 PGO
如要在原生模組的 Android.bp
檔案中啟用 PGO,只需指定 pgo
屬性即可。這個屬性包含下列子屬性:
資源 | 說明 |
---|---|
instrumentation
|
使用檢測工具將 PGO 設為 true 。預設值為 false 。 |
sampling
|
將此值設為 true ,即可使用取樣技術進行 PGO。預設值為 false 。 |
benchmarks
|
字串清單。如果 ANDROID_PGO_INSTRUMENT 建構選項中指定了清單中的任何基準測試,這個模組就會建立用於剖析的資料。 |
profile_file
|
與 PGO 搭配使用的設定檔檔案 (相對於 toolchain/pgo-profile )。建構作業會將此檔案新增至 $DIST_DIR/pgo_profile_file_missing.txt ,並發出檔案不存在的警告,除非 enable_profile_use 屬性設為 false 或 ANDROID_PGO_NO_PROFILE_USE 建構變數設為 true 。 |
enable_profile_use
|
如果不應在建構期間使用設定檔,請將其設為 false 。可在引導期間使用,用於啟用設定檔收集功能,或暫時停用 PGO。預設值為 true 。 |
cflags
|
在檢測建構期間使用的其他標記清單。 |
使用 PGO 的模組範例:
cc_library { name: "libexample", srcs: [ "src1.cpp", "src2.cpp", ], static: [ "libstatic1", "libstatic2", ], shared: [ "libshared1", ] pgo: { instrumentation: true, benchmarks: [ "benchmark1", "benchmark2", ], profile_file: "example.profdata", } }
如果基準 benchmark1
和 benchmark2
為程式庫 libstatic1
、libstatic2
或 libshared1
執行代表性行為,這些程式庫的 pgo
屬性也可以包含基準。Android.bp
中的 defaults
模組可為一組程式庫加入常見的 pgo
規格,避免為多個模組重複相同的建構規則。
如要選取不同的設定檔或針對架構有選擇地停用 PGO,請為每個架構指定 profile_file
、enable_profile_use
和 cflags
屬性。範例 (架構目標以粗體字表示):
cc_library { name: "libexample", srcs: [ "src1.cpp", "src2.cpp", ], static: [ "libstatic1", "libstatic2", ], shared: [ "libshared1", ], pgo: { instrumentation: true, benchmarks: [ "benchmark1", "benchmark2", ], } target: { android_arm: { pgo: { profile_file: "example_arm.profdata", } }, android_arm64: { pgo: { profile_file: "example_arm64.profdata", } } } }
如要在以檢測為基礎的分析期間解析對分析執行階段程式庫的參照,請將建構旗標 -fprofile-generate
傳遞至連結器。使用 PGO 檢測的靜態資料庫、所有共用資料庫,以及任何直接依附於靜態資料庫的二進位檔,也必須為 PGO 檢測。不過,這類共用程式庫或執行檔不需要使用 PGO 設定檔,且其 enable_profile_use
屬性可設為 false
。除了這項限制之外,您可以將 PGO 套用至任何靜態資料庫、共用資料庫或可執行檔。
處理 LLVM 設定檔檔案
執行檢測程式庫或可執行檔會在 /data/local/tmp
中產生名為 default_unique_id_0.profraw
的設定檔 (其中 unique_id
是此程式庫專屬的數字雜湊值)。如果此檔案已存在,剖析執行階段會在寫入設定檔時,將新設定檔與舊設定檔合併。請注意,應用程式開發人員無法存取 /data/local/tmp
;他們應改用 /storage/emulated/0/Android/data/packagename/files
之類的項目。如要變更設定檔檔案的位置,請在執行階段設定 LLVM_PROFILE_FILE
環境變數。
接著,使用 llvm-profdata
公用程式將 .profraw
檔案 (並可能合併多個 .profraw
檔案) 轉換為 .profdata
檔案:
llvm-profdata merge -output=profile.profdata <.profraw and/or .profdata files>
接著,profile.profdata
即可提交至來源樹狀結構,以便在建構期間使用。
如果在基準測試期間載入多個經檢測的二進位檔/程式庫,每個程式庫都會產生一個 .profraw
檔案,並附上獨立的唯一 ID。通常,所有這些檔案都可以合併為單一 .profdata
檔案,並用於 PGO 建構。如果程式庫由其他基準測試執行,則必須使用兩個基準測試的設定檔來最佳化該程式庫。在這種情況下,llvm-profdata
的 show
選項就很實用:
llvm-profdata merge -output=default_unique_id.profdata default_unique_id_0.profraw llvm-profdata show -all-functions default_unique_id.profdata
如要將 unique_id 對應至個別程式庫,請搜尋每個 unique_id 的 show
輸出內容,找出程式庫專屬的函式名稱。
個案研究:ART 的 PGO
本個案研究以 ART 做為相關範例,但並未正確描述為 ART 剖析的實際程式庫集合或其相互依賴關係。
ART 中的 dex2oat
預先編譯器會依附 libart-compiler.so
,而後者則依附 libart.so
。ART 執行階段主要實作於 libart.so
中。編譯器和執行階段的基準測試會有所不同:
基準 | 已剖析的程式庫 |
---|---|
dex2oat
|
dex2oat (可執行)、libart-compiler.so 、libart.so |
art_runtime
|
libart.so
|
- 將下列
pgo
屬性新增至dex2oat
、libart-compiler.so
:pgo: { instrumentation: true, benchmarks: ["dex2oat",], profile_file: "dex2oat.profdata", }
- 在
libart.so
中新增下列pgo
屬性:pgo: { instrumentation: true, benchmarks: ["art_runtime", "dex2oat",], profile_file: "libart.profdata", }
- 使用以下工具,為
dex2oat
和art_runtime
基準測試建立檢測版本:make ANDROID_PGO_INSTRUMENT=dex2oat make ANDROID_PGO_INSTRUMENT=art_runtime
- 執行
dex2oat
和art_runtime
的基準測試,以取得下列項目:dex2oat
中的三個.profraw
檔案 (dex2oat_exe.profdata
、dex2oat_libart-compiler.profdata
和dexeoat_libart.profdata
),使用「處理 LLVM 設定檔」一文所述的方法識別。- 單一
art_runtime_libart.profdata
。
- 使用以下方法,為
dex2oat
可執行檔和libart-compiler.so
產生通用的 profdata 檔案:llvm-profdata merge -output=dex2oat.profdata \ dex2oat_exe.profdata dex2oat_libart-compiler.profdata
- 合併兩個基準資料的設定檔,取得
libart.so
的設定檔:llvm-profdata merge -output=libart.profdata \ dex2oat_libart.profdata art_runtime_libart.profdata
兩個剖析資料的
libart.so
原始計數可能不同,因為基準測試的測試案例數量和執行時間不同。在這種情況下,您可以使用加權合併:llvm-profdata merge -output=libart.profdata \ -weighted-input=2,dex2oat_libart.profdata \ -weighted-input=1,art_runtime_libart.profdata
上述指令會將
dex2oat
的權重值乘以 2,實際權重應根據領域知識或實驗結果決定。 - 將設定檔
dex2oat.profdata
和libart.profdata
檢查至toolchain/pgo-profiles
,以便在建構期間使用。
或者,您也可以使用以下方式建立單一檢測版本,並檢測所有程式庫:
make ANDROID_PGO_INSTRUMENT=dex2oat,art_runtime (or) make ANDROID_PGO_INSTRUMENT=ALL
第二個指令會建構 所有支援 PGO 的模組,用於剖析。