背景
C++は、コード規模の増分に対して指数的にコンパイル・リンク時間が増大します。
以前、C++とJavaのビルド時間比較で調査したデータid:torutk:20071104と、id:torutk:20071107から、C++のコード規模によるビルド時間の違いをまとめ直したのが以下の表です。
対象プログラム名 | 総行数 | 命令行数 | ファイル数 | ビルド時間 |
---|---|---|---|---|
ACE 5.6.1 | 307,819 | 79,930 | 1,248 | 00:10:40 |
ACE+TAO 5.6.1 | 1,066,708 | 247,391 | 2,592 | 2:35:30 |
コード規模が3倍でビルド時間は15倍となっています。
ビルド時間を短縮するアプローチ
ビルド時間を早めるための工夫がいくつか存在しています。
- キャッシュ等前回実行した結果を活用して処理時間を短くする
- 並列処理によって処理時間を短くする
開発者が自分の作業で何回もビルドを行う場合、キャッシュによる時間短縮は効果的です。しかし、ゼロから全てをビルドする(クリーンビルド)場合、キャッシュ的アプローチによる時間短縮は期待できません。そこで、並列処理によって全体のビルド時間を短縮します。
最近の計算機環境は、マルチコアによる並列処理の可能性、LAN上の複数計算機による並列処理の可能性が高まっているので、並列・分散による短縮が期待できます。
Linux/GCC環境
前回実行した結果を利用するアプローチでは、1.GNUmake、2.GCCのPCH、3.ccacheといった仕組みが利用可能です。
並列処理によるアプローチでは、1.GNUmake、2.distccと言った仕組みが利用可能です。
distccを使う
同じバージョンのGCCが入ったマシンがネットワーク上に複数ある場合、distccを使って分散ビルドを実行する環境が構築できます。
インストール
distccは、現在http://distcc.org/ の実体であるhttp://code.google.com/p/distcc/で公開されています。
Downloadsでは、ソースコードのtarballの他、i386系プロセッサ用のバイナリがRPMパッケージ形式およびdebianパッケージ形式で提供されています。本日現在このページにて提供されるバージョンは3.1で、2008年12月に載せられたものです。
また、Sourceでは、Subversionリポジトリからdistccの最新コードを取得する方法が載っています。
CentOS 5.3でのインストールの問題
- distcc-serverのRPMパッケージをインストールすると、distccサービスの起動に失敗する。
127.0.0.1 192.168.1.0/24
- IPv6で接続しようとする
IPv6を有効にしていると、distccdがIPv6で待ち受けるようです。/var/log/messagesを見ると、接続してくるクライアントアドレスが、::ffff:192.168.1.10 のようになっています。動作に支障がない環境であればそのままでかまわないと思います。
-
- distccdの--listenオプションでIPv4アドレスをバインドする
$ distccd --daemon --listen=192.168.1.1 --allow=192.168.1.0/24
- IPv6で接続してきたクライアントの許可
clients.allowではIPv4で指定しても、接続がIPv6だと許可したクライアントと見なされないかもしれません。
-
- /etc/distcc/clients.allowにIPv4射影アドレスを指定する
::ffff:192.168.1.0/120
distccサービスの稼動
distcc-serverパッケージを入れると、/etc/rc.d/init.d/distccが置かれ、chkconfig管理下になりますが、ランレベルは全てoff状態です。
# chkconfig distcc on # service distcc start
distccの利用(ノーマルモード)
プリプロセス処理が完了したソースファイルをdistccサーバに転送してコンパイル結果を受け取ります。
環境変数DISTCC_HOSTSに、distccサーバ(複数)を指定します。標準的なMakefileが用意されていれば、makeの-jオプションで並列度を指定し、コンパイラにg++の代わりにdistccを指定すればよいでしょう。慣例では、C++コンパイラのコマンド名は変数CXXで指定します。
$ export DISTCC_HOSTS='localhost red blue yellow pink green' $ make -j12 CXX=distcc :
distccの利用(pumpモード)
プリプロセス処理からdistccサーバに依頼します。ソースファイルとそのソースファイルがインクルードするヘッダーファイル群をdistccサーバに転送してコンパイル結果を受け取ります。
環境変数DISTCC_POTENTIAL_HOSTSに、distccサーバ(複数)を指定します。ノーマルモード同様標準的なMakefileが用意されていれば、pumpコマンドのオプションに、-jオプションとC++コンパイラのコマンドをdistccに指定したmakeコマンドを記述します。
$ export DISTCC_POTENTIAL_HOSTS='localhost red blue yellow pink green' $ pump make -j12 CXX=distcc :
分散コンパイル状況の把握
- クライアント側
distccmon-textコマンドで、その時点でdistccサーバ名と依頼しているファイルを表示します。
- サーバ側
/var/log/messagesに、distccdがネットワークから受け取ったログが逐次追加されています。
distccの最新ソースとRPMパッケージのビルド
distccの最新ソースはsubversionリポジトリで管理され、取得可能です。ダウンロードで用意されているVer.3.1は、2008.12の時点のものなので、それ以降の修正が必要ならば、ソースをsubversionリポジトリから取得し、ビルドします。
RPMパッケージ作成
distccのソースツリーの中に、packaging/RedHat/rpm.specがあります。specファイルからビルドするには、専用スクリプトpackaging/rpm.sh も提供されています。
- rpmbuildでエラー
%filesに、以下を追加します。rpmbuild時に警告が出ますがこれでしのぎます。
%{_libdir}/python2.4/site-packages/include_server
- サービス起動エラー
clients.allowにとりあえず127.0.0.1だけ記述すればインストール時にサービスが起動するようになります。rpmbuildのパッチファイルとして用意するのがよいでしょう。
- updateの考慮不足
distccのspecファイルには、RPMパッケージのアップデートに対する対応エラーがあります。
参考リンク
distccの簡単な使い方、pumpモードの使用方法、ccacheとpumpモードのトレードオフについて検討しているページ。