夏休みの自由研究をした。

8月1日から始めた自由研究、今日で終わりで御座います。いや長かったぜ。スクリプト走らせてるだけだったけれど。 初日中間の記事もよろしければどうぞ。

GitHubで公開されているLinuxカーネルを落してきて、それをひたすらコンパイルしまくって時間計測をしたり、行数やら関数呼び出しやらを数えてみました。 なお、今回行なった計測は非常にてきとーなものであり、その正確性を保証するものではありません。夏休みの自由研究クオリティです。

方法とか

実験に用いたPCはIntel Core i5-4690Sで4コアの3.2GHz、メモリを24G搭載しているものです。 すべての作業をtmpfs上で行なったので、多分ディスクIOの影響はほとんど受けていません。

コンパイルは概ね次のようなスクリプトで行ないました。

yes "" | make config
/usr/bin/time -a -o "$OUTDIR/$tag" -f '%E %U %S' make -j$PARALLEL
make clean distclean
git clean -df
git reset --hard

実際はエラー処理だのなんだのが入りますのでもっと長いです。スクリプト全体も公開していますのでご興味があれば。 yes "" | make configで設定している、というのが重要な点でしょうか。エンター連打と同義ですので、初期設定のような状態になっております。 そんな適当コンパイルなので、古いバージョンはほとんどまったくコンパイル出来ませんでした。コンパイル出来るようにするのも面倒なので、本稿ではコンパイル出来なかったバージョンは飛ばしております。

サイズとコンパイル時間

コンパイル時間に影響を与えそうなものとしてまっさきに思い付くのはやっぱりソースコードの行数ですね。 グラフにすると次のような感じです。

ソースコードの行数とコンパイル時間。大体どちらも右肩上がり。

黒いのがコンパイルに掛かるCPU時間、白いのが行数です。40万行ですって、凄まじい。 なんとなく一緒に増えていっているような気がしますが、v3.4あたりとv3.14あたりで逆行しているような感じがあります。コンパイル時間と完全に比例、というわけでも無いみたい。

では今度は、出力されるbzImageのサイズとコンパイル時間。

bzImageのサイズとコンパイル時間。大体同じに見えるが、ちょっとbzImageの方がゆるやか。

ほとんど重なっていますが、黒いのがコンパイル時間(CPU時間)で、白いのがbzImageのサイズです。 かなり良い感じに一致しているように見えますが、v3.3付近はなんだか一致していない感じです。微妙です。

関数とソースコードの行数

ソースコードの規模を表わす指標として、メモリ操作関数の呼び出し回数はなかなか使えるような気がします。というわけで数えてみました。 grepを使って正規表現で数えたので、正確な数が出ているかちょっと分かりません。まあ、大幅に違うということも無いのではないかと思います。

メモリ操作関数の呼び出し回数とソースコードの行数。free系がめっちゃ多い。

kfreeばっかり呼ばれてます。次いで多いのがfree。開放ばっかりです。その次の3位がやっとkmallocで確保なのですが、4位はvfreeです。開放の嵐です。 全体的に比例しているような印象ですが、v2.6.23あたりまでkmallocが減少しているのが気になりますね。freeの独壇場です。 ゆるやかに推移していて、ソースコードの規模がなんとなく分かりそうな感じです。

次は名高きprintfとその仲間たち、それとopenfopen。メジャーな関数たちです。 出力をやるなら入力も数えようかと思ったのですが、入出力関数は色々あって手に負えなくなりそうなのでやめておきました。

printf系とopen系の呼び出し回数とソースコードの行数。printf/sprintfがすごくあばれている。

なんだかprintfsprintfが暴れています。printfはコンパイル時間と良い感じに比例していそうなのですが、残念ながら重ねたらずれてました。 少し意外だったのは、linuxカーネルってfopenを殆んど使わないんですね。高級関数に興味は無いようです。

構造体の数なんかを数えると、プログラムの規模に直結しそうな気がします。数えてみました。

構造体の数とソースコードの行数。かなりうねりながら増えている。

printfを上回る大暴れです。なんだこれ。 v2.6.28からv2.6.32までの期間、v3.6からv3.16あたりまでが特に急激に増加しているような感じです。 ソースコードの規模とはあまり関係無く増えているような印象です。

プロセス数とコンパイル時間

最後に、複数のプロセスでコンパイルした場合のコンパイル時間を比べてみました。 なお、検証している間も裏で普通に遊んでいたり作業していたりしたので、他のプロセスもばりばり走っている状況下でのテストです。厳密に測ればもっとプロセス数を増やせるはず。

カーネルバージョン別のプロセス数とコンパイル時間。CPU時間は変わらず、現実時間では変わる。

上段がCPU時間、下段が現実時間です。 当然のことなのですが、プロセスを増やすとCPU時間はむしろ微増します。プロセスの管理に手間が掛かるのでしょうね。 これに対して、現実時間ではプロセスを1から2に増やしたらコンパイル時間が約半分になりました。凄い。 更に3つ以上になると大きな差が出なくなり、頭打ちな印象です。

見づらいので、今回計測した全バージョンのコンパイル時間の平均をグラフ化してみました。

プロセス数ごとのコンパイル時間。現実時間がなんというか、指数グラフ的。

CPU時間は1プロセスの時が一番短かく、プロセスの数を増やすと少し増えます。 現実時間はプロセス数1から3までは猛烈に時間短縮になっていますが、あとはあんまり変わらない。 CPUの数の2倍である8プロセスのときが最速という結果になりました。このあとは時間が伸びていく、のかな?

プロセス数1のときは各バージョンにつき30回ととにかく回しまくったのですが、2以上は各5回ずつしかやっていないので、誤差が結構出ているような気がします。 他のプロセスもがんがん走っている状況での検証ですし。

まとめ

Linuxカーネルはどんどん成長して膨れ上がっているようです。ただ、v3.0あたりから穏かになってきているので、そのうち増えなくなるときが来るのかもしれません。 完全な比例ではないとはいえやっぱりソースの規模とコンパイル時間は比例してますから、巨大化しすぎないことを祈るばかりですね。

関数の数を数えてみるのはとても面白いことですが、単純に数えるだけでは何の参考にもならなそうです。 変更の内容と照らし合せると色々分かってより面白いのでしょうが、流石に面倒なのでやめておきます。

結論としては、コンパイル時のプロセス数は増やしすぎても大した害はなさそう。ということでしょうか。 これは結構重要な事な気がします。CPUの数+1とか言いますが、CPUの数*2くらい設定しちゃってもきっと大丈夫です。効率は上がらずとも、コンパイル時間が大幅に伸びることは無さそうです。

あともう一つ。自由研究、楽しい。以上。