OS毎のシステムコール実行性能 〜 その1
Mercurial のテストセット ("make tests
") を複数の環境で実行したところ、ほぼ同一性能の CPU 上での実行にも関わらず、Mac OS X 上での実行では、仮想環境上の Linux での実行よりも、大幅に時間を要することが確認できました。
仮想環境上の実行ではクロック情報の精度がよろしくないので、計測主体が仮想環境上にあるベンチマーク結果はあまり信用できない、ということを考慮に入れても、明らかに体感できるレベルで遅い(分単位の所要時間差)ので、単純に「仮想環境上の計測誤差が、良い方向に出ている」と片付けるわけにも行きません。
そこで、幾つかのシステムコールに関して、OS 間での実行性能を計測してみることにしました。
元々の比較対象が「Mercurial のテストセット」なので、比較的影響が高そうな、以下のシステムコールを計測対象にします。
- fork/exec 等によるプロセス生成
テスト手順スクリプトを元に、コマンド起動〜結果比較を実施しているため - lstat/fstat 等によるファイルシステムアクセス
「ファイルの履歴管理」という性格上、ファイルシステムアクセスの全体に占める比率は高い筈
各 OS の実行環境は以下の通りです。個人的な趣味の関係で、Solaris も計測対象に加えています(笑)。
---- | MacOSX | Linux | Solaris |
---|---|---|---|
OS 詳細 | Lion (10.7.5) | Debian (2.6.32-5) | OpenIndiana (151.a2) |
CPU | Core i5 2415M (2.3GHz) | Core i5 2410M (2.3GHz) | |
利用可能コア/スレッド数 | 4 | 2 | |
メモリ | 16GB | 2GB | |
インストール形態 | ベアメタル | 仮想環境 (VirtualBox on Windows7 64bit) |
Core i5 2415M と 2410M は、ターボブースト時のクロックが前者の方が若干高い可能性がある以外は、整数演算に関しては同一性能と考えて良い筈です。
- その1: fork, execve の性能計測
- その2: vfork の性能計測
- その3: fstat, lstat の性能計測
- その4: getpid, gettimeofday の性能計測
- その5: time, umask の性能計測
- その6: まとめ
execve の性能比較
execve
システムコールの性能比較として、以下の様なプログラムを実行してみます。
- 引数文字列を整数に変換
- 0 なら終了
- それ以外なら、1 を減じた数の文字列を引数に、自分自身を
execve
繰り返し回数 0x10000 = 約6万4千の実行に要する時間 (単位:秒) は、以下の様な結果でした。
---- | MacOSX | Linux | Solaris |
---|---|---|---|
execve | 157.19 | 22.02 | 39.41 |
fork の性能比較
fork
システムコールの性能比較として、以下の様なプログラムを実行してみます。
- 引数文字列を整数に変換
- 0 なら終了
- それ以外なら、
fork
を実施 - 子プロセスは、即時
_exit
- 親プロセスは、子プロセスを wait
- 指定整数から 1 を減じて、手順2から繰り返し
繰り返し回数 0x10000 = 約6万4千の実行に要する時間 (単位:秒) は、以下の様な結果でした。
---- | MacOSX | Linux | Solaris |
---|---|---|---|
fork | 27.36 | 9.35 | 24.32 |
fork + execve の性能比較
ここまでの計測で、Macs OS X で fork および execve
の実行が、Linux と比較して共に大幅に時間を要することが既にわかっていますが、fork
+ execve
を対で実施した場合の所要時間も、念のため測っておくことにしましょう。
fork
+ execve
システムコールの性能比較として、以下の様なプログラムを実行してみます。
- 引数文字列を整数に変換
- 0 なら終了
- それ以外なら、
fork
を実施 - 子プロセスは、引数に文字列 "0" を指定して、自分自身を
execve
→ 即終了する筈 - 親プロセスは、子プロセスを
wait
- 指定整数から 1 を減じて、手順2から繰り返し
繰り返し回数 0x10000 = 約6万4千の実行に要する時間 (単位:秒) は、以下の様な結果でした。
---- | MacOSX | Linux | Solaris |
---|---|---|---|
fork + execve | 194.90 | 31.06 | 68.04 |
Mac OS X での fork
+ execve
の実行は、Linux と比較して6倍程度の時間を要しています。
Mercurial のテストセット全体では、およそ3万回程度の fork
+ execve
が実施されていますので、上記計測における繰り返し回数 0x10000 = 約6万4千の半分だとすれば、単純計算で (194.90 - 31.06) / 2 = 81.92 秒の所要時間差が生じることになります。
並列度 N でテストを実施することで、見かけ上の性能差を 1/N に減らすことができますが、並列度が 2 〜 4 程度であれば、無視できない差と言えるでしょう。
さて、fork
/execve
の実行性能を個別に計測した結果と、両者を実際に組み合わせた際の計測結果を比較してみると、以下のようになります。
---- | MacOSX | Linux | Solaris |
---|---|---|---|
「fork」実測 | 27.36 | 9.35 | 24.32 |
「execve」実測 | 157.19 | 22.02 | 39.41 |
「fork」と「execve」の合算 | 184.55 | 31.37 | 63.73 |
「fork + execve」実測 | 194.90 | 31.06 | 68.04 |
「実測」-「合算」(「実測」比) | +10.35 (5.3%) | -0.31 (1.0%) | +4.31 (6.3%) |
Linux における "「実測」-「合算」" の -0.31 (実測値の約1%) は、「仮想環境上での簡易計測」ということを考えると、まぁ、見逃しても良さそうな気がしないでもないですが、Mac OS X (と Solaris) における "「実測」-「合算」" は、一応理屈を付けておきたい程度には、無視できない値ですね。
とは言え、底まで調べ上げるには相当に深い沼でしょうから、まずは「差がある」という認識のレベルで止めておくことにします (この性能比較自体、本来の目的からの大幅な脱線ですし……)。
以下、次回に続く。