使用配置文件引導優化 (PGO)

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-instr-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 )。構建通過將此文件添加到$DIST_DIR/pgo_profile_file_missing.txt來警告該文件不存在,除非enable_profile_use屬性設置為falseANDROID_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檢入源樹以在構建期間使用。

如果在基準測試期間加載了多個已檢測的二進製文件/庫,則每個庫都會生成一個具有單獨唯一 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映射到各個庫,請在show輸出中搜索每個unique_id以查找該庫唯一的函數名稱。

案例研究:用於 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
  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. 使用:
        make ANDROID_PGO_INSTRUMENT=dex2oat
        make ANDROID_PGO_INSTRUMENT=art_runtime
    dex2oatart_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. 使用
    llvm-profdata merge -output=dex2oat.profdata \
        dex2oat_exe.profdata dex2oat_libart-compiler.profdata
    dex2oat可執行文件和libart-compiler.so生成一個通用 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.profdatatoolchain/pgo-profiles以在構建期間使用。