看到實驗室學弟妹要開始編譯 Linux kernel
就想到去年花了很多時間在編譯上
因為每次需要先 Clean(原因不明)

雖然最後有使用 ccache 來加速,但還是需要一點時間
當時有聽說可以更進一步使用 distcc 來做分散式編譯

決定趁這次機會來看看 distcc 能加快多少時間

實驗環境

讓所有電腦使用同一個 OS 和編譯器版本會比較好

主電腦

  • OS:Ubuntu 14.04.6 LTS 32bit
  • CPU:Intel(R) Core(TM) i5-3570 CPU @ 3.40GHz (使用 4 個核心)
  • gcc
    $ gcc -v
    Using built-in specs.
    COLLECT_GCC=/usr/bin/gcc
    COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-linux-gnu/4.8/lto-wrapper
    Target: i686-linux-gnu
    Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.4-2ubuntu1~14.04.4' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-i386/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-i386 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-i386 --with-arch-directory=i386 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-targets=all --enable-multiarch --disable-werror --with-arch-32=i686 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=i686-linux-gnu --host=i686-linux-gnu --target=i686-linux-gnu
    Thread model: posix
    gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.4)
    
  • ccache
    $ which gcc
    /usr/lib/ccache/gcc
    $ ls -al /usr/lib/ccache/gcc
    lrwxrwxrwx 1 root root 16 11月  7  2018 /usr/lib/ccache/gcc -> ../../bin/ccache
    
  • 備註:
    • 是在 Windows 10 上用 Oracle VM VirtualBox 開 VM

輔助 server

  • OS:Ubuntu 14.04.6 LTS 32bit
  • CPU:Intel(R) Core(TM) i7-3770 CPU @ 3.40GHz (使用 2 個核心)
  • gcc
    $ gcc -v
    Using built-in specs.
    COLLECT_GCC=gcc
    COLLECT_LTO_WRAPPER=/usr/lib/gcc/i686-linux-gnu/4.8/lto-wrapper
    Target: i686-linux-gnu
    Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.4-2ubuntu1~14.04.4' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-i386/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-i386 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-i386 --with-arch-directory=i386 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-targets=all --enable-multiarch --disable-werror --with-arch-32=i686 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=i686-linux-gnu --host=i686-linux-gnu --target=i686-linux-gnu
    Thread model: posix
    gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.4)
    
  • distcc 安裝:
    $ sudo apt install distcc
    $ sudo vim /etc/default/distcc
    
  • 備註:
    • 是在 ESXi 上開 VM

運作流程

ccache --> distcc --> gcc

實驗項目

  • 清空 ccache,重新編譯
  • 使用 ccache,重新編譯
  • 使用 ccache + distcc,重新編譯
  • 清空 ccache,使用 ccache + distcc,重新編譯 (參數一)
  • 清空 ccache,使用 ccache + distcc,重新編譯 (參數二)

實驗結果

時間測量方式

使用 time 指令,但由於使用多核心編譯(user 會比 real 大),所以只使用 real 來比較

清空 ccache,重新編譯

指令:

$ ccache -C

$ fakeroot debian/rules clean
$ time fakeroot debian/rules binary-headers binary-generic binary-perarch

結果:

real    155m20.747s
user    325m48.648s
sys      25m35.220s
$ ccache -s
cache directory                     /home/illya/.ccache
cache hit (direct)                    16
cache hit (preprocessed)               5
cache miss                         16419
called for link                       92
called for preprocessing            2720
compile failed                         3
bad compiler arguments                 3
unsupported source language           47
autoconf compile/link                 20
unsupported compiler option           16
no input file                        610
files in cache                     49041
cache size                           2.9 Gbytes

使用 ccache,重新編譯

指令:

$ fakeroot debian/rules clean
$ time fakeroot debian/rules binary-headers binary-generic binary-perarch

結果:

real    67m41.522s
user    55m50.664s
sys     14m21.780s
$ ccache -s
cache directory                     /home/illya/.ccache
cache hit (direct)                 16436
cache hit (preprocessed)              21
cache miss                         16423
called for link                      184
called for preprocessing            5440
compile failed                         6
bad compiler arguments                 6
unsupported source language           94
autoconf compile/link                 40
unsupported compiler option           32
no input file                       1220
files in cache                     49065
cache size                           2.9 Gbytes

使用 ccache + distcc,重新編譯

指令:

$ export CCACHE_PREFIX="distcc"
$ export DISTCC_HOSTS="localhost/4 192.168.168.142/2"
$ export DEB_BUILD_OPTIONS="parallel=6"

$ fakeroot debian/rules clean
$ time fakeroot debian/rules binary-headers binary-generic binary-perarch

結果:

real    68m47.509s
user    56m17.168s
sys     15m19.432s

清空 ccache,使用 ccache + distcc,重新編譯 (參數一)

指令:

$ ccache -C

$ export CCACHE_PREFIX="distcc"
$ export DISTCC_HOSTS="localhost/4 192.168.168.142/2"
$ export DEB_BUILD_OPTIONS="parallel=6"

$ fakeroot debian/rules clean
$ time fakeroot debian/rules binary-headers binary-generic binary-perarch

結果:

real    131m58.161s
user    222m5.100s
sys      30m50.084s

清空 ccache,使用 ccache + distcc,重新編譯 (參數二)

主電腦留一顆 CPU 給非編譯工作使用 (像是 Link 之類的) 指令:

$ ccache -C

$ export CCACHE_PREFIX="distcc"
$ export DISTCC_HOSTS="localhost/3 192.168.168.142/2"
$ export DEB_BUILD_OPTIONS="parallel=5"

$ fakeroot debian/rules clean
$ time fakeroot debian/rules binary-headers binary-generic binary-perarch

結果:

real    111m59.051s
user    218m54.588s
sys      28m12.564s

結論

實驗 花費時間
清空 ccache,重新編譯 155m20.747s
使用 ccache,重新編譯 67m41.522s
使用 ccache + distcc,重新編譯 68m47.509s
清空 ccache,使用 ccache + distcc,重新編譯 (參數一) 131m58.161s
清空 ccache,使用 ccache + distcc,重新編譯 (參數二) 111m59.051s
  • 在 code 變動不多下且有 ccache 的狀況下,distcc 沒有幫助
  • 第一次編譯使用 distcc 會節省一點時間
  • 主電腦留一顆 CPU 效果會好些