2010-3-12[金] ちょっと速度比較
前回触った LLVM-gccやpcc,coins (で作ったプログラム)の速度が気になったので、
手持ちのCコンパイラ(vc意外はフリーのもの)で適当に実行速度を計ってみた。
(3/14修正: cygwinの計測が間違って別のmingwでの結果になってました).
(3/15修正: llvm-gccは生成方法を間違えていたためやり直しました.
また他と比較しずらいので clangの結果も含めました)
試したコンパイラは全てwin環境用で
コンパイラ | 生成にかかわるオプション | 補足 |
vc9sp1 64bit | -GR- -Ox -DNDEBUG -MT | |
vc9sp1 32bit | -GR- -Ox -DNDEBUG -MT | |
cygwin gcc 3.4.4 | -O2 -DNDEBUG | bashでなくcmd.exe上で実行. |
mingw32 gcc 3.4.5 | -O2 -DNDEBUG | |
mingw32 gcc 4.4.0 | -O2 -DNDEBUG | |
LLVM-gcc 2.6 | -O2 -DNDEBUG -emit-llvm | 実際には一度に作れず複数工程になる |
clang | -O2 -DNDEBUG | -emit-llvmせずで、おそらくclang単体での生成 |
Open Watcom 1.8 | -Ot -O3 -DNDEBUG -finline-functions -frerun-optimizer -floop-optimize -funroll-loops -finline-math | |
dmc 8.51 | -o -DNDEBUG | |
pcc-20090818-win32 | -O3 -DNDEBUG | |
COINS 1.4.4.3-en | -O2 -DNDEBUG | bashでなくcmd.exe上で実行 |
BorlandC 5.5.1 | -O2 -Ox -RT- -d -dc -DNDEBUG | |
PellesC 6.00.6 | /Zx /Ze /Ox -DNDEBUG | |
TinyCC 0.9.25 | -DNDEBUG | オプティマイズは無い |
正直、オプションが、どの適度適切かは不明。
Watcomはつけすぎてるけど、基本はデフォルトに近い状態。
浮動小数点関係は、設定しだいで結構違うだろうけど不精してせず(watcom以外)。
試したテストプログラムは
download:上記のソースのzip
たくさんやるのも面倒なので、これだけ(これだけでも結構しんどく)。
自分が大雑把に雰囲気をつかむため、なので、あまり適切でないサンプルかも。
1core 1threadな簡易な処理だけだし。
Dhrystone,Whetstoneは一応してみたけど、あまりピンときていない
(処理内容わかってないからだろうけど).
実行環境は vista64(PhenomIIx4 3G)、通常のデスクトップでDOS窓とエディタ程度だが、サービスや常駐モノはある程度残った状態で実行.(テスト中の 1core がフル稼働で、あとの処理は他のcoreが大筋まかなってるだろうと期待. 以前別の計測にてsafemodeで起動して計測したほうが安定していた感じはあったけれど、酷すぎるほどの差もなかったので楽してる)
実行結果 は (3/14 一部計測し直し. cygwin計測ミス、安易インタプリタのclang対処反映)
コンパイラ | Bilinear 拡大(ミリ秒) | 安易 インタプリタ(秒) | quick sort(μ秒) | QSORT(μ秒) | Dhrystone/sec | Whetstone (MWIPS) |
vc9sp1 64 | 87.5 | 25.2 | 14439 | 39856 | 14214641 | 3465.753 |
vc9sp1 32 | 189.2 | 24.7 | 14452 | 69039 | 11530036 | 2284.091 |
cygwin 344 | 262.0 | 20.2 | 20300 | 60900 | 10208248 | 2108.046 |
mingw 345 | 245.0 | 25.4 | 19166 | 61556 | 9893154 | 1456.068 |
mingw 440 | 265.0 | 25.3 | 19118 | 85483 | 10273269 | 1554.432 |
LLVM-gcc(sse2) | 105.8 | 27.6 | 19871 | 35860 | (25056376) | 1525.463 |
clang | 199.9 | 27.9 | 15225 | 67820 | 12841916 | 1478.956 |
watcom | 387.3 | 26.4 | 28222 | 42918 | 11186934 | 2199.402 |
dmc | 371.9 | 25.1 | 21224 | 60580 | 9040774 | 1560.336 |
pcc | 289.9 | 32.3 | 19436 | 79627 | 8033419 | 1176.030 |
COINS | 384.1 | 28.0 | 18700 | 65500 | 5990894 | 1335.854 |
Bcc 5.5 | 582.2 | 39.4 | 19092 | 59047 | 10111223 | 1692.216 |
PellesC | 429.3 | 30.4 | 14696 | 66794 | 7317965 | 1241.080 |
TinyCC | 511.4 | 49.9 | 66213 | 105858 | 5754402 | 1063.352 |
(補足) | ↓good | ↓good | ↓good | ↓good | ↑good | ↑good |
たったこれだけだし、
測定(実行)環境はザルで実行毎の誤差からすれば
細かい数値みちゃうとまずいだろう。
特に浮動少数演算関係のオプション設定が適切でないだろうで
設定かえたら(Whetstoneとか)結果変わってきそうな気もする.
(c標準ライブラリも計測範囲で使われてるので
それの影響もどう据えるかにもよるし)。
が、おおざっぱに、vcが1番よさそうで次gcc系、
後は混戦で、ケツがTinyCCって感じか。
今回以外の例を思えば vcが抜きでてるとはいいきれないけれど.
(Intel C/C++気になるけど懐的に手が出せないのでVCで満足しとく)
vc9sp1 64 の結果は CPUが64bit CPUなので、コンパイラの比較ってよりCPUの比較になるけど、
64ビットOS用にコンパイルするだけで、
結構違いがでる処理もある、という例になってるかも、で(代わり映えしない処理もあるけど)。
バイリニア拡大の結果は、
64ビット整数の利用頻度が少なかろうと
汎用レジスタが増えたことによるメリットが効いている例だろう
(あとSSE2も関係あるか? 追記:というか、汎用レジスタどうこうでなく、
まさにSSE2になったことが効いているよう。
clangの結果がいいのも、SSE?なコードが生成されているためのよう
(clangのほうはsseしてない)
)。
32bitでもVCが結構速くなる例で、結構かたよった代物だろうけど...
(この手の画像処理なんかは普通からすれば特殊な扱いになるのかも.
速度/ハードを気にしだすと生のCだけで済まさないだろうし)
感想としては
llvm(-gcc)は(いろいろミスして勘違いしまくりだったけれど)ものによっては非常に速くなったりでびっくりで早く使い易くなってほしく、
Clangはllvmをしなくても(?)これだけの性能あっていろいろ期待、
PCC は速度は思ってたよりはいいかも、だけど(Win版は)思ったより安定してなさそう、
PellesC はそんなもんだろう、
TinyCC は実行時速度じゃなくてコンパイル速度優先で(-benchなんてオプションがあるくらいだし)スクリプト言語的にCソースを扱うような方向があるようなので
実行時速度はこの程度の差ならokなんだろう、
COINSは悪くないのだけど期待しすぎてたため
(ひょっとするとあまりx86系向きじゃないのかもだけど)
ちょっと哀しい気分、てとこか。
※追記:cygwin-gcc、測定ミスでやりなおしたけど、gcc3.4の範囲なのでたいして値はかわってない(でもWhetstoneは結構ちがうか。浮動小数点はオプション設定しだいだろうでデフォルトがいい状態だったのかも)。
もともとcygwin使ったCOINSの結果と比較するのにmingwのでいいか微妙な気もして追加したものなので(ただの計算だけだとそう違わないだろうけど).
あと最初の4つのテストで cygwin-gccとCOINSは win-apiでなくtime.hを用いて計測しているため若干条件が違う、とも.
※追記:安易インタプリタの結果は、clang対策での修正前にくらべ、どれも4,5秒短くなっている. isalphaやtoupperを手抜きなマクロに置き換えただけだが、結構ライブラリのオーバーヘッドがあったということか. テーブル参照より単純比較のほうが速いのかスレッド関係やロケール対策がらみなのかはしらないけれど。
※追記:
llvm-gcc のやり直しにおいて、Bilinear拡大は最適化されすぎて計算がなくなってしまったため、そうならないよう、若干ソースを修正(計測時間外での対処)した.
また、Dhrystone2.1の結果も最適化されるぎている可能性があるかも(大丈夫?).
(dhry_1.c dhry_2.c を1つのソースにした場合のvc64も結構はやかったので
全体最適化としてはありなのかも?)
※追記:llvm-gcc 同様に clangも -emit-llvm で生成すると速くなる模様
(例えばbilinear拡大のは 100.9 に). が、どうも何かミスっていて正常終了できないハングするexeが作られるためちゃんと試せていない.(追記:スタックフレームポインタを保持してるはずの ebp を退避せずに汎用レジスタ的に破壊して使うコードができてる模様)
(4/23追記: 試したのはbilinearのだけだが、最近のclang(1.5 trunk 102038)で試したら修正されてるようで動作)
コンパイル不具合のメモ
- pcc は #include で、#より前に空白が置かれていると、エラーになる場合があった.
行頭に#を置けばok. #の後ろに空白が入るのはok.
- pcc で、初期化していないグローバル or static 変数でハングする場合あり(必ずではなく).
char buf[10] ={0}; な感じに初期値を入れてしまうことで回避できた.
- COINSでdhrystoneコンパイル時、 gccのヘッダを流用しているため?か、
stdio.hヘッダにあるstatic inlineになっていないinline関数(fget?の内部関数)が
複数のobjでincludeされてると、リンクで名前の衝突が発生.
(実際に必要としたソースは1つだったので、includeを調整して回避).
- COINS, 正常なtolower(c)で')'がらみでエラー. (interpreter_smp:マクロでtoupperを乗っ取って回避).
(とかいたけど、coinsはちゃんと環境できていない可能性もあり)