作者lc85301 (pomelocandy)
看板C_and_CPP
标题[分享] 使用 ccache 加速编译
时间Thu Mar 25 15:15:24 2021
网志好读版:
https://yodalee.me/2021/03/2021_ccache/
发在这里好像不太适合,但最需要编译的应该也是这里:
----
故事是这样子的,小弟在公司工作内容,要维护公司产品核心的engine
要维护当然会需要把程式码从版本控制里签出来,修改、编译後测试修正有没有问题
而编译一直以来都非常花时间。
本文介绍的 ccache 是 compiler cache 的简称
https://ccache.dev/
会在编译时存下档案内容的 hash 与编译结果
在未来如果有相同的档案要编译的时候,就不用再次呼叫 gcc/g++ 进行耗时的编译
只要把存下的 object 档从 cache 里面抓出来就行了。
----
在编译加速上,小弟的公司已经做了许多努力,包括:
* prebuilt library:因为公司有很多共用的 library,每天某个时间点
电脑会自动签出当天的程式码并编译所有 library
如果你没改到 library,不签出这个 library 就不用重编译
连结定期建好的 library 即可。
* 公司也自干了一套编译工具,可以帮你把 code 洒到许多(一般预设是80台)
机器上平行编译, 有点类似 distcc,可以大幅减少编译时间。
话虽如此,分散式编译从零开始编译到产生执行档仍然需要 11 分 33 秒
如果不用分散式编译用单机编译则需要 23 分 36 秒
目前程式码里,有一些 cpp 档不知道是不是写太长或太复杂
光编译单一档案都要编超久,即使有分散式编译也会卡住整个编译流程。
最糟的是,随着签出的 library 数量愈多,编译时间也会愈长
某个极度复杂用程式写程式的元件,单机编译可能要花上两个小时
後来忘了我在哪个场合,听到强者我同学在 Google 大杀四方的小新大大
提到 ccache,就决定来试试看能加速多少?
## 安装
不是管理员无权动工作站的内容,我在工作站上只有找到一款 ccache-swig,版本是
1.2.4,这版本实在有点太老了
因此我决定自己去 github 载最新的 code 回来自己编译
https://github.com/ccache/ccache
建议至少要用到 ccache 3,才有支援下面会提到的 hash_dir 的功能。
ccache 采用的是 Cmake,载下来之後照安装步骤进行编译即可:
mkdir build
cd build
cmake -DZSTD_FROM_INTERNET=ON ..
make
make install
ccache 背後采用 facebook 的 libzstd 来压缩、储存快取的 .o 目的档
同样因为我的机器没装 libzstd,所以让 cmake 去网路上抓。
## 设定
装完之後 ccache 会需要一些设定,这里只列出我有设定的,其他的就请参阅文件。
https://ccache.dev/manual/4.2.html
每个 ccache 的设定都有两种设定方式,一种是用环境变数
一种是写到 ccache.conf档案中
### ccache directory
ccache 快取储存的位置,我用 CCACHE_DIR 环境变数来设定
一般预设会使用 $HOME/.cache 作为储存位置
但我们工作站有限制家目录的容量,因此我用 softlink
从 $HOME/.cache 连到大容量磁碟另一个 .cache 资料夹。
我不清楚 cache directory 放在硬碟、固态硬碟、Ramdisk 会不会对效能有影响
以速度、频繁读写又可以限制容量的性质来看,ccache 放在 Ramdisk 上应该满合理的
可惜在工作站上权限不够没办法自建挂载 ramdisk QQ。
ccache directory 下的 ccache.conf 则是我们的设定档。
### 最大容量
执行 ccache -M 2G 或在设定档中留下
max_size = 2G
来设定 ccache 可使用的最大容量
因为使用了 zstd 的关系,ccache 用的 cache 空间不会很大
我编译了应该有几百 MB 的执行档,debug/release 各一套近 1000 个目的档
也只用掉 250 MB 的 cache 空间,2G 对一般人来说应该很够用了。
### hash_dir
hash_dir = false
在写程式难免需要 debug build,而 debug build 会在目的档内留下编译时
资料夹的绝对路径,这会让 ccache 失效
因为在不同资料夹内的同一个档案,会被 ccache 视为不同档案而重编译
而工作上为了修正不同的问题,在不同地方同时签出 code 司空见惯。
设定 hash_dir = false 可以让 ccache 忽视掉档案的绝对路径资讯
即使不同资料夹内的编译也能共享 cache, 这也是为什麽上面说一定要用 >3 的版本
因为没有 hash_dir ccache 的效率会大幅下降。
对这个问题有其他的解决方式,请参考Compiling in different directories
https://ccache.dev/manual/4.2.html#_compiling_in_different_directories
## 测试
ccache 的使用方式很简单,把 gcc/g++ 呼叫改成 ccache gcc/g++
如果用的是 Makefile,最简单的就是设定 CC, CXX 两个变数
让 Makefile 替换掉编译的指令。
小弟因为公司自干一套编译系统,花了一点时间跟整合 team 问了该如何
设定自己的编译器
而且因为上述的分散式编译,会把工作丢到其他机器去执行
而远端机器的函式库旧到无法执行我用最新函式库编译的 ccache
导致我下面的测试都是把分散式编译关掉改用单机编译
测试结果可能会比用分散式编译还要好。
### 测试步骤
以下测试流程:
1. 用 ccache -Cz 清空快取与 ccache 统计资料
2. 签出 baseline 进行 debug build
3. 签出 enhance 进行 debug build
4. 在 baseline 进行 opt build
5. 在 enhance 进行 opt build
6. ccache -s 观看统计资料
我们的程式在 build 的时候,除了编译各个档案外
还有一些时间花在从程式里剖析 prototype 以及最後连结执行档的时间
这些都不是 ccache 可以加速的步骤;4. 5 步时,因为 2.3 步 debug build
已经做过从程式里剖析 prototype这件事,编译 c/cpp 档案的时间占比会更高。
### 测试结果
Baseline Enhance Gain
Debug Build 29 min 39 sec 11 min 51 sec 2.3x
Opt Build 23 min 36 sec 4 min 47 sec 4.9x
看这个结果我们应该可以推估从程式里剖析 prototype 这件事大概耗时六分钟
(而且这步没有平行化处理)。
这个结果比我想得还要厉害一点,编译占比高的 Opt build 几乎快了五倍。
当然,这里并没有测试分散式编译下 ccache 的影响
因为分散式编译下编译占的时间会少很多,想必效能增长不会这麽大。
统计结果当个参考就好 ccache -s
cache directory /home/ipban/.ccache
primary config /home/ipban/ccache.conf
secondary config (readonly) /home/ipban/myinstall/etc/ccache.conf
stats updated Wed Mar 24 12:46:34 2021
stats zeroed Wed Mar 24 11:48:15 2021
cache hit (direct) 459
cache hit (preprocessed) 2
cache miss 465
cache hit rate 49.78 %
called for link 4
cleanups performed 0
files in cache 928
cache size 246.8 MB
max cache size 2.0 GB
## 结语
导入 ccache 对编译速度改进比预想还要好
目前小弟应该会跟公司的整合 team 连络看看
看能不能将 ccache 导入我们的编译流程中。
毕竟如果在每天定期的编译时,也能把 ccache 的结果一并建出来
放在共用的磁碟内,大家把 cache dir 设到那里去,很可能可以省下巨量的编译时间
应该是满值得的。
--
______ |\
/ \ | \
/ ● ● \ |__\
/ ______ \ |
/ \__/ \___|
/______________\ |
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 149.117.214.29 (美国)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1616656531.A.B09.html
1F:推 Lipraxde: 为 CompilerDev 板感到难过 QQ 03/25 15:41
2F:→ lc85301: 那是编译器开发不是如何使用编译器吧XD 03/25 16:57
3F:推 oToToT: 前几天在build clang的时候也刚好看到这个,一直还没测测 03/26 19:36
4F:→ oToToT: 看就看到这篇了,感谢实测XD 03/26 19:36
5F:推 dces4212: 推 原来有编译器板喔== 03/27 01:36
6F:推 hare1039: 推 实用 03/28 20:48
7F:推 sppmg: ramdisk 可用 /run/shm (tmpfs) 04/05 19:53
8F:→ sppmg: 或是 /dev/shm ,这和 /tmp 一样都是公用的,不太会有权限 04/05 19:55
9F:→ sppmg: 问题。 04/05 19:55