上班等编译的时间顺手回答下,可以说是相当切题了..
TL;DR
相当重要。
先说说我的体会,再谈一些以前看到的趣闻。
六月初刚入职一个做存储产品的部门,几万行C++,再加上相关的库等等,规模也不算小了,一次完整编译,40~60分钟不等(O0 debug模式)。
刚来的那一周一直在看代码、gdb追踪,除了最开始build了一次(为了方便调试没开优化,debug模式,没有那么多编译、链接期优化)基本不用编译代码,因此无甚感受。
后面开始写gtest、写功能的时候就开始难受了...
不是在黑我司,跟同事前辈聊他们也说这两年代码也在拆了,你看我们那两个两万多行的Server和Servertest就是分拆之后的了
分拆之后的了
之后的了
的了
。。。
他们说的没错,我能看出来很多component现在是单独自己的文件、测试,但架不住核心模块很多还是缠在一起,变成些个巨无霸的.cc文件,这就直接导致:
- compile时单个文件过大,大到编译它本身花的时间成为lock step中最长的,linker就在那等它编译完,它是显著的bottleneck
- link时这个文件对外部的引用过多,又是没法并行化,导致link time解析符号表、重定位的时间巨长
粗略估计了下,只修改这单个巨无霸文件引发一次重编译、链接的时长大约在20分钟左右,其中1/4~1/3的时间是编译,剩下大头是链接。
我思考过这是不是我电脑太烂了,16英寸mbp 2019,i7-9750H,只有6个物理核。但后来我想了想也不是,或者不完全是。
我这个增量编译的场景压根儿不吃核心的,当然确实吃主频,可cpu主频也没办法scale up得上你代码膨胀的速度啊...
所以这确实是一个问题,而且是一个相当大的问题。我很久以前曾刷到
介绍ReScript解决的痛点:...
Scalability主要体现在编译性能上,我们可以在100ms左右增量编译一个10,000文件的大型项目,这点很符合大公司的胃口,因为大公司的代码库很大,编译性能严重影响程序员的生产力。
当时还很纳闷儿,有这么夸张吗?现在我明白了,操,什么吕布骑狗。。。
实际写代码,我自己有一些治标不治本的方法或许可能提供给各位参考(为了构建得快一点,我特么真的想了很多... 而这时候熟悉构建系统就很重要了),以cmake为例
- 把不相干的target暂时注释掉,确保只构建你要测试的target
- 把优化暂时关了,一方面单文件编译优化,另一方面C++是有很多链接期优化的,这些在规模大的时候也非常耗时
- 如果功能非常独立(不依赖整个系统),可以暂时开一个单独的target,只build这一个小target,等测试得差不多了再把它加到主干target上测试
- 多clone几个仓库,编译一个的时候在其他仓库上改其他分支...
最后附上一个趣闻(不是在黑rust,我也很喜欢rust,但这真的很难绷2333):据说,TiKV 一天只有 24 次编译机会,用一次少一次
...
TiDB 中的其他节点是用 Go 编写的,当然,Go 与 Rust 有不同的优点和缺点。PingCAP 的一些 Go 开发人员对于不得不等待 Rust 组件的构建而表示不满。因为他们习惯于快速的构建-测试迭代。
在 Go 开发人员忙碌工作的同时,Rust 开发人员却在编译时间休息(喝咖啡、喝茶、抽烟,或者诉苦)。Rust 开发人员有多余的时间来跨越内心的“阴影(译注:据说,TiKV 一天只有 24 次编译机会,用一次少一次)。
