More info...

2011-04-18

MySQL 5.5をわずか30秒足らずでコンパイルするためのテクニック

べっ・・・別にソースコードなんて自分でコンパイルしないんだからねッ!!などと言わずにまず聞いていただきたい。30秒でMySQLのコンパイルが出来るというこの事実を。最近、細々とビルド時間の短縮に取り組んでいたのだが、正直ここまで爆速になるとは思わなかった。今日はビルド時間短縮のためのテクニックを紹介するので、是非皆さんも参考にして、快適ビルド生活を送って頂きたい!!

自己ベストは26.262秒

マシンの状態や負荷の状況によって多少ビルドにかかる時間は前後してしまうのだが、これまでの自己ベストはなんと26.262秒。平均すると30秒ぐらい。以前は1分を切ることがなかったのだが、今ではなんとその半分でビルドが出来てしまう。これは純粋にmakeをするのにかかった時間であり、cmake(MySQL 5.5以降)やconfigure(MySQL 5.1以前)にかかる時間は除いてある。だがそれでも速い。トレビア〜〜〜ン。

以下はビルドの様子をキャプチャしたものである。キャプチャを動かしながらなのでいつもより多少時間がかかってしまっているが、それでも31秒台である。自分でコンパイルした時と見比べてみて欲しい。



特別速いマシンを利用しているだろって?いやいや、そんなことはない。俺のマシンは以前ブログで紹介したDELL社製のM4500である。多少重くて性能重視のマシンだとは言え、一般的なメーカーの、しかも一世代前のCPU(Core i7 Q740)を積んだごく普通のマシンである。OSはエントリにも書いた通りXubuntuだ。ハードウェアは一切変更はない。以前と違うのはOSとソフトウェア、しかも種類が違うのではなくチューニングしただけなのだ!

並列コンパイル

基本中の基本だが、makeを実行するときは-jオプションでジョブを並列化すると良い。すると並列でコンパイルが実行されるので、時間が短縮される。筆者の場合、Core i7 Q740は4コアで、かつHyper Threadingに対応しているため、仮想的に8つのCPUコアがOSから認識されている。なのでmake -j 8というように、8並列でmakeを実行している。あまりスレッド数を増やしてもスラッシングが起きるだけなので、物理または仮想CPUコア数に合わせてジョブの数を調整すると良いだろう。

ccache

コンパイルの高速化には、ccacheの利用が欠かせない。まだccacheをインストールしていなければ、"sudo apt-get install ccache"でインストールしておこう。環境変数を次のように設定しておけば、コンパイル時にccacheを利用するようになる。

export CC='ccache gcc'
export CXX='ccache g++'

カーネルをコンパイル

もし、最近のアーキテクチャのCPUを搭載したマシンを使っているにも関わらず、デフォルトのカーネルを使っているとしたら、今直ぐカーネルを自分でコンパイルしたものに置き換えることをお勧めする。その日からすべてが変わるだろう。自分でコンパイルすると言っても、何も特別なことをする必要はない。Ubuntuの公式ドキュメントに載っているような、ごく有り触れた手順でコンパイルするだけでOKだ。なら何故そんなに違うかって??それは、デフォルトのカーネルが新しいCPUに最適化されてないからである。

デフォルトのカーネルは、古いマシンでも利用できるよう、generic x86_64向けのコードで配布されている。インテル系のCPUは世代が新しくなるごとに命令が追加されたりするのが常であるが、generic x86_64では、そのような新しい命令を使わずに実行するようになっている。つまり、新しいCPUが本来持っている性能を発揮できないのである。

互換性を保つため、generic x86_64用のバイナリを生成するのは、汎用的なバイナリを配布するために一般的に行われることである。だからそれ自体は悪いことではないのだが、再配布するつもりがない、自分のマシンだけで利用するバイナリを生成するのであれば、genericではなくちゃんと最新のCPU向けに最適化するべきなのだ。持っている新命令をわざわざ使わないなんてことは、もったいないこと極まりない話である。なら使え!使っちまえってんだチクショウッ!!てなわけで、多少面倒だがカーネルは自分でコンパイルしたものを使おう。そうするだけで、ソースコードのコンパイルだけでなく、すべての操作が高速化されるからだ。フリーソフトウェア万歳!!オープンソース万歳!!である。

カーネルの再構築において、新しい世代のCPUに最適化したコードを生成するには、make menuconfigにて設定を行う。カーネルバージョン2.6.35の場合は「Processor type and features」を開き、「Processor family」において「Core 2/newer Xeon」を選択しよう。筆者は、さらに「Maximum number of CPUs」を8に、「Numa Memory Allocation and Scheduler Support」をOFFにしている。実際、筆者のマシンは先に述べたように8コアだし、Numaアーキテクチャではないからだ。

カーネルは数千万行からなる巨大なプログラムである。カーネルのコンパイルにはかなりの時間がかかるので、夜寝る前にでも仕掛けておくと良いだろう。

libcをコンパイル

カーネルをコンパイルするのと同じノリだが、ほぼ全てのプログラムが利用するlibcを自分でコンパイルするのもかなり効く。カーネル以外のパッケージは、作業ディレクトリを掘って次のような手順で作業を行えばオッケーだ。

shell> sudo apt-get build-dep libc6
shell> apt-get source libc6
shell> cd eglibc*
shell> debchange -i # 特に編集せず保存すればOK
debian/rulesファイルを編集
shell> debuild -uc -us
debパッケージをインストール

ポイントはdebian/rulesファイルの編集だが、BUILD_CFLAGSとHOST_CFLAGSに-march=nativeを追加すればOKだ。libc6もほとんどのアプリケーションの動作に影響を及ぼすので、ソースコードのコンパイルだけでなく日々の作業が快適になる。

GCCをコンパイル

当然ながら、コンパイラ自身を最適化するというのも有効だ。作業自体は上記のlibcをコンパイルするときと同じ流れだが、GCCの場合、取得するパッケージ名はgcc-4.4となる。ligcの場合の手順ではdebian/rulesを編集したが、こちらはdebian/rulesではなくdebian/rules2を編集する。「CONFARGS += --with-tune=generic」という行で、genericをcore2に書き換えよう。

ちなみに、GCCのコンパイルはとても時間がかかる。カーネルよりもかかる。PCを使っているときにビルドを開始すると後悔することになるので気をつけよう。

その他のプログラムもついでにコンパイル

ちょっと話を脱線して、自前でdebパッケージをコンパイルしなおす方法についてもう少し触れておこう。

自前でdebパッケージを構築する手順は、基本的にはlibcのところで紹介したものと同じである。ただし、libcやGCCではrulesファイルを編集したが、それはこれらのパッケージが特別だからであり、コンパイラオプションを指定するだけであれば、~/.config/dpkg/buildflags.confという設定ファイルに次のように書いておけば十分である。rulesファイルをいちいち編集する必要はない。

SET CFLAGS -m64 -march=native -g -O3
SET CXXFLAGS -m64 -march=native -g -O3

コンパイラオプションは好みに応じて変えると良いだろう。cmake以外はソースコードのビルドには関係はないけど、よく使うライブラリやソフトウェアを自前でコンパイルしておくとPC利用時の全体的な体感速度が向上する。寝る前にでもコンパイルを仕掛けておけば、翌日からPCライフが快適になるだろう。筆者は次のパッケージを自前でコンパイルしている。

  • cmake
  • xorg-server
  • libgtk2.0
  • compiz-core
  • libqt4-core
  • emerald

--without-embedded-server

さらに少し横道に逸れるが、MySQL 5.5では組み込み版のサーバーであるlibmysqldがデフォルトでは無効化されている。libmysqldはめったに使わないのに構築は非常に時間がかかるので、これは嬉しい変更なのだが、逆に言うとMySQL 5.1まではデフォルトではlibmysqldも生成されてしまうのである。最新の安定版はMySQL 5.5であるとは言え、まだまだMySQL 5.1を現役で利用されている人も多いことだろう。MySQL 5.1でlibmysqldを生成しないようにするには、configureコマンド実行時に、--without-embedded-serverオプションを指定しよう。それだけで、4割程度時間の短縮になる。

その他の注意点

ソースコードのコンパイルは、とてもたくさんのCPUリソースを使う作業である。そのため、CPUをよく使うアプリケーションをコンパイル中に使うと、リソースの競合が起きてコンパイルもアプリケーションもスローダウンしてしまうことがある。よって、そのようなアプリケーションはコンパイル中は使わないか、できれば終了させておくと良いだろう。

特に影響が大きいと感じるのはFirefoxだ。予めFirefoxを終了しておくと、コンパイルがよりスムーズに進むように感じる。

さらに極端なことを言えば、Xを終了してGUIのためにCPUリソースを使わないようにしておくとナイスだ。特に俺のようにCompizを使って3Dグリグリなデスクトップを使っていたりすると、消費するCPUリソースは馬鹿にならない。Xを終了させてRescueモードでログインすることで、コンパイルがさらに高速化することだろう。

小技であるが、コンパイル時の標準出力を抑えるのも割と効く。makeの出力を/dev/nullにリダイレクトしても良いが、nohupコマンドなどを使ってファイルに落としておくだけでもかなり違う。ファイルにリダイレクトしておけば、コンパイルエラーが起きたときに後から内容を確認することが可能だし、コンパイルの様子が見たければtail -fで追いかけることも可能だ。

さらなる高速化に向けて

筆者のマシンは7200rpmのHDDを搭載しているのだが、SSDを搭載するともう少し記録が伸びるかも知れないと考えている。が、予算の都合上、それは今のところ見送っている。

現在使用しているGCC 4.4はCore2世代のアーキテクチャの拡張命令までしか対応していないが、GCC 4.6はCore i7の拡張命令にも対応しており、将来的にはこのバージョンを使うことで、今よりも高速なバイナリを生成できるようになるかも知れない。

まとめ

今回思い知ったのは、フリーソフトウェアならびにオープンソースのありがたさである。ソースコードがなければ、そしてそのソースコードを自由に理由して良い権利がなければ、今回のようにシステムをコンパイルし直して高速化するなどということは出来ないだろう。「だったら全部自分でコンパイルすればいいんじゃないか?」と思うかも知れない。だが、ソフトウェアのコンパイルにはまだまだ時間がかかる。大規模なソフトウェアでは数時間〜数日かかるような場合もあるだろう。従って、OSにインストールされている全てのソフトウェアを自分でコンパイルするのは、そのための手間と効用のバランスを考えると、現時点ではあまり現実的ではないというのが筆者の意見だ。従って、自分の目的に照らし合わせ、要となるソフトウェアまたはライブラリだけを自分でコンパイルするなどをして高速化を図るのが賢い選択だ。

将来的に、もっとマシンがパワフルになって、コンパイル時間がぐっと短縮されれば、手間と効用のトレードオフが逆転し、Gentoo Linuxのように全てを自分でビルドするのがデフォルトだ!というOSが理想郷になるかも知れない。全てを自分でコンパイルする世界が到来するには、デバイスドライバやコーデックのソースコードが全て公開されている必要がある。そのためにも、筆者はフリーソフトウェア運動、オープンソース運動をもっと盛り上げる一員でありたいと思う。

0 件のコメント:

コメントを投稿