プログラムによる数値演算のベンチマーク
2002.11.30 Yutaka Yoshisaka.


C/Javaプログラムによる数値演算の速度差をベンチしてみました。
チェック項目として、

「カラの関数の呼び出し」
「整数(int型)の加減乗除算とシフト」
「単精度浮動小数点(float型)の加減乗除算」
「倍精度浮動小数点(double型)の加減乗除算」
「三角関数演算関数(cos)の呼び出し」
「平方根演算関数(sqrt)の呼び出し」
「3次元ベクトルの単位ベクトルの計算」

をテストし、それぞれを「10000*10000回」繰り返して演算し、その処理時間を計測します。

テスト環境は、Windows2000マシン(Athlon 1100MHz / Mem 512MB)と OS X10.2.2マシン(eMac(G4 700MHz / Mem 384MB))です。

Windows環境では、コンパイラとして「Borland C++5.5.1」「Visual C++6.0」「J2SE 1.4.1」にてチェック、
OS X環境では、コンパイラとして「gcc 3.1」と「CodeWarrior8.3(コンパイラは「Mac OS X PowerPC Mach-O」)」「J2SE 1.3.0」にてコンパイルしてチェックしました。

※OS Xでの「gcc 3.1」は、ProjectBuilder2.0.1と同等、と思っていただいていいかと思います。



使用したソースファイル

ベンチマーク結果

関数呼び出しと整数演算の比較

環境関数呼び出し 整数加算整数減算 整数乗算整数除算 シフト演算
Win:VC++ 最適化なし 1011 ms 451 ms 540 ms 551 ms 4547 ms 540 ms
Win:VC++ 最適化あり 540 ms 181 ms 190 ms 360 ms 3906 ms 180 ms
Win:BCC 最適化なし 641 ms 791 ms 802 ms 650 ms 4357 ms 651 ms
Win:BCC 最適化あり 640 ms 181 ms 180 ms 180 ms 190 ms 271 ms
Win:Java 370 ms 641 ms 461 ms 641 ms 4456 ms 591 ms
OSX:gcc3.1 最適化なし 3300 ms 2000 ms 2010 ms 2300 ms 5200 ms 2010 ms
OSX:gcc3.1 最適化あり 1140 ms 290 ms 280 ms 300 ms 270 ms 280 ms
OSX:CW8.3 最適化なし 1010 ms 420 ms 290 ms 280 ms 3320 ms 440 ms
OSX:CW8.3 最適化あり 1010 ms 440 ms 430 ms 440 ms 430 ms 430 ms
OSX:Java 1309 ms 2065 ms 2091 ms 2354 ms 5400 ms 2210 ms

単精度浮動小数点演算の比較

環境単精度浮動小数点加算 単精度浮動小数点減算単精度浮動小数点乗算 単精度浮動小数点除算
Win:VC++ 最適化なし 1002 ms 1122 ms 1001 ms 1813 ms
Win:VC++ 最適化あり 361 ms 370 ms 361 ms 1001 ms
Win:BCC 最適化なし 1171 ms 1182 ms 1182 ms 1732 ms
Win:BCC 最適化あり 1152 ms 1181 ms 1182 ms 1732 ms
Win:Java 1262 ms 1251 ms 1352 ms 1983 ms
OSX:gcc3.1 最適化なし 8170 ms 8170 ms 8170 ms 8170 ms
OSX:gcc3.1 最適化あり 300 ms 280 ms 300 ms 280 ms
OSX:CW8.3 最適化なし 4020 ms 4040 ms 4040 ms 4050 ms
OSX:CW8.3 最適化あり 420 ms 420 ms 440 ms 430 ms
OSX:Java 6263 ms 6257 ms 6259 ms 6257 ms

倍精度浮動小数点演算の比較

環境倍精度浮動小数点加算 倍精度浮動小数点減算倍精度浮動小数点乗算 倍精度浮動小数点除算
Win:VC++ 最適化なし 1031 ms 1262 ms 1001 ms 1863 ms
Win:VC++ 最適化あり 361 ms 370 ms 361 ms 1001 ms
Win:BCC 最適化なし 2083 ms 2093 ms 1903 ms 2814 ms
Win:BCC 最適化あり 1913 ms 1903 ms 1913 ms 2543 ms
Win:Java 2264 ms 1962 ms 1963 ms 2544 ms
OSX:gcc3.1 最適化なし 7440 ms 7450 ms 7430 ms 7460 ms
OSX:gcc3.1 最適化あり 290 ms 280 ms 290 ms 290 ms
OSX:CW8.3 最適化なし 4040 ms 4030 ms 4020 ms 4040 ms
OSX:CW8.3 最適化あり 430 ms 440 ms 430 ms 440 ms
OSX:Java 6256 ms 6983 ms 6980 ms 7002 ms

数値演算関数の呼び出しの比較

環境三角関数(cos) 平方根(sqrt)三次元ベクトルを単位ベクトル化
Win:VC++ 最適化なし 13800 ms 4897 ms 9804 ms
Win:VC++ 最適化あり 9394 ms 2183 ms 9443 ms
Win:BCC 最適化なし 11066 ms 3144 ms 14491 ms
Win:BCC 最適化あり 12869 ms 5758 ms 16404 ms
Win:Java 31295 ms 2273 ms 13500 ms
OSX:gcc3.1 最適化なし 27110 ms 29980 ms 43830 ms
OSX:gcc3.1 最適化あり 23420 ms 26940 ms 28280 ms
OSX:CW8.3 最適化なし 24900 ms 27690 ms 35080 ms
OSX:CW8.3 最適化あり 23580 ms 26980 ms 29170 ms
OSX:Java 57057 ms 27282 ms 41198 ms


考察

上記の結果より、同じWindows環境で同じC言語コンパイラのVisual C++(VC++)とBorland C++(BCC)では、 整数除算の効率化が、BCCのほうが最適化されているのが分かります。
逆に、シフト演算はVC++のほうがよくなってるようです (ただ、これは最適化によりループがまとめられた結果かもしれません)。
C言語では、OS環境や最適化なし・ありに関係なく、「関数呼び出し」に時間がかかっているのが分かります。
しかし、Javaでは逆に、整数の四則演算よりも関数呼び出しのほうが早いです。
OS Xでは、浮動小数点演算が加減乗除算に関係なく、処理速度は一定のようです。
また、最適化した場合は、整数の加減乗除算・シフト演算も、処理速度が一定のような感じです。
(ただ、これは最適化によりループがまとめられた結果かもしれません)。
また、全体的に数値演算関数(cos/sqrtなど)の実行にかなりの時間を費やしています。
計測の数値だけでは、結果が見えにくいですので、個々の機能別に処理時間の比率を出して見てみることにします。

機能別に比較

WinマシンとMacマシンは、共にスペックが違うため純粋には比べられないですが、それぞれの「整数加算」での結果を1.0としたときの比率を以下に示します。
これにより、全体よりどの部分がボトルネックになっているのか、というのを調べてみます。

※「最適化あり」の比較は、 最適化によって無駄なループがまとめられてしまっている可能性があります。 そのため、純粋な比較にはならないかもしれません。

関数呼び出しと整数演算の比較(比率)

環境関数呼び出し 整数加算整数減算 整数乗算整数除算 シフト演算
Win:VC++ 最適化なし 2.2 1.0 1.2 1.2 10.1 1.2
Win:VC++ 最適化あり 3.0 1.0 1.0 2.0 21.6 1.0
Win:Java 0.58 1.0 0.72 1.0 7.0 0.92
OSX:gcc3.1 最適化なし 1.7 1.0 1.0 1.2 2.6 1.0
OSX:gcc3.1 最適化あり 3.9 1.0 1.0 1.0 0.9 1.0
OSX:CW8.3 最適化なし 2.4 1.0 0.7 0.7 7.9 1.0
OSX:CW8.3 最適化あり 2.3 1.0 1.0 1.0 1.0 1.0
OSX:Java 0.6 1.0 1.0 1.1 2.6 1.1

単精度浮動小数点演算の比較(比率)

環境単精度浮動小数点加算 単精度浮動小数点減算単精度浮動小数点乗算 単精度浮動小数点除算
Win:VC++ 最適化なし 2.2 2.5 2.2 4.0
Win:VC++ 最適化あり 2.0 2.0 2.0 5.5
Win:Java 2.0 2.0 2.1 3.1
OSX:gcc3.1 最適化なし 4.1 4.1 4.1 4.1
OSX:gcc3.1 最適化あり 1.0 1.0 1.0 1.0
OSX:CW8.3 最適化なし 9.6 9.6 9.6 9.6
OSX:CW8.3 最適化あり 1.0 1.0 1.0 1.0
OSX:Java 3.0 3.0 3.0 3.0

倍精度浮動小数点演算の比較(比率)

環境倍精度浮動小数点加算 倍精度浮動小数点減算倍精度浮動小数点乗算 倍精度浮動小数点除算
Win:VC++ 最適化なし 2.3 2.8 2.2 4.1
Win:VC++ 最適化あり 2.0 2.0 2.0 5.5
Win:Java 3.5 3.1 3.1 4.0
OSX:gcc3.1 最適化なし 3.7 3.7 3.7 3.7
OSX:gcc3.1 最適化あり 1.0 1.0 1.0 1.0
OSX:CW8.3 最適化なし 9.6 9.6 9.6 9.6
OSX:CW8.3 最適化あり 1.0 1.0 1.0 1.0
OSX:Java 3.0 3.4 3.4 3.4

数値演算関数の呼び出しの比較(比率)

環境三角関数(cos) 平方根(sqrt)三次元ベクトルを単位ベクトル化
Win:VC++ 最適化なし 30.6 10.9 21.7
Win:VC++ 最適化あり 52.0 12.1 52.2
Win:Java 48.8 3.5 21.1
OSX:gcc3.1 最適化なし 13.6 15.0 21.9
OSX:gcc3.1 最適化あり 80.8 92.9 97.5
OSX:CW8.3 最適化なし 59.3 66.0 84.0
OSX:CW8.3 最適化あり 53.6 61.3 66.3
OSX:Java 27.6 13.2 20.0

これらから以下のことが分かります。

結果

以上のことから、数値演算が絡むプログラムの際に、
「関数の呼び出しは極力控える」
「除算は、乗算やシフトで代用できる場合は、極力使用するのを避ける」
「(OS X環境では大差がないが)整数演算でできる部分は、整数で」
「数値演算関数は、ルックアップテーブルなどを使うようにして、頻繁な呼び出しを避ける」

と、ごく当たり前ですが、
このあたりを守ることが速度アップにつながることと思います。
OS Xでは、平方根(sqrt)の計算が十分ネックになりうる、ということも重要な点だと思います。
Windowsではまったく気にならなかったのですが、OS Xで3D関連の計算が遅い、というのも、 どうもこのsqrt関数呼び出しが原因のような気がしないでもありません。
G4の「VelocityEngine」がなぜ存在するのか、というのも、このあたりの演算の弱さをバックアップするためなのかもしれないですね。