inline@gcc
static int test(int i) { return i*i; } int main() { return test(); }
のtest()がどれだけinline化されるか試してみた。対象は手元にあるgcc-2.9.6, gcc-3.4.0, gcc-4.1.2。確認は-Sオプションで出力したgasアセンブラコードにcall testがあるかないかによる。
オプション | gcc-2.9.6 | gcc-3.4.0 | gcc-4.1.2 |
---|---|---|---|
-O0 | x | x | x |
-O1 | x | x | o |
-O2 | x | o | o |
-O3 | o | o | o |
新しいgccほどinline化を積極的にするようだ。-finline-functionsが加わるのは-O3のはずなのにそれ以前からinline化が進んでいるのはちょっと意外かも。
static int test(int i) { return i*i; } int main() { int i, j; int sum = 0; for (i=0; i<0x10000; ++i) { for (j=0; j<0x1000; ++j) { sum += test(j); } } return sum; }
として所用時間を測ってみた。測定法はtime ./a.outのuser分による。一回しか測っていないので誤差が大きいが気にしない。
オプション | gcc-2.9.6 | gcc-3.4.0 | gcc-4.1.2 |
---|---|---|---|
-O0 | 4.859 | 4.947 | 3.934 |
-O1 | 2.962 | 3.090 | 0.988 |
-O2 | 2.763 | 0.975 | 0.975 |
-O3 | 0.980 | 0.970 | 0.977 |
明らかにinline化の有無で差がついている。やはりこのコードでは関数呼び出しのコストが大きいのだろう。各バージョンの-O3同士を比較するとどれも大差はない。最適化する余地のないコードだったのかもしれない。
ついでに
static int test(int i) { return i*i; } int main() { int i, j; int sum = 0; for (j=0; j<0x1000; ++j) { for (i=0; i<0x10000; ++i) { sum += test(j); } } return sum; }
とループの順番を変えてコンパイル時計算をどこまで最適化するかを試してみた。
オプション | gcc-2.9.6 | gcc-3.4.0 | gcc-4.1.2 |
---|---|---|---|
-O0 | 4.633 | 4.518 | 3.783 |
-O1 | 3.022 | 0.824 | 0.001 |
-O2 | 3.111 | 0.548 | 0.000 |
-O3 | 0.548 | 0.551 | 0.000 |
どうやら4.1.2では全部の計算をコンパイル時に行ったようだ。ただし、コードによっては2.9.6の方が速いこともあるそうなので、厳密な話は実機と実コードでベンチマークすべき。