作者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://webptt.com/cn.aspx?n=bbs/CompilerDev/M.1591680622.A.035.html
1F:推 create8: 感谢分享 06/09 16:01
2F:推 decheng: 推 06/09 18:59
3F:推 JackChung: 推 06/09 19:33
4F:推 Dracarys: 推 06/09 19:44
5F:推 sonicyang: 实用,不然i7 32GB Ninja 一样编到死。是说虽然连结不 06/09 20:08
6F:→ sonicyang: 会平行化,但是如果平行化编译的话,各工具程式独立执 06/09 20:08
7F:→ sonicyang: 行档会同时连结,32GB也会OOM... 06/09 20:08
8F:推 akasan: LLVM_PARALLEL_LINK_JOBS 设定小一点 才不会在 link 阶段 06/09 21:28
9F:→ akasan: 吃光记忆体 swap 地狱 06/09 21:28
10F:推 SMMIT: 推分享 06/09 22:50
11F:→ s89162504: 远端去工作站工作吧 每次make都两三分钟 抠顶很痛苦啊 06/09 23:19
12F:推 a1u1usul3: 还会用ccache 06/11 02:46
13F:推 sonicyang: 原来可以控制平行连结数啊... 06/11 07:02