admin管理员组

文章数量:1646249

超级加速!ccache让编译速度飞起来

  • 一、关于ccache
  • 二、ccache的安装和配置
    • 2.1、安装ccache
    • 2.2、ccache的配置选项和参数
  • 三、ccache的使用方法
  • 四、ccache的实际工程表现
    • 4.1、ccache在Makefile的工程应用
    • 4.2、ccache在CMake的工程应用
  • 五、ccache的局限性
  • 六、总结

一、关于ccache

ccache是“compiler cache”的缩写,是一个gcc/g++的c语言编译器缓存。它加快了编译速度,特别是对于重复编译相同文件的情况,主要是通过缓存以前的编译并检测是否相同来重新编译。

ccache 是免费软件,发布于 GNU 通用公共许可证(版本3或更高版本)。

ccache的作用和优势:

  1. ccache会将每次编译的输出结果缓存起来 ,当下次遇到相同的编译任务时,会直接使用缓存中的结果,而不需要重新编译,从而节省时间。

  2. 通过避免重复编译相同文件,ccache可以显著加快编译过程,尤其是对于大型项目或需要频繁修改和构建的代码来说,效果尤为明显。

  3. 由于避免了大量的重复编译操作,使用ccache能够减轻系统的负担,降低了CPU和磁盘等资源的占用。

  4. ccache可以用于任何支持C、C++和类似语言的编译器。

简言之,ccache通过在单个gcc编译命令级别对本次编译产物进行压缩并存储到缓存目录中。下次发现相同编译命令且未修改源文件时,直接使用缓存中的结果,省去编译时间,从而优化了编译时长。在项目工程中,一次代码修改通常只涉及少量源文件,因此ccache只需重新编译修改的部分,而未变动的源文件可直接使用缓存,进一步优化了编译时长。

CCache加速编译的流程图原理示意图:

命中缓存 未命中缓存 开始编译请求 CCache检查缓存 返回缓存中编译结果 结束编译 编译源代码 存储新的编译结果到缓存

这个流程图描绘了CCache在编译过程中的工作原理:

  1. 接收到开始编译的请求。
  2. CCache检查是否有现有的编译缓存可以复用。
  3. 如果命中缓存(即预编译的结果可用),则返回缓存中的编译结果。
  4. 如果没有命中缓存,则进行实际的源代码编译。
  5. 将新的编译结果存储到缓存中,用于后续可能的命中。
  6. 编译结束。

二、ccache的安装和配置

2.1、安装ccache

ccache可以通过apt直接安装,也可以通过源码安装。

(1)通过apt直接安装:

# 先更新apt包管理器的软件包列表
sudo apt update
# 进行ccache的安装
sudo apt install ccache

(2)开源软件的迭代较快,apt源并不能实时同步最新版本,可通过源码编译安装的方式,获取最新版本。通过源码安装:

  1. 从ccache的官方网站下载最新版本的ccache源代码压缩包。比如Linux X86-64版本:wget https://github/ccache/ccache/releases/download/v4.9/ccache-4.9-linux-x86_64.tar.xz

  2. 将下载的压缩包解压缩到一个目录。比如tar -zxvf ccache-4.9-linux-x86_64.tar.xz

  3. 进入解压后的ccache源代码目录并使用以下命令开始编译和安装ccache:

    ./configure
    make
    sudo make install
    

查看ccache版本:

ccache -V 

2.2、ccache的配置选项和参数

ccache具有丰富的配置选项和参数,可以通过配置文件或命令行参数进行设置。

配置文件选项:

  1. max_size:指定ccache缓存目录的最大尺寸,默认为 5GB。
  2. cache_dir:指定ccache缓存的目录位置。
  3. umask:设置以八进制表示的缓存文件的umask值。
  4. compression:配置文件压缩级别,可以是 0(无压缩)到 9(最大压缩)。
  5. direct_mode:启用或禁用直接模式,用于在多个机器上共享缓存。
  6. sloppiness:用于控制ccache的宽松模式,可以包括文件时间戳宽松、编译器错误宽松等选项。

命令行参数:

  1. -c, --cleanup:清理过期的缓存文件。
  2. -M, --max-size=SIZE:设置ccache缓存目录的最大尺寸。
  3. -s, --show-stats:显示ccache的统计信息。
  4. -z, --zero-stats:将ccache的统计信息清零。
  5. -C, --clear:清除ccache的全部缓存。

其他常用参数:

  1. --config:手动指定ccache的配置文件。
  2. -E, --set-config=CONFIG:设置指定的配置选项。
  3. -F, --cleanup-timeout=SECS:设置清理过期缓存文件的超时时间。
  4. -I, --skip-includes:忽略包括导入的文件。
  5. -S, --skip-sloppiness:禁用宽松模式。

使用ccache跑一个工程的时候,如果不注意标准输出内容,就比较难判断本次编译是否使用了ccache。ccache提供了查询缓存命中能力更好的判断当前工程有没有使用ccache:

ccache -s -v

输出:

root@hecs-274489:~/workspace/learning# ccache -s -v
Summary:
  Cache directory:             /root/.cache/ccache
  Primary config:              /root/.config/ccache/ccache.conf
  Secondary config:            /etc/ccache.conf
  Stats updated:               Thu Jan 18 17:51:21 2024
  Hits:                           1 /    2 (50.00 %)
    Direct:                       1 /    2 (50.00 %)
    Preprocessed:                 0 /    1 (0.00 %)
  Misses:                         1
    Direct:                       1
    Preprocessed:                 1
  Uncacheable:                    7
Primary storage:
  Hits:                           2 /    4 (50.00 %)
  Misses:                         2
  Cache size (GB):             0.00 / 5.00 (0.00 %)
  Files:                          2
Uncacheable:
  Called for linking:             5
  Unsupported source language:    2

可以详细的看到:

  • 缓存存放目录:Cache directory。
  • 缓存配置文件路径:Primary config。
  • 最近一次使用缓存的时间:Status updated。
  • 缓存总体命中的情况:
    • Hits表示命中缓存;
    • Misses表示未命中缓存,但是生成了缓存,下次可以命中。
  • 缓存目录使用大小:Cache size。

三、ccache的使用方法

在实际工程当中,可能是由Makefile或者CMake进行管理编译,不可能手动修改所有的编译命令,我们应该将ccache使用上呢?

这时候需要对编译工具和环境进行相应的配置。不同编译环境下使用ccache的方法:

(1)在Makefile中使用ccache。打开Makefile文件,找到编译命令的位置。将编译命令前加上ccache,例如:

CC=ccache gcc
CXX=ccache g++

(2)在CMake中使用ccache。在CMakeLists.txt中设置CMAKE_CXX_COMPILERCMAKE_C_COMPILER变量为ccache,例如:

set(CMAKE_CXX_COMPILER "ccache g++")
set(CMAKE_C_COMPILER "ccache gcc")

(3)在Autotools中使用ccache。

  1. 在configure.ac或configure.in文件中添加AC_PROG_CCACHE宏。
  2. 运行autoreconf --install命令重新生成configure脚本。
  3. 运行./configure脚本时ccache将被自动启用。

(4)在Visual Studio中使用ccache

  1. 安装并配置ccache工具。
  2. 在Visual Studio中设置包含ccache的路径。
  3. 在项目中的编译器设置中选择ccache作为编译器。

最为常用的方式是:无论是在Makefile还是Cmake都可以通过声明环境变量的方式来使用ccache。

# 在构建脚本中增加
export CC="ccache gcc"
export CXX="ccache g++"
# 再进行编译make/cmake 
make 
# cmake: 
cmake -B output && cmake --build output

为了在日常编译中可以轻松使用ccache,可以将ccache伪装成编译器,比如:

# 找到ccache的安装路径
which ccache 
# 安装实际路径为: /usr/bin/ccache 
# 创建软连接,将ccache伪装成g++编译器
ln -s /usr/bin/ccache g++
# 使用伪装后的g++ 进行编译
./g++ -c hello.cpp -o hello.o

小试牛刀:使用ccache编译一个简单的cpp。

(1)没有使用ccache的编译:

root@hecs-274489:~/workspace/learning# time g++ -c test.cpp -o test.o

real    0m0.466s
user    0m0.385s
sys     0m0.080s

(2)首次通过ccache 进行编译:

root@hecs-274489:~/workspace/learning# time ccache g++ -c test.cpp -o test.o

real    0m0.538s
user    0m0.477s
sys     0m0.062s

(3)二次通过ccache 进行编译:

root@hecs-274489:~/workspace/learning# time ccache g++ -c test.cpp -o test.o

real    0m0.012s
user    0m0.005s
sys     0m0.005s
编译方式编译时长
原始构建0.466s
使用ccache首次构建0.538s
使用ccache二次构建0.012s

结论:首次使用ccache会对编译命令做缓存处理需要花费一些耗时,结果显示使用ccache首次编译时长 > 原始编译时长 >> 使用ccache二次编译时长

四、ccache的实际工程表现

实验的硬件环境信息:

# lshw -short
H/W path        Device     Class          Description
=====================================================
                           system         OpenStack Nova
/0                         bus            Motherboard
/0/0                       memory         96KiB BIOS
/0/400                     processor      Intel(R) Xeon(R) Gold 6161 CPU @ 2.20GHz
/0/1000                    memory         4GiB System Memory
/0/1000/0                  memory         4GiB DIMM RAM
/0/100                     bridge         440FX - 82441FX PMC [Natoma]
/0/100/1                   bridge         82371SB PIIX3 ISA [Natoma/Triton II]
/0/100/1/0                 system         PnP device PNP0b00
/0/100/1/1                 input          PnP device PNP0303
/0/100/1/2                 input          PnP device PNP0f13
/0/100/1/3                 storage        PnP device PNP0700
/0/100/1/4                 communication  PnP device PNP0501
/0/100/1.1                 storage        82371SB PIIX3 IDE [Natoma/Triton II]
/0/100/1.2                 bus            82371SB PIIX3 USB [Natoma/Triton II]
/0/100/1.2/1    usb1       bus            UHCI Host Controller
/0/100/1.2/1/1  input5     input          QEMU QEMU USB Tablet
/0/100/1.3                 bridge         82371AB/EB/MB PIIX4 ACPI
/0/100/2        /dev/fb0   display        GD 5446
/0/100/3                   network        Virtio network device
/0/100/3/0      eth0       network        Ethernet interface
/0/100/4                   bridge         QEMU PCI-PCI bridge
/0/100/5                   bridge         QEMU PCI-PCI bridge
/0/100/5/1                 storage        Virtio block device
/0/100/5/1/0    /dev/vda   disk           42GB Virtual I/O device
/0/100/5/1/0/1  /dev/vda1  volume         39GiB EXT4 volume
/0/100/6                   bridge         QEMU PCI-PCI bridge
/0/100/7                   bridge         QEMU PCI-PCI bridge
/0/100/8                   bridge         QEMU PCI-PCI bridge
/0/100/9                   bridge         QEMU PCI-PCI bridge
/0/100/a                   bridge         QEMU PCI-PCI bridge
/0/100/b                   bridge         QEMU PCI-PCI bridge
/0/100/c                   communication  Virtio console
/0/100/c/0                 generic        Virtual I/O device
/0/100/d                   generic        Virtio memory balloon
/0/100/d/0                 generic        Virtual I/O device
/1              input0     input          Power Button
/2              input1     input          AT Translated Set 2 keyboard
/3              input3     input          VirtualPS/2 VMware VMMouse
/4              input4     input          VirtualPS/2 VMware VMMouse

工程项目:stressapptest和muduo。

4.1、ccache在Makefile的工程应用

工程项目:stressapptest。

原始直接make:

real    0m11.902s
user    0m10.161s
sys     0m1.656s

找到src/Makefile中的CCCXX,并将它们更改为:

CC = ccache gcc
CXX = ccache g++

ac_ct_CC = ccache gcc
ac_ct_CXX = ccache g++

make clean后使用ccache首次编译:

real    0m13.912s
user    0m11.942s
sys     0m1.892s

make clean后使用ccache二次编译:

real    0m0.444s
user    0m0.317s
sys     0m0.125s
编译方式编译时长
原始构建11.902s
使用ccache首次构建13.912s
使用ccache二次构建0.444s

可以看到,使用ccache二次编译的速度提升了96%左右。

4.2、ccache在CMake的工程应用

工程项目:muduo。

muduo的依赖项安装:

#安装cmake
sudo apt-get install cmake 
#安装boost
sudo apt-get install libboost-dev libboost-test-dev
#三个非必须的依赖库:curl、c-ares DNS、Google Protobuf  (安装之后cmake会自动多编译一些示例)
sudo apt-get install libcurl4-openssl-dev libc-ares-dev
sudo apt-get install protobuf-compiler libprotobuf-dev

原始直接cmake:

time ./build.sh

执行时间:

real    4m36.686s
user    4m2.975s
sys     0m33.327s

清除之前的构建,除了在CMakeLists.txt中添加ccache,也可以在构建脚本中增加如下的语句(比如在build.sh中):

export CC="ccache gcc"
export CXX="ccache g++"

使用ccache首次编译:

real    5m14.653s
user    4m33.229s
sys     0m41.105s

清除上次构建内容后后使用ccache二次编译:

real    0m34.869s
user    0m22.974s
sys     0m10.292s
编译方式编译时长
原始构建4m36.686s
使用ccache首次构建5m14.653s
使用ccache二次构建34.869s

可以看到,使用ccache二次编译的速度提升了87%左右。

五、ccache的局限性

ccache会自动清理较长时间未访问的缓存文件,使用LRU(最近最少使用)算法,以确保缓存文件总大小不超过指定的缓存大小。不要手动删除缓存目录下的文件,因为这可能会导致缓存丢失。

如果默认的缓存目录会占用过多磁盘空间,可以通过在/etc/profile中增加ccache的环境变量配置来改变缓存目录,并使其持续生效,从而解决磁盘空间不足的问题。

# 将ccache的缓存目录设置为了/home/fly/ccache
vim /etc/profile
# 追加环境变量
export CCACHE_DIR=/home/fly/ccache
# 让环境变量生效
source /etc/profile

ccache的局限性与不足:

  1. ccache使用本地磁盘缓存编译结果,缓存大小受限于本地磁盘空间,如果缓存空间不足,会导致编译结果被清理,从而影响编译速度。

  2. ccache的缓存命中率取决于项目中文件的变化情况,如果项目文件频繁变动,将降低缓存命中率,无法发挥其应有的性能优势。

  3. ccache只能用于本地编译环境中,无法在分布式编译环境中发挥作用。

  4. ccache只能缓存完整的编译结果,对于中间生成的对象文件等无法实现缓存。

  5. ccache主要是为支持标准构建系统而设计的,对于非标准构建系统的支持有限。

新的编译加速技术对ccache的影响:

  1. 新的编译加速技术提供更有效的缓存机制,提高缓存命中率,减少重新编译的次数。这将提高ccache的效率并增强其在编译加速中的地位。

  2. 一些新的编译加速技术支持更好的多核并行编译,使得编译过程更加快速。这减少ccache在编译速度方面的优势,因为编译速度本身已经得到改善。

  3. 新的技术会涉及构建缓存,即缓存构建过程中产生的中间输出,使得编译可以更快地进行。而ccache目前主要关注源码层面的缓存。

六、总结

对于重复编译,无论是单命令编译,还是实际工程编译,使用ccache构建速度都极大的提升了编译效率。

ccache通过缓存已经编译过的对象文件,可以大大减少重复的编译工作。帮助减轻大型项目的编译负担,节约开发过程中的计算资源和成本。

本文标签: 飞起速度ccache