カーネル、libc、gccのビルドで気持ちを軽くする

MySQLのビルドが30秒を切るという話を聞いて一度ためしてみたものの、UbuntuでやるとカーネルやGCCのアップデートがある度に手順が最初からやり直しになってめんどくさかったんだけど、さすがにDebian開発者の人だってこんな面倒な手順踏んでないで何か自動化してるだろ、というのを効果を調べながらやってみたので結果報告です。

$ git clone git://github.com/jubatus/jubatus.git
$ ./waf configure
$ time ./waf
Waf: Leaving directory `/tmp/jubatus/build'
'build' finished successfully (2m26.716s)

real 2m27.113s
user 3m12.364s
sys 0m53.899s

うん、これは遅い。C++ってのもあるけど、もうちょっと速くしたい。WAFなのでコア数を増やせばその分簡単に速くなるんだけども、そこはホラ、ノートPCで仮想マシンなのでちょっと勘弁。イカ、順を追ってやってみたでゲソ。

ccacheを使ってみる

$ export CC='ccache gcc'
$ export CXX='ccache g++'
$ ./waf build
...
real 2m12.806s
user 3m0.147s
sys 0m43.895s

ちょっと速くなったかな。と思ってccache -sしてみたら全然キャッシュしてねーの。ええええどうなってんだ?しかしccacheの説明読むと「同じファイルのビルド」はキャッシュするとか書いてある。gnu makeだとよくてwafだとダメなのかな。この先が思いやられる…

gcc

つづいてgccのビルド。

$ cd /usr/local/src/mybuild/gcc
$ apt-get source gcc-4.4-base
$ cd gcc-4.4-base
$ emacs -nw debian/rules2

    • CONFARGS += --with-tune=genericで s/generic/core2/

$ dpkg-buildpackage
$ cd ../
$ sudo dpkg -i *.deb

同じようにJubatusをビルドしてみる。

real 1m53.221s
user 2m44.082s
sys 0m44.867s

えっ。仮想マシンもあるかもしれないけど、けっこう速くなったぞ…

libc

$ cd /usr/local/src/mybuild/libc
$ apt-get source libc6
$ cd eglibc-2.11.2
$ emacs -nw debian/rules

    • BUILD_CFLAGSとHOST_CFLAGSに-march=nativeを追加する

$ dpkg-buildpackage

ビルドがコケたので後回し。#error "TLS support is required." とか言われる。ちょっとググったけど分からんかった。

linux kernel

やっぱり公式のドキュメントが一番参考になる。Ubuntuよりもよい手順だね。

$ sudo aptitude install kernel-package
$ aptitude search linux-source
...
$ sudo aptitude install linux-source-2.6.32
$ cd /usr/local/src/mybuild/kernel
$ tar jxf /usr/src/linux-source-2.6.32.tar.bz2 -C .
$ cd linux-source-2.6.32
$ make-kpkg clean
$ cp /boot/config-2.6.32-5-amd64 .config
$ make config
$ make-kpkg --rootcmd fakeroot --initrd kernel-image --revision=mybuild0
(すんごい時間かかる、がここまで簡単になってるだけでも感謝感謝)
$ cd ..
$ sudo dpkg -i linux-image-2.6.32_mybuild0_amd64.deb
(おお、VirtualBoxのGuest Additionもよしなにやってくれる)
$ sudo shutdown -r now
GRUBでは、2.6.32の無印がそれっぽかったので選択)
$ uname -a
Linux debian 2.6.32 #3 SMP Tue Dec 20 07:25:20 JST 2011 x86_64 GNU/Linux
$ ls -l /boot # => カーネルのタイムスタンプがそれっぽかったので合ってる
$ cd src/jubatus
$ ./waf configure && time ./waf build
Waf: Leaving directory `/home/kuenishi/src/jubatus/build'
'build' finished successfully (1m12.613s)

real 1m12.817s
user 2m8.164s
sys 0m14.793s

えええこんなに速くなるの???いちど再起動してるからDiskキャッシュとかがクリーンになってる影響が大きいかも…にしても、冒頭と比べて実時間で半分、ユーザ時間でも2/3になっているのでやらない手はない…とはいえ、パッケージのアップデートが頻繁なディストリ(ArchとかDebian testingとかUbuntuとか)では、パッケージがアップデートされる度にこの手順を手動でやらないし、基本的に無保証なのでオススメできない。ビルド時間の長さに困ってる人はどうぞ。という。あとはこれにdistcc加えたら最強のビルド環境なんじゃないかなあ。数十のCPUがあるマシンで-jでビルドするとか。でもMakefileの-jってたまにビルドできないから嫌なんだよね。

とまあ、こんな感じで。いろいろやってみたけど再起動直後の2分8秒が最速でした。MacBook ProのCore2上のVirtualBox上のDebian stable(2コア、2048MBメモリ)の話です。あとはこれを自動化するスクリプトを書きたいかな。sudo aptitude safe-upgradeしても大丈夫なようにする。とか。続報を待つな。それにしてもccacheってどういう仕組みで何をキャッシュしてくれるんだろう。

追記:Q. つGentoo

Gentooは何でもかんでもビルドしないといけないからエコじゃない。ほとんど使わないものでもビルドしないといけないし、実行時間がクリティカルじゃないプログラム(たとえばXとかGnomeとか、その手のGUI系やツール系)は長い時間かけてビルドして実行時間を半分にしてもその間に人間の作業がブロックすることなんてそうない。プログラミング関係のツールについては、書いてからテストして結果を知るまでのサイクルが短ければ短いほどよいので、そのサイクルの中で大きな時間を占めるといえば、当然C++だとコンパイル時間なわけだ。まあC++やめろという話ではある。

追記: aptitude hold

インストールしたパッケージはアップデート対象から外しておかないと、aptでアップデートしたときにまた更新されてもとのパッケージに戻ってしまう。他にもapt-pinningというのができるようだ(参考?)。