distccでビルドを速くする
MeltdownとSpectreの対応でカーネルもアップデートされており、最近カーネルをビルドする回数が増えてきました。
新しいカーネルをビルドということは、ccacheは効かないため、手持ちの1番高速な自作PCでも1時間はかかります。どうにか速くできる方法を模索してみたところ、distccというのがあるみたいなので使ってみました。
distccとは?
LAN上で動作しているPCにもコンパイル作業を割り振って分散コンパイルを実現できるというものです。
LANでの転送コストがかかりますが、コンパイル作業の多重度が上がるので実際に試したところ
1時間 → 40分
まで短縮することができました。
設定はシンプルだと思うので、余っているPCがたくさんある場合は挑戦してみると楽しいですよ(=゚ω゚)ノ
distccの動作条件
gccのバージョンが同じであること。という一点だけです。
Linuxのディストリビューションが異なっても大丈夫です。x86が混在しても大丈夫なようです。
Macは微妙にgccのバージョンが同じでも内容が違うようです。VirtualBoxにUbuntuServerを構成すれば参加可能。
WindowsはWSL(Windows Subsystem for Linux)を使うかVirturlBox上にUbuntuServerを構成すれば参加可能。
(WSLはUbuntu16.04なので、gccのバージョンアップが必要です。→詳しくはWSLのgccを7.2にする。を参照してください。)
インストール
Ubuntuでインストールした手順を説明します。
①パッケージのインストール
●マスター(コンパイルの指令を出すPC)
ソースとそのビルドできる環境とdistccをインストールします。
●スレーブ(コンパイルを依頼されるPC)
build-essentialsとdistccだけ入れます。(ソースのコピーは不要。)
sudo apt-get -y install build-essentials distcc
各PCの設定
/etc/default/distcc を編集します。
★マスターもスレーブも全部設定します。
※もし、マスターはコンパイルさせないというのであればマスターは不要。
# Defaults for distcc initscript
# sourced by /etc/init.d/distcc
#
# should distcc be started on boot?
#
# STARTDISTCC="true"
# PC起動時にdistcc.serviceを起動するかどうか。
STARTDISTCC="true"
#
# Which networks/hosts should be allowed to connect to the daemon?
# You can list multiple hosts/networks separated by spaces.
# Networks have to be in CIDR notation, f.e. 192.168.1.0/24
# Hosts are represented by a single IP Adress
#
# ALLOWEDNETS="127.0.0.1"
# distccの命令を受け取るIPアドレスの範囲を指定(下記は192.168.1.1~255の場合)
ALLOWEDNETS="192.168.1.0/24"
#
# Which interface should distccd listen on?
# You can specify a single interface, identified by it's IP address, here.
#
# LISTENER="127.0.0.1"
# 自身のPCのIPアドレス(下記は192.168.1.123を指定)
LISTENER="192.168.1.123"
#
# You can specify a (positive) nice level for the distcc process here
#
# NICE="10"
# プロセスを実行する優先度を指定(優先度高 -20~19 優先度低で指定する。)
NICE="10"
#
# You can specify a maximum number of jobs, the server will accept concurrently
#
# JOBS=""
# 受け持つJOB数の上限を指定する。(CPUの全スレッド数が最大)
JOBS="4"
#
# Enable Zeroconf support?
# If enabled, distccd will register via mDNS/DNS-SD.
# It can then automatically be found by zeroconf enabled distcc clients
# without the need of a manually configured host list.
#
# ZEROCONF="true"
# ZEROCONFで環境を構築している場合trueにします。
ZEROCONF="false"
※NICE値やJOBSの値は、スレーブ側の状況によって変える必要があります。
例えば、他の人が作業中のPCを間借りする場合は低めに設定するとか、フルに活用可能であれば高めにするとか。
JOBSの値は、私が動かした感じではCPUの全スレッド数が限界のようです。
実行
①環境変数DISTCC_HOSTSの設定
DISTCC_HOSTSという環境変数に、コンパイルに使用するPCの"IPアドレス(ホスト名)/多重度"を指定します。(多重度を省略すると4になります。)
●設定例
export DISTCC_HOSTS="192.168.1.100/8 192.168.1.101/4 192.168.1.102/4 192.168.1.123/2"
DISTCC_HOSTSは優先的に処理させたいPCから並べていくと良いようです。
★マスターの指定について★
「localhost」と指定すると4より大きく指定しても何故か多重度が4までしか上がらないので注意してください。(IPアドレスまたはホスト名で指定した方がいいです。)
makeする(-jオプションは忘れずに。)
多重度は色々試しましたが、最大値は全部のPCの全スレッド数を足した数が限界のようです。
私の環境の場合はCore i7 920(4C8T)+Corei5 4350S(4C4T)+AtomZ8700(4C4T)+Core2DuoT7100(2C2T)=18です。
通常のmakeの場合
MAKEFLAGS="CC=distcc\ gcc" make -j 18
カーネルをmake-kpkgでビルドする場合。
time CONCURRENCY_LEVEL=18 MAKEFLAGS="CC=distcc\ gcc" make-kpkg -j 18 --rootcmd fakeroot --initrd --append_to_version=-hogehoge1 --revision=fugafuga2 kernel_image kernel_headers
モニタリングの仕方
各PCでどのようにコンパイルしているかモニタリングできます。多重度を設定する際の参考にもなります。
GUIは「distcc monitor」というパッケージがあります。
起動すると下記の画像のように、各PCでコンパイルが動いていることを確認できます。
CUIの場合はdistccmon-textコマンドを使います。
補足
【補足①】速くするコツ
私の持っているPCは、速度も構成もバラバラなので参考になるかどうか分かりませんが、、、
・CPUクロックが高ければ、古くても役に立つ。(AtomでもCore2でも)
・LANは有線の方がレスポンスが上がる。
・スレーブはHDDの速さにはあまり依存しない。
・マスターのPCが遅いとボトルネックになりやすい。(CPU,HDD,LAN共に)
特にビルドに使うフォルダはなるべく読み書きが速いSSDに置いた方がいいです。
【補足②】余っているWindowsタブレットの有効利用も手
Atom Z3740、Z3735F、Z8350などの格安タブレットやStickPCを購入して使わなくなった方も多いのではないでしょうか。
これらのCPUは4コアあるので使ってみたのですが、遅いなりに助けにはなっている感じがします。
Windows10Home(32bit)ということが多いでしょうが、BayTrailとCherryTrailは実は64bit対応なのでVirtualBoxを使うと64bitのOSをゲストOSに使えます。
●VirtualBoxの設定
build-essentialとdistccを入れて使うぐらいであればディスクは10GBでも動きます。
物理メモリが2GBの場合、900MBぐらいが上限です。
CPUはお好みですが、思い切って4でも行けました。
ちなみにAtom Z8700やZ3795など、クロックが高いマシンは思ったより速く処理が可能です。
【補足③】ZeroConfとは?
ネット上にあるデーモンを自動的に(?)検出して利用できる仕組みのようです。
distccだと、ネット上にあるdistcc.serviceが動いているスレーブPCを見つけて割り振る感じでしょうか。
DISTCC_HOSTSを設定しなくていい分楽ですね。
あと、スレーブPCの構成がコロコロ変わる場合にも有効でしょう。
時間ができたら挑戦しようと思います。
【補足④】エラー時の振る舞い
スレーブが途中で接続が切れた場合は、エラーが起きたジョブは「localhost」に割り当てられるようになります。突然スレーブが固まったなどのトラブルがあっても、マスターさえ動いていればコンパイル作業は継続されます。
【補足⑤】WSLでdistccdを動作させる
WSLではsystemdが動かないので、手動でスクリプトを実行します。
sudo /etc/init.d/distcc start
実行した時に下記のWarningが出ますが動いています。(Windowsではnice値(プロセス優先度)は指定できません。)
* Starting Distributed Compiler Daemon: distccd
distccd[31] (main) Warning: nice 10 failed: Operation not permitted
[ OK ]
LinuxとWSLの混在環境でのエラー
私の環境(Ubuntu+WSL)でVimをビルドしてみた際に下記のエラーが出ました。(Ubuntuだけの場合は出ません。)
/usr/bin/ld: objects/message.o: relocation
R_X86_64_32 against `.rodata.str1.8' can not be used when making a shared object。
-fPIC を付けて再コンパイルしてください。
このエラーが場合は下記のように「-fPIC」オプションを付けて実行すればコンパイルが通ります。
MAKEFLAGS="CC=distcc\ gcc CFLAGS=-fPIC" make -j 18
おわりに
古いPCの有効活用にもdistccは使えると思います。成功すると面白いのでビルド時間を少しでも短くしたい方は挑戦してみてください。