使用設定檔引導最佳化功能

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 的步驟如下:

  1. -fprofile-generate 傳遞至編譯器和連結器,藉此建構含有檢測功能的程式庫/可執行檔。
  2. 在檢測二進位檔上執行代表性工作負載,藉此收集設定檔。
  3. 使用 llvm-profdata 公用程式對設定檔進行後置處理 (詳情請參閱「處理 LLVM 設定檔檔案」)。
  4. -fprofile-use=<>.profdata 傳遞給編譯器和連結器,藉此使用設定檔套用 PGO。

針對 Android 中的 PGO,應在離線狀態下收集設定檔,並與程式碼一併簽入,以確保可重現的版本。設定檔可在程式碼演進時使用,但必須定期重新產生 (或在 Clang 警告設定檔過時時重新產生)。

收集設定檔

Clang 可以使用設定檔,這些設定檔是透過執行基準測試時,使用檢測版本的程式庫或硬體計數器取樣所收集到的。目前 Android 不支援使用以取樣為基礎的設定檔收集作業,因此您必須使用檢測版本收集設定檔:

  1. 找出基準測試和該基準測試共同執行的一組程式庫。
  2. pgo 屬性新增至基準和程式庫 (詳情請見下文)。
  3. 使用以下工具,產生 Android 版本,其中包含這些程式庫的檢測副本:
    make ANDROID_PGO_INSTRUMENT=benchmark

benchmark 是用來識別建構期間用於檢測的程式庫集合的預留位置。實際的代表性輸入內容 (以及可能與基準測試程式庫連結的其他可執行檔) 並非 PGO 專屬,且超出本文的範圍。

  1. 在裝置上刷新或同步檢測版本。
  2. 執行基準測試以收集設定檔。
  3. 使用 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",
    }
}

如果基準 benchmark1benchmark2 為程式庫 libstatic1libstatic2libshared1 執行代表性行為,這些程式庫的 pgo 屬性也可以包含基準。Android.bp 中的 defaults 模組可為一組程式庫加入常見的 pgo 規格,避免為多個模組重複相同的建構規則。

如要選取不同的設定檔或針對架構有選擇地停用 PGO,請為每個架構指定 profile_fileenable_profile_usecflags 屬性。範例 (架構目標以粗體字表示):

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-profdatashow 選項就很實用:

  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_idshow 輸出內容,找出程式庫專屬的函式名稱。

個案研究:ART 的 PGO

本個案研究以 ART 做為相關範例,但並未正確描述為 ART 剖析的實際程式庫集合或其相互依賴關係。

ART 中的 dex2oat 預先編譯器會依附 libart-compiler.so,而後者則依附 libart.so。ART 執行階段主要實作於 libart.so 中。編譯器和執行階段的基準測試會有所不同:

基準 已剖析的程式庫
dex2oat dex2oat (可執行)、libart-compiler.solibart.so
art_runtime libart.so
  1. 將下列 pgo 屬性新增至 dex2oatlibart-compiler.so
        pgo: {
            instrumentation: true,
            benchmarks: ["dex2oat",],
            profile_file: "dex2oat.profdata",
        }
  2. libart.so 中新增下列 pgo 屬性:
        pgo: {
            instrumentation: true,
            benchmarks: ["art_runtime", "dex2oat",],
            profile_file: "libart.profdata",
        }
  3. 使用以下工具,為 dex2oatart_runtime 基準測試建立檢測版本:
        make ANDROID_PGO_INSTRUMENT=dex2oat
        make ANDROID_PGO_INSTRUMENT=art_runtime
  4. 或者,您也可以使用以下方式建立單一檢測版本,並檢測所有程式庫:

        make ANDROID_PGO_INSTRUMENT=dex2oat,art_runtime
        (or)
        make ANDROID_PGO_INSTRUMENT=ALL

    第二個指令會建構 所有支援 PGO 的模組,用於剖析。

  5. 執行 dex2oatart_runtime 的基準測試,以取得下列項目:
    • dex2oat 中的三個 .profraw 檔案 (dex2oat_exe.profdatadex2oat_libart-compiler.profdatadexeoat_libart.profdata),使用「處理 LLVM 設定檔」一文所述的方法識別。
    • 單一 art_runtime_libart.profdata
  6. 使用以下方法,為 dex2oat 可執行檔和 libart-compiler.so 產生通用的 profdata 檔案:
    llvm-profdata merge -output=dex2oat.profdata \
        dex2oat_exe.profdata dex2oat_libart-compiler.profdata
  7. 合併兩個基準資料的設定檔,取得 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,實際權重應根據領域知識或實驗結果決定。

  8. 將設定檔 dex2oat.profdatalibart.profdata 檢查至 toolchain/pgo-profiles,以便在建構期間使用。