如何使用設定檔導向最佳化建置 Clang 和 LLVM

簡介

PGO(設定檔導向最佳化)讓您的編譯器能夠根據程式碼的實際執行情況更好地最佳化程式碼。使用者報告指出,將此技術應用於 Clang 和 LLVM 可以減少整體編譯時間達 20%。

本指南將引導您完成如何使用 PGO 建置 Clang 的步驟,儘管它也適用於其他子專案,例如 LLD。

如果您想使用 PGO 建置其他軟體,請參閱 PGO 的終端使用者文件

使用預先設定的 CMake 快取

請參閱 https://llvm.dev.org.tw/docs/AdvancedBuilds.html#multi-stage-pgo

使用腳本

我們在 utils/collect_and_build_with_pgo.py 提供了一個腳本。此腳本已在幾個 Linux 版本上測試過,並且需要 LLVM、Clang 和 compiler-rt 的 checkout。儘管名稱如此,它會執行四次 Clang 的完整建置,因此可能需要一段時間才能完成。請參閱腳本的 --help 以獲取更多關於如何執行它以及可用的不同選項的資訊。如果您想針對特定用例(例如,編譯特定的龐大軟體)充分利用 PGO,請務必閱讀以下關於「基準測試」選擇的部分。

請注意,此腳本僅在少數 Linux 發行版上進行了測試。一如既往,非常感謝您提供補丁以增加對其他平台的支持。:)

此腳本也支援 --dry-run 選項,這會使其印出重要的命令而不是執行它們。

選擇「基準測試」

當收集到的設定檔能代表使用者計劃如何使用編譯器時,PGO 的效果最佳。值得注意的是,如果您要以 ARM 為目標,那麼準確度極高的 llc 建置 x86_64 程式碼的設定檔並不是非常有幫助。

預設情況下,上述腳本會執行兩項操作以獲得穩固的覆蓋率。它

  • 執行 Clang 和 LLVM 的所有 lit 測試,以及

  • 使用 instrumented Clang 建置 Clang、LLVM 以及所有其他可用的 LLVM 子專案。

總之,這些應該為您提供

  • 穩固的 C++ 建置覆蓋率,

  • 良好的 C 建置覆蓋率,

  • 出色的執行最佳化覆蓋率,

  • 出色的主機架構後端覆蓋率,以及

  • 一些其他架構的覆蓋率(如果其他架構是支援的後端)。

總而言之,這應該涵蓋 Clang 和 LLVM 的各種不同用途。如果您有非常特定的需求(例如,您的編譯器旨在為四個不同的平台編譯大型瀏覽器,或類似情況),您可能需要執行其他操作。這可以在腳本本身中配置。

使用 PGO 建置 Clang

如果您不喜歡使用腳本或 cmake 快取,本節將簡要介紹如何使用 PGO 建置 Clang/LLVM。

首先,您應該至少在本地 checkout LLVM、Clang 和 compiler-rt。

接下來,從高層次來看,您需要執行以下操作

  1. 建置標準的 Release Clang 和相關的 libclang_rt.profile 庫

  2. 使用您在上面建置的 Clang 建置 Clang,但要帶有 instrumentation

  3. 使用 instrumented Clang 生成設定檔,這包含兩個步驟

  • 在代表使用者將如何使用所述工具的任務上執行 instrumented Clang/LLVM/lld/etc。

  • 使用工具將上面生成的「raw」設定檔轉換為單個最終的 PGO 設定檔。

  1. 使用從基準測試收集的設定檔建置最終的 release Clang(以及您需要的任何其他二進制檔案)

更詳細的步驟

  1. 像平常一樣配置 Clang 建置。強烈建議您為此使用 Release 配置,因為它將用於建置另一個 Clang。由於您需要 Clang 和支援庫,因此您需要建置 all 目標(例如 ninja allmake -j4 all)。

  2. 如上所述配置 Clang 建置,但添加以下 CMake 參數

    • -DLLVM_BUILD_INSTRUMENTED=IR – 這會使我們建置所有帶有 instrumentation 的內容。

    • -DLLVM_BUILD_RUNTIME=No – 一些專案在使用 profiling 建置時會有不良互動,並且不是必要的建置項目。此標誌會將它們關閉。

    • -DCMAKE_C_COMPILER=/path/to/stage1/clang - 使用我們在步驟 1 中建置的 Clang。

    • -DCMAKE_CXX_COMPILER=/path/to/stage1/clang++ - 與上述相同。

在這個建置目錄中,您只需要建置 clang 目標(以及您的基準測試所需的任何支援工具)。

  1. 如上所述,這包含兩個步驟:收集設定檔資料,然後將其整理成有用的形式

    1. 使用在步驟 2 中生成的 Clang 建置您的基準測試。「標準」基準測試建議是在 instrumented Clang 的建置目錄中執行 check-clangcheck-llvm,並使用您的 instrumented Clang 完整建置 Clang/LLVM。因此,再創建另一個建置目錄,並使用以下 CMake 參數

      • -DCMAKE_C_COMPILER=/path/to/stage2/clang - 使用我們在步驟 2 中建置的 Clang。

      • -DCMAKE_CXX_COMPILER=/path/to/stage2/clang++ - 與上述相同。

      如果您的使用者是 debug info 的愛好者,您可能需要考慮使用 -DCMAKE_BUILD_TYPE=RelWithDebInfo 而不是 -DCMAKE_BUILD_TYPE=Release。這將提供更好的 clang debug info 組件覆蓋率,但會花費更長的時間才能完成,並導致更大的建置目錄。

      建議使用您的 instrumented Clang 建置 all 目標,因為更高的覆蓋率通常更好。

  1. 您現在應該在 path/to/stage2/profiles/ 中有一些 *.profraw 檔案。您需要使用 llvm-profdata 合併這些檔案(即使您只有一個!設定檔合併也會將 profraw 轉換為實際的設定檔資料)。這可以使用 /path/to/stage1/llvm-profdata merge -output=/path/to/output/profdata.prof path/to/stage2/profiles/*.profraw 完成。

  1. 現在,建置您的最終 PGO 最佳化 Clang。為此,您需要將以下額外參數傳遞給 CMake。

    • -DLLVM_PROFDATA_FILE=/path/to/output/profdata.prof - 使用上一步驟中的 PGO 設定檔。

    • -DCMAKE_C_COMPILER=/path/to/stage1/clang - 使用我們在步驟 1 中建置的 Clang。

    • -DCMAKE_CXX_COMPILER=/path/to/stage1/clang++ - 與上述相同。

    從這裡開始,您可以建置您需要的任何目標。

    注意

    您可能會在建置輸出中看到關於設定檔不匹配的警告。這些通常是無害的。若要消除它們,您可以將 -DCMAKE_C_FLAGS='-Wno-backend-plugin' -DCMAKE_CXX_FLAGS='-Wno-backend-plugin' 添加到您的 CMake 調用中。

恭喜!您現在擁有一個使用設定檔導向最佳化建置的 Clang,如果您願意,您可以刪除除了最終建置目錄之外的所有內容。

如果這對您來說效果良好,並且您計劃經常執行此操作,則可以進行一些輕微的最佳化:LLVM 和 Clang 有一個名為 tblgen 的工具,該工具在建置過程中建置和執行。雖然在步驟 3 中將其建置以獲得覆蓋率可能很好,但您的其他建置都不應從建置它中受益。您可以將 CMake 選項 -DLLVM_NATIVE_TOOL_DIR=/path/to/stage1/bin 傳遞給步驟 2 及之後的步驟,以避免這些無用的重新建置。