构建发布 提高编译速度的几种方法 (转)

laofo · 2013年12月11日 · 3 次阅读

1.使用 tmpfs 来代替部分 IO 读写

  1. ccache,可以将 ccache 的缓存文件设置在 tmpfs 上,但是这样的话,每次开机后,ccache 的缓存文件会丢失 3.distcc,多机器编译 4.将屏幕输出打印到内存文件或者/dev/null 中,避免终端设备(慢速设备)拖慢速度。 项目越来越大,每次需要重新编译整个项目都是一件很浪费时间的事情。Research 了一下,找到以下可以帮助提高速度的方法,总结一下。
  2. tmpfs 有人说在 Windows 下用了 RAMDisk 把一个项目编译时间从 4.5 小时减少到了 5 分钟,也许这个数字是有点夸张了,不过粗想想,把文件放到内存上做编译应该是比在磁盘上快多了吧,尤其如果编译器需要生成很多临时文件的话。 这个做法的实现成本最低,在 Linux 中,直接 mount 一个 tmpfs 就可以了。而且对所编译的工程没有任何要求,也不用改动编译环境。 mount -t tmpfs tmpfs ~/build -o size=1G 用 2.6.32.2 的 Linux Kernel 来测试一下编译速度: 用物理磁盘:40 分 16 秒 用 tmpfs:39 分 56 秒 呃……没什么变化。看来编译慢很大程度上瓶颈并不在 IO 上面。但对于一个实际项目来说,编译过程中可能还会有打包等 IO 密集的操作,所以只要可能,用 tmpfs 是有益无害的。当然对于大项目来说,你需要有足够的内存才能负担得起这个 tmpfs 的开销。
  3. make -j 既然 IO 不是瓶颈,那 CPU 就应该是一个影响编译速度的重要因素了。 用 make -j 带一个参数,可以把项目在进行并行编译,比如在一台双核的机器上,完全可以用 make -j4,让 make 最多允许 4 个编译命令同时执行,这样可以更有效的利用 CPU 资源。 还是用 Kernel 来测试: 用 make: 40 分 16 秒 用 make -j4:23 分 16 秒 用 make -j8:22 分 59 秒 由此看来,在多核 CPU 上,适当的进行并行编译还是可以明显提高编译速度的。但并行的任务不宜太多,一般是以 CPU 的核心数目的两倍为宜。 不过这个方案不是完全没有 cost 的,如果项目的 Makefile 不规范,没有正确的设置好依赖关系,并行编译的结果就是编译不能正常进行。如果依赖关系设置过于保守,则可能本身编译的可并行度就下降了,也不能取得最佳的效果。
  4. ccache ccache 用于把编译的中间结果进行缓存,以便在再次编译的时候可以节省时间。这对于玩 Kernel 来说实在是再好不过了,因为经常需要修改一些 Kernel 的代码,然后再重新编译,而这两次编译大部分东西可能都没有发生变化。对于平时开发项目来说,也是一样。为什么不是直接用 make 所支持的增量编译呢?还是因为现实中,因为 Makefile 的不规范,很可能这种 “聪明” 的方案根本不能正常工作,只有每次 make clean 再 make 才行。 安装完 ccache 后,可以在/usr/local/bin 下建立 gcc,g++,c++,cc 的 symbolic link,链到/usr/bin/ccache 上。总之确认系统在调用 gcc 等命令时会调用到 ccache 就可以了(通常情况下/usr/local /bin 会在 PATH 中排在/usr/bin 前面)。 安装的另外一种方法: vi ~/.bash_profile 把/usr/lib/ccache/bin 路径加到 PATH 下 PATH=/usr/lib/ccache/bin:$PATH:$HOME/bin 这样每次启动 g++ 的时候都会启动/usr/lib/ccache/bin/g++,而不会启动/usr/bin/g++ 效果跟使用命令行 ccache g++ 效果一样:) 这样每次用户登录时,使用 g++ 编译器时会自动启动 ccache 继续测试: 用 ccache 的第一次编译 (make -j4):23 分 38 秒 用 ccache 的第二次编译 (make -j4):8 分 48 秒 用 ccache 的第三次编译 (修改若干配置,make -j4):23 分 48 秒 看来修改配置(我改了 CPU 类型...)对 ccache 的影响是很大的,因为基本头文件发生变化后,就导致所有缓存数据都无效了,必须重头来做。但如果只是修改一些.c 文件的代码,ccache 的效果还是相当明显的。而且使用 ccache 对项目没有特别的依赖,布署成本很低,这在日常工作中很实用。 可以用 ccache -s 来查看 cache 的使用和命中情况: cache directory /home/lifanxi/.ccachecache hit 7165cache miss 14283called for link 71not a C/C++ file 120no input file 3045files in cache 28566cache size 81.7 Mbytesmax cache size 976.6 Mbytes 可以看到,显然只有第二编次译时 cache 命中了,cache miss 是第一次和第三次编译带来的。两次 cache 占用了 81.7M 的磁盘,还是完全可以接受的。
  5. distcc 一台机器的能力有限,可以联合多台电脑一起来编译。这在公司的日常开发中也是可行的,因为可能每个开发人员都有自己的开发编译环境,它们的编译器版本一般是一致的,公司的网络也通常具有较好的性能。这时就是 distcc 大显身手的时候了。 使用 distcc,并不像想象中那样要求每台电脑都具有完全一致的环境,它只要求源代码可以用 make -j 并行编译,并且参与分布式编译的电脑系统中具有相同的编译器。因为它的原理只是把预处理好的源文件分发到多台计算机上,预处理、编译后的目标文件的链接和其它除编译以外的工作仍然是在发起编译的主控电脑上完成,所以只要求发起编译的那台机器具备一套完整的编译环境就可以了。 distcc 安装后,可以启动一下它的服务: /usr/bin/distccd --daemon --allow 10.64.0.0/16 默认的 3632 端口允许来自同一个网络的 distcc 连接。 然后设置一下 DISTCC_HOSTS 环境变量,设置可以参与编译的机器列表。通常 localhost 也参与编译,但如果可以参与编译的机器很多,则可以把 localhost 从这个列表中去掉,这样本机就完全只是进行预处理、分发和链接了,编译都在别的机器上完成。因为机器很多时,localhost 的处理负担很重,所以它就不再 “兼职” 编译了。 export DISTCC_HOSTS="localhost 10.64.25.1 10.64.25.2 10.64.25.3" 然后与 ccache 类似把 g++,gcc 等常用的命令链接到/usr/bin/distcc 上就可以了。 在 make 的时候,也必须用-j 参数,一般是参数可以用所有参用编译的计算机 CPU 内核总数的两倍做为并行的任务数。 同样测试一下: 一台双核计算机,make -j4:23 分 16 秒 两台双核计算机,make -j4:16 分 40 秒 两台双核计算机,make -j8:15 分 49 秒 跟最开始用一台双核时的 23 分钟相比,还是快了不少的。如果有更多的计算机加入,也可以得到更好的效果。 在编译过程中可以用 distccmon-text 来查看编译任务的分配情况。distcc 也可以与 ccache 同时使用,通过设置一个环境变量就可以做到,非常方便。 总结一下: tmpfs: 解决 IO 瓶颈,充分利用本机内存资源 make -j: 充分利用本机计算资源 distcc: 利用多台计算机资源 ccache: 减少重复编译相同代码的时间 这些工具的好处都在于布署的成本相对较低,综合利用这些工具,就可以轻轻松松的节省相当可观的时间。上面介绍的都是这些工具最基本的用法,更多的用法可以参考它们各自的 man page。 5.还有提速方法是把屏幕输出重定向到内存文件或/dev/null,因对终端设备 (慢速设备) 的阻塞写操作也会拖慢速度。推荐内存文件,这样发生错误时,能够查看。

对 c\c++ 效果是不错的,MTK 的 AP 编译稍微优化一下 30MIN 内完成整个编译过程。如果再优化 Java 这一块,15MIN 内应该是没有问题。

其它语言的呢,比如 java, C# 等,有没有加速的方法?

make -j + ccache + distcc + 升级硬件配置(主要是 CPU/内存),这种方式很早之前在 C 语言环境下改进过。 distcc 需要和 make -j 配合使用,不然用 distcc 没有意义,这两个方式提高的速度比较明显,分布式编译需要注意的是要保证链接的依赖顺序。 ccache 是通过将头文件高速缓存到源文件之中而改进了构建性能,通过减少每一步编译时添加头文件所需要的时间来提高编译速度的。会有一些帮助,效果次于分布式编译。 distcc 用了一段时间就没有用了,主要需要把所有的数据存在一台主服务器上,而且主服务器出现问题的时候不能马上切换到从服务器上,对主服务器的备份和容量要求都很大,因为其他一些因素没有同意使用。如果用 distcc 的话,要注意考虑这些问题。

ccache + distcc + make -j + 硬件配置升级(内存/CPU)的方式,很早之前在 C 编译环境上使用过,效果不错。 distcc:要配合 make -j 使用,不然意义不大,不过 make -j 可以单独使用。这种分布式加并行编译的方法,需要注意保证链接的依赖顺序。改进效果最明显。 ccache:通过将头文件高速缓存到源文件之中来改进构建性能,减少每一步编译时添加头文件所需要的时间来提高编译速度。效果要次于分布式编译。 distcc 使用了一段时间后面没用,如果当时主服务器出现问题时,从服务器不能自动升级为主服务器,同时对主服务器的容量要求比较高,因为某些原因没有同意使用。如果有打算使用 distcc 的,这些问题需要考虑清楚。

分布式的一个问题是如果构建机器是随机选取的,那么如何增量编译?

分布式有主控服务器和节点服务器,编译结果都是保存在主控服务器,节点服务器主要是接收主控服务器的编译请求。比如有 10 个 c 文件,主控服务器在上一次编译的结果基础上判断,发现这次只改动了 2 个,那节点服务器只处理 2 个文件。 还有一个,节点服务器的编译过程使用的环境要要和主服务器一样,比如 gcc 版本,操作系统环境等。 distcc 本身并不参与编译过程,它只是编译器的一个前端,为编译加入分布式的特性。

distcc 貌似只是针对 C 和 C++ 的,对 JAVA 不起效的。 各位对 JAVA 的分布式有什么好的方案吗?

需要 登录 后方可回复。