作者mshockwave (夏克維夫)
看板CompilerDev
標題[閒聊] 加快建置LLVM專案的速度
時間Tue Jun 9 13:30:19 2020
我想大家都知道LLVM原始碼的規模只會不斷增加 建置他所要花的時間與資源也逐漸讓
各位手上的舊筆電哀嚎
很可惜的並沒有一種方法是能突然讓編譯時間縮減為幾分鐘甚至幾秒鐘
如果各位要專為這種大規模建置購買硬體的話只能尋求:
1. 超多核心CPU。每顆的時脈不用很高 但核心數一定要多
2. 很多的RAM。建議最低也要64GB,其實吃最多記憶體的不是編譯階段、而是
鏈結階段。等一下也會提到減少鏈結階段記憶體消耗的方法
3. SSD或是更高速的儲存裝置。筆者有親身體驗過用傳統HDD建置是多麼痛苦的一件事
當然不是說沒這些規格就不能建置,只是總時間通常都將近一兩個小時。
除了選對的硬體以外 這邊就來介紹幾個從建置設定下手的加速小訣竅
首先來複習一下最基本建置LLVM的方法:
從github上面clone下來...
$ git clone https://github.com/llvm/llvm-project
(如果你還不知道的話 官方很早就遷移到github,而且使用mono-repo的專案結構
也就是說clang compiler-rt 等子專案已經不再分別在其他repo 而是合併在一起了)
再來就是跑CMake...
$ mkdir build
$ cd build
$ cmake ../llvm
然後Make...
$ make all
然後你就會發現大概要花個1~2個小時才能編完。以下列出幾個可以加快建置速度的設定:
I. 不要用 GNU Make
真的,不要不要不要不要再用 Make 了(很重要所以說N遍
倒也不是說這個工具已經死了 單純只是一些本身設計上的缺失限制了他的速度
目前Unix/Linux類系統上最快的建置工具就屬 Ninja 了(
https://ninja-build.org/)
如果是在 Ubuntu 上可以安裝 ninja-build 這個 package
要使用 Ninja 的話 CMake 就要改成這樣:
$ cmake -G Ninja ../llvm
然後建置的時候指令就變成:
$ ninja all
II. 使用 Gold linker 或者 LLD
前面提過,鏈結階段吃最多記憶體,而且由於鏈結器是收集多個object file(*.o) 然後
生出單一個檔案,基本上不能做檔案層級的平行化,所以跑的速度也很慢
解決方式就是不要用多數Linux系統預設的鏈結器(他其實有個名字叫做 BFD linker)。
改用最早由 google 推出的 gold linker (ld.gold) 或是 LLVM 自己搞得一個 linker,
LLD (ld.lld)
gold linker 很早就被 google 捐贈到 GNU Project 所以只要你的 binutils 版本不要
太舊,基本上都已經是內建了,等下會介紹怎麼在 CMake 設定中使用
LLD 的話雖然已經包含在你現在盯著看的源碼樹裡面,但如果要先編LLD、再建置剩下的
專案的話有點麻煩 所以你可以直接從 package manager 安裝 (debian 家族還有
FreeBSD 基本上都有 lld 這個 package)
接下來就是修改 CMake 設定 (以 gold linker 為例):
$ cmake -G Ninja -DLLVM_USE_LINKER=gold ../llvm
如果是用 LLD 的話當然就是 -DLLVM_USE_LINKER=lld
Gold linker 可以幫你省下蠻可觀的記憶體 速度也比 BFD linker 還快
LLD 不僅記憶體消耗最少,他還能做模組階層、甚至函式階層的平行化 但那又是另一個
故事了
III. 不要編譯所有的Backend
預設情況下LLVM會建置所有架構的backend, 包括X86, ARM, RISCV...等等
幾年前這還不是什麼大問題 但近幾年加入的架構數目暴增,筆者寫這篇文章的當下
就有將近 20 個支援的架構。更別提每個backend的原始碼複雜程度也不可小覷
然而大部分的時候我們不需要那麼多 backends。這時就可以用 LLVM_TARGETS_TO_BUILD
這個 CMake 變數來挑選你要建置的backend:
$ cmake -G Ninja -DLLVM_USE_LINKER=gold \
-DLLVM_TARGETS_TO_BUILD="X86;AArch64" \
../llvm
這個變數接受的是一個用分號分隔的架構名稱列表
IV. 建置成動態鏈結函式庫
LLVM 這個計畫其中一個最迷人的地方在於所有的功能都模組化了 要用的時候挑選所需的
函式庫就行了。但預設上這些模組都是靜態鏈結函式庫(static library, *.a)
靜態函式庫的優點是執行速度快 但假設你有 N 個執行檔,每個都有用相同的 M 個靜態
函式庫,那在鏈結的時候最終要複製出 N*M 份函式庫、而且要花 N*M 的時間為每個
執行檔進行較為複雜的鏈結程序
不僅耗時而且會耗掉非常 非常 非常多的儲存空間
如果使用動態鏈結函式庫 (dynamic library, *.so)的話,最終只會產生出 M 份函式庫
而且在每個執行檔上面花的鏈結時間也比較少
回到 LLVM 的話題上。LLVM的建置是可以把每個模組的函式庫編譯成動態函式庫 以節省
非常可觀的硬碟空間以及不少鏈結時間
但動態鏈結往往有隱藏比較複雜的因素要擔心 因此LLVM官方是建議只有在開發的時候
才用這個選項,也就是 BUILD_SHARED_LIBS 這個 CMake 變數:
$ cmake -G Ninja -DLLVM_USE_LINKER=gold \
-DLLVM_TARGETS_TO_BUILD="X86;AArch64" \
-DBUILD_SHARED_LIBS=ON \
../llvm
==============
以上就是筆者知道的幾個可以加快建置LLVM速度 以及省下不少資源的方法
希望對你有幫助
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 169.234.228.195 (美國)
※ 文章網址: https://www.ptt.cc/bbs/CompilerDev/M.1591680622.A.035.html
推 create8: 感謝分享 06/09 16:01
推 decheng: 推 06/09 18:59
推 JackChung: 推 06/09 19:33
推 Dracarys: 推 06/09 19:44
推 sonicyang: 實用,不然i7 32GB Ninja 一樣編到死。是說雖然連結不 06/09 20:08
→ sonicyang: 會平行化,但是如果平行化編譯的話,各工具程式獨立執 06/09 20:08
→ sonicyang: 行檔會同時連結,32GB也會OOM... 06/09 20:08
推 akasan: LLVM_PARALLEL_LINK_JOBS 設定小一點 才不會在 link 階段 06/09 21:28
→ akasan: 吃光記憶體 swap 地獄 06/09 21:28
推 SMMIT: 推分享 06/09 22:50
→ s89162504: 遠端去工作站工作吧 每次make都兩三分鐘 摳頂很痛苦啊 06/09 23:19
推 a1u1usul3: 還會用ccache 06/11 02:46
推 sonicyang: 原來可以控制平行連結數啊... 06/11 07:02