使用設定檔引導優化

Android 13 及更低版本的 Android 建置系統支援在具有藍圖建置規則的本機 Android 模組上使用 Clang 的設定檔引導優化 (PGO) 。本頁介紹了 Clang PGO、如何持續產生和更新 PGO 的設定文件,以及如何將 PGO 與建置系統整合(帶有用例)。

注意:本文檔描述了 PGO 在 Android 平台中的使用。若要了解如何從 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用於基於採樣的設定檔收集,以產生最少的偵錯資訊。

設定檔可用於 PGO,分別使用-fprofile-use= pathname-fprofile-sample-use= pathname來表示基於偵測和基於取樣的設定檔。

注意:隨著程式碼的更改,如果 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 make 變數。如果指定了其他路徑,這些路徑中的設定檔將覆蓋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使用採樣將 PGO 設為true 。預設為false
benchmarks字串列表。如果在ANDROID_PGO_INSTRUMENT建置選項中指定了清單中的任何基準,則建置此模組用於分析。
profile_file與 PGO 一起使用的設定檔(相對於toolchain/pgo-profile )。除非將enable_profile_use屬性設為falseANDROID_PGO_NO_PROFILE_USE建置變數設為true ,否則建置會將此檔案新增至$DIST_DIR/pgo_profile_file_missing.txt來警告此檔案不存在。
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簽入來源樹以在建置期間使用。

如果在基準測試期間載入多個偵測的二進位檔案/函式庫,則每個函式庫都會產生一個具有單獨唯一 ID 的單獨.profraw檔案。通常,所有這些檔案都可以合併到一個.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-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. 將以下pgo屬性加入到libart.so
        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的設定檔分配兩倍的權重。實際權重應根據領域知識或實驗來決定。

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