distccを用いた分散コンパイル環境の構築
カーネルを触っていると、コンパイル時間が開発のボトルネックになってしまうことがあります. この問題を解決するために、distccを用いた分散コンパイル環境を構築してみました. なお、ファイルパスなどはすべてubuntuのものとなっており、分散先のマシンのgccのバージョンは一致している必要があります.
debパッケージをインストールする
distccをdebパッケージ経由でインストールします. 今回インストールしている ccache は今回の件には直接関係はないのですが、メモリ上にコンパイル済みのオブジェクトを保持しておき、コンパイル速度を早める効果があるため、ついでにインストールしてみました.
$ aptitude install distcc ccache
設定ファイルを書く
/etc/default/distcc が設定ファイルです. このファイルに設定を書くことで、distccデーモン起動時、明記的にオプションを与える必要がなくなります.
# Defaults for distcc initscript # sourced by /etc/init.d/distcc # # should distcc be started on boot? # # STARTDISTCC="true" 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" # 同一LAN内からのコンパイル要求を通過させる ALLOWEDNETS="127.0.0.1 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" # Listen するインターフェースのIPアドレスを指定する. # 空文字にするとすべてのインターフェースでListenを行う. LISTENER="" # # You can specify a (positive) nice level for the distcc process here # # NICE="10" NICE="10" # # 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"
環境変数の設定
処理を分散させたいホスト名を、環境変数 DISTCC_HOSTS にスペース区切りで指定します.
export DISTCC_HOSTS='localhost machine1.hoge.net machine2.hoge.net'
コンパイルしてみる
- 何もない場合
$ make -j4 bzImage CC="ccache gcc" real 6m6.095s user 10m45.380s sys 1m0.672s Core 2 Duo machine 2GHz memory 2GB
- distccを用いた場合
$ make -j40 bzImage CC="ccache distcc" real 2m38.123s user 3m33.881s sys 0m43.043s Core i7 2.66GHz memory 12GB Core 2 Duo 3GHz memory 4GB x 3 Core 2 Duo 2GHz memory 2GB
素晴らしい!2倍以上の速度がでました. カーネルに限らず、大変有用ですね.
パッチの返信が返ってきた!
先日投げたパッチですが、なんと 開発者の Avi さんから返信がありました! 日本語版のユーザドキュメントしか見てなかったので知りませんでしたが、 -drive オプションなんてできていたのですねー(日本語版のユーザドキュメントを見ると、-driveオプションはまだないことがわかる). なかなか楽しい経験ができて、良かったです!
次はこういった表面的なパッチではなくて、ちゃんとしたパッチを投げていきたいです:D
gdbstub: packet reply is too long
qemu に -s オプションをつけると、qemu の gdbstub が localhost:1234 で立ち上がり、gdb 上で target remote localhost:1234 などとすると接続できますよね. しかし、kvm-88の時点で、現在の qemu では、これを利用することができません. 具体的には、以下のような挙動に陥ります:
(gdb) target remote localhost:1234 Remote debugging using localhost:1234 [New Thread 1] Remote 'g' packet reply is too long: bae1120000000000000000000000000000000000000000000600000000000000645267b9000000000100000000000000149fbcc70000000000 9fbcc70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c0e11fc00 00000008302000060000000680000007b0000007b000000d8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000000040cf16407f03000000380000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000801f0000
そして、エラー名で検索してみると、以下のスレッドが出てきます:
http://www.mail-archive.com/kvm@vger.kernel.org/msg08717.html
まとめると、
- 解決策はあるにはあるが、根本的な解決策ではない. 修正するなら、もっと根本的に変更するべきだ.
- 私の直したkvmのソースを見てもいいよ.
というわけで、修正がマージされていない様子です. かなり使える機能なので、早く修正されて欲しい気持ちはありますが、確かに保守する方はかなりしんどいのではないかと...(switch...case文で、数値直打ちで分岐してたしなぁ...w)
なお、修正版も試してみたのですが、私の環境では同様のエラーが出てしまいました. まとめると、現段階では動作しないのかな、という結論です.
KVMを用いて、カーネルイメージから直接起動したい...!(解決編) + パッチ投げた
先日の記事で、KVMからの直ブートに失敗していましたが、無事に動作しました!
/usr/local/kvm/88/bin/qemu-system-x86 -kernel /boot/vmliuz-2.6.28-15-generic -initrd /boot/initrd.img-2.6.28-15-generic -hda ~/disks/ubuntu.img -append "root=/dev/sda"
でブートします. 前回犯していた過ちは、ルートデバイスを "/dev/hda" と示していたことです.
busybox中で、
$ ls /dev/hda
としても、としても、何も出てこなかったのでおかしいなぁとは思っていましたがw
id:viverとid:kidminにアドバイス頂き、再度 ls し直してみると...
$ ls /dev/ | grep da sda sda1 sda2 sda3
と出てきました!そりゃうごきませんわ...w
というわけで、起動デバイスファイルがsdaにも関わらずhdaを指定するのは非直感的であると思ったため、以下のようなパッチを作成しました.
diff --git a/qemu-options.hx b/qemu-options.hx index c1ec976..91cd931 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -68,6 +68,13 @@ Use @var{file} as floppy disk 0/1 image (@pxref{disk_images}). You can use the host floppy by using @file{/dev/fd0} as filename (@pxref{host_drives}). ETEXI +DEF("sda", HAS_ARG, QEMU_OPTION_sda, + "-sda/-sdb file use 'file' as IDE hard disk 0/1 image\n") +DEF("sdb", HAS_ARG, QEMU_OPTION_sdb, "") +DEF("sdc", HAS_ARG, QEMU_OPTION_sdc, + "-sdc/-sdd file use 'file' as IDE hard disk 2/3 image\n") +DEF("sdd", HAS_ARG, QEMU_OPTION_sdd, "") + DEF("hda", HAS_ARG, QEMU_OPTION_hda, "-hda/-hdb file use 'file' as IDE hard disk 0/1 image\n") DEF("hdb", HAS_ARG, QEMU_OPTION_hdb, "") diff --git a/vl.c b/vl.c index 3485ce6..62d1d91 100644 --- a/vl.c +++ b/vl.c @@ -5085,6 +5085,7 @@ int main(int argc, char **argv, char **envp) initrd_filename = optarg; break; case QEMU_OPTION_hda: + case QEMU_OPTION_sda: if (cyls == 0) hda_opts = drive_add(optarg, HD_ALIAS, 0); else @@ -5096,6 +5097,9 @@ int main(int argc, char **argv, char **envp) translation == BIOS_ATA_TRANSLATION_NONE ? ",trans=none" : ""); break; + case QEMU_OPTION_sdb: + case QEMU_OPTION_sdc: + case QEMU_OPTION_sdd: case QEMU_OPTION_hdb: case QEMU_OPTION_hdc: case QEMU_OPTION_hdd:
なお、パッチの適応先は 2009/09/07 時点での最新レポジトリです. このパッチを適応することで、
/usr/local/kvm/88/bin/qemu-system-x86 -sda ~/disks/ubuntu.img
といった風に、-sdaをオプションでディスクイメージを指定することができます. その他, sdb,sdc,sdd に対応しています. なお、このパッチをKVMのMLに投げてみました. スルーされるかもしれませんが、どうなるか楽しみですw
KVMを用いて、カーネルイメージから直接起動したい...!(未解決)
というのは、需要としてはかなりありますよね. というわけで、以下のオプションを用いることでブートできる...はずなのですが!
/usr/local/kvm/88/bin/qemu-system-x86 -kernel /boot/vmliuz-2.6.28-15-generic -initrd /boot/initrd.img-2.6.28-15-generic -hda /dev/zero -append "root=/dev/hda rootdelay=90"
丁度virtio-pciを読みこんだ後に、
Begin: Loading essential drivers... done. ... Begin: Mounting for root file system ... Begin: Waiting for root file system Gave up wating for root device. Common problems: - Boot args (cat /proc/cmdline) - Check rootdelay= (did the system wait long enough?) - Check root = (did the system wait for the right device?) - Missing modules (cat /proc/modules; ls /dev) ALERT! /dev/root does not exit. Dropping to a shell!
というメッセージが出て、busyboxが起動. どうしたらいいのだろう. こういうときはドキュメントを読んでみます. まずは initramfs のドキュメント
全ての 2.6 系 Linux カーネルは gzip 圧縮された「cpio」フォーマットのアー
カイブを含んでおり、これはカーネルが起動する際に rootfs に展開されます。
展開後、カーネルは rootfs が「init」ファイルを含んでいるかどうか確認し、
あれば PID 1 ※として実行されます。by http://www.linux.or.jp/JF/JFdocs/kernel-docs-2.6/filesystems/ramfs-rootfs-initramfs.txt.html
ということは、rootfs を見つける前段階でコケてるってことですね. 次に、qemuのオプションを見てみます.
Use ‘-kernel’ to provide the Linux kernel image and ‘-append’ to give the kernel command line arguments. The ‘-initrd’ option can be used to provide an INITRD image.
When using the direct Linux boot, a disk image for the first hard disk ‘hda’ is required because its boot sector is used to launch the Linux kernel.
めぼしい情報はみつからず. ドライバを確認してみるかなぁ.
Linux カーネル 2.6.30.5 で kvm-88 のインストールが通らない
タイトルの通りです. make installしてみると、
$ make install WARNING: Loop detected: /lib/modules/2.6.30.1/extra/kvm.ko which needs kvm.ko again! WARNING: Module /lib/modules/2.6.30.1/extra/kvm.ko ignored, due to loop WARNING: Module /lib/modules/2.6.30.1/extra/kvm-intel.ko ignored, due to loop WARNING: Module /lib/modules/2.6.30.1/extra/kvm-amd.ko ignored, due to loop
となり、depmodに失敗します. この問題は、こちらのパッチを当てることで回避できます:
diff -Nur kvm-88.orig/kvm/kernel/external-module-compat-comm.h kvm-88/kvm/kernel/external-module-compat-comm.h --- kvm-88.orig/kvm/kernel/external-module-compat-comm.h 2009-07-17 20:47:08.000000000 -0300 +++ kvm-88/kvm/kernel/external-module-compat-comm.h 2009-07-17 20:55:21.000000000 -0300 @@ -845,7 +845,7 @@ #include <linux/tracepoint.h> -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) struct tracepoint; by http://patchwork.kernel.org/patch/36141/
どうも、kvm-88/kvm/kernel/external-module-compat-comm.h が、Linux 2.6.29 までしか対応していないようです. リリース時期を考えるとしょうがないでしょう. このファイルをpatchとして保存し、
$ patch -p1 -d 88 < patch
として、再度
$ sudo make install
とすると、depmod に成功します. なお、このパッチのライセンスはGPLになると思われます.
カーネルコンパイルについて
Debian系のディストリビューションにおいて、マシン間で動作するカーネルをコンパイルしようと思ったら、通常は"make-kpkg"コマンドを利用しますよね. ちょっとしたオプションを付け加えるだけで deb パッケージを作成できるため、大変便利なのですが、2つ欠点があります. それは、
- 動作する deb パッケージを作成しようと思うと、時間がかかってしょうがない.
- ディストリビューション依存である
という点です. 遅い原因は、恐らくカーネルだけでなく、モジュール/設定ファイル/バージョン情報もインストールするためでしょう. これを回避するには、やはり標準の make を用いて、カーネルだけをコンパイルするのが良いように思われます. そんなわけで、カーネルソースのルートディレクトリで実行すると、kernel+moduleのtar.gzができあがるシェルスクリプトを書いてみました. ソースは私のgithubからダウンロードすることができます. これと、kernelのイメージを作成するシェルスクリプトを用いれば、カーネルだけを換装可能な状態に持って行けるので、コンパイル時間を大幅に減らすことができます(最初からそうしろという話もあるw