如何使用 Profile-Guided Optimizations 建置 Clang 和 LLVM¶
簡介¶
PGO(Profile-Guided Optimization,剖析導引最佳化)允許您的編譯器根據程式碼實際執行的方式更好地最佳化程式碼。使用者回報說,將其應用於 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。儘管名稱如此,但它會執行四次 Clang 的乾淨建置,因此可能需要一段時間才能完成執行。有關如何執行腳本以及可用的不同選項的更多資訊,請參閱腳本的 --help
。如果您想為特定用例(例如,編譯一個特定的龐大軟體)充分利用 PGO,請閱讀下方關於「基準測試」選擇的部分。
請注意,此腳本僅在少數 Linux 發行版上進行過測試。一如既往,我們非常歡迎您提供新增對其他平台支援的補丁。:)
此腳本也支援 --dry-run
選項,這會導致它列印重要命令而不是執行它們。
選擇「基準測試」¶
當收集到的剖析資料代表使用者計畫如何使用編譯器時,PGO 的效果最佳。值得注意的是,如果您要以 ARM 為目標,那麼高度準確的 llc 建置 x86_64 程式碼的剖析資料並不是非常有用。
根據預設,上述腳本會執行兩件事以獲得可靠的覆蓋率。它
會執行所有 Clang 和 LLVM 的 lit 測試,並且
會使用已檢測的 Clang 來建置 Clang、LLVM 以及所有其他可用的 LLVM 子專案。
這些加起來應該可以讓您
可靠地涵蓋 C++ 建置,
良好地涵蓋 C 建置,
極佳地涵蓋執行最佳化,
極佳地涵蓋主機架構的後端,並且
涵蓋其他架構(如果支援其他架構的後端)。
總之,這應該涵蓋 Clang 和 LLVM 的各種使用方式。如果您有非常特定的需求(例如,您的編譯器旨在為四種不同的平台編譯一個大型瀏覽器,或類似情況),您可能需要執行其他操作。這可以在腳本本身中進行配置。
使用 PGO 建置 Clang¶
如果您不想使用腳本或 cmake 快取,以下簡要介紹如何使用 PGO 建置 Clang/LLVM。
首先,您應該至少在本機檢出 LLVM、Clang 和 compiler-rt。
接下來,從高層次來看,您需要執行以下操作
建置一個標準的 Release Clang 和相關的 libclang_rt.profile 函式庫
使用您在上方建置的 Clang 建置 Clang,但要使用插裝
使用插裝的 Clang 產生效能剖析資料,這包含兩個步驟
在代表使用者將如何使用上述工具的任務上執行插裝的 Clang/LLVM/lld/etc。
使用工具將上方產生的「原始」效能剖析資料轉換為單一、最終的 PGO 效能剖析資料。
使用從基準測試收集的效能剖析資料建置最終的 Release Clang(以及您需要的任何其他二進位檔案)
更詳細的步驟
以您通常的方式設定 Clang 建置。強烈建議您為此使用 Release 組態,因為它將用於建置另一個 Clang。因為您需要 Clang 和支援函式庫,所以您需要建置
all
目標(例如ninja all
或make -j4 all
)。如上所述設定 Clang 建置,但新增以下 CMake 參數
-DLLVM_BUILD_INSTRUMENTED=IR
– 這會導致我們使用插裝建置所有內容。-DLLVM_BUILD_RUNTIME=No
– 一些專案在使用效能剖析建置時會產生不良互動,並且不需要建置。此旗標會將其關閉。-DCMAKE_C_COMPILER=/path/to/stage1/clang
- 使用我們在步驟 1 中建置的 Clang。-DCMAKE_CXX_COMPILER=/path/to/stage1/clang++
- 與上相同。
在此建置目錄中,您只需要建置
clang
目標(以及您的基準測試所需的任何支援工具)。
如上所述,這包含兩個步驟:收集效能剖析資料,然後將其調整為可用的形式
使用在步驟 2 中產生的 Clang 建置您的基準測試。建議的「標準」基準測試是在您插裝的 Clang 的建置目錄中執行
check-clang
和check-llvm
,並使用您插裝的 Clang 進行 Clang/LLVM 的完整建置。因此,建立另一個建置目錄,並使用以下 CMake 參數-DCMAKE_C_COMPILER=/path/to/stage2/clang
- 使用我們在步驟 2 中建置的 Clang。-DCMAKE_CXX_COMPILER=/path/to/stage2/clang++
- 與上相同。
如果您的使用者是偵錯資訊的愛好者,您可能會考慮使用
-DCMAKE_BUILD_TYPE=RelWithDebInfo
而不是-DCMAKE_BUILD_TYPE=Release
。這將提供 clang 偵錯資訊部分的更好覆蓋率,但需要更長的時間才能完成,並且會導致更大的建置目錄。建議使用您插裝的 Clang 建置
all
目標,因為更高的覆蓋率通常更好。
您現在應該在
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
完成。
現在,建置您最終的 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 及之後的步驟,以避免這些不必要的重建。