最適化と分岐予測についての議論の要点を示すために、Cコードを書きました。それから、私は予想よりもさらに多様な結果に気づきました。私の目標は、C ++とCの間で共通のサブセットであり、両方の言語の標準に準拠し、かなり移植性のある言語でそれを書くことでした。さまざまなWindowsPCでテストされました。
#include <stdio.h>
#include <time.h>
/// @return - time difference between start and stop in milliseconds
int ms_elapsed( clock_t start, clock_t stop )
{
return (int)( 1000.0 * ( stop - start ) / CLOCKS_PER_SEC );
}
int const Billion = 1000000000;
/// & with numbers up to Billion gives 0, 0, 2, 2 repeating pattern
int const Pattern_0_0_2_2 = 0x40000002;
/// @return - half of Billion
int unpredictableIfs()
{
int sum = 0;
for ( int i = 0; i < Billion; ++i )
{
// true, true, false, false ...
if ( ( i & Pattern_0_0_2_2 ) == 0 )
{
++sum;
}
}
return sum;
}
/// @return - half of Billion
int noIfs()
{
int sum = 0;
for ( int i = 0; i < Billion; ++i )
{
// 1, 1, 0, 0 ...
sum += ( i & Pattern_0_0_2_2 ) == 0;
}
return sum;
}
int main()
{
clock_t volatile start;
clock_t volatile stop;
int volatile sum;
printf( "Puzzling measurements:\n" );
start = clock();
sum = unpredictableIfs();
stop = clock();
printf( "Unpredictable ifs took %d msec; answer was %d\n"
, ms_elapsed(start, stop), sum );
start = clock();
sum = unpredictableIfs();
stop = clock();
printf( "Unpredictable ifs took %d msec; answer was %d\n"
, ms_elapsed(start, stop), sum );
start = clock();
sum = noIfs();
stop = clock();
printf( "Same without ifs took %d msec; answer was %d\n"
, ms_elapsed(start, stop), sum );
start = clock();
sum = unpredictableIfs();
stop = clock();
printf( "Unpredictable ifs took %d msec; answer was %d\n"
, ms_elapsed(start, stop), sum );
}
VS2010でコンパイル。/O2の最適化IntelCore2、WinXPの結果:
Puzzling measurements:
Unpredictable ifs took 1344 msec; answer was 500000000
Unpredictable ifs took 1016 msec; answer was 500000000
Same without ifs took 1031 msec; answer was 500000000
Unpredictable ifs took 4797 msec; answer was 500000000
編集:コンパイラの完全なスイッチ:
/ Zi / nologo / W3 / WX- / O2 / Oi / Oy- / GL / D "WIN32" / D "NDEBUG" / D "_CONSOLE" / D "_UNICODE" / D "UNICODE" / Gm- / EHsc / GS / Gy / fp:precise / Zc:wchar_t / Zc:forScope / Fp "Release \ Trying.pch" / Fa "Release \" / Fo "Release \" / Fd "Release \ vc100.pdb" / Gd / analysis- / errorReport:queue
他の人がそのような投稿をしました...MinGW、g ++ 4.71、-O1最適化Intel Core 2、WinXPの結果でコンパイル:
Puzzling measurements:
Unpredictable ifs took 1656 msec; answer was 500000000
Unpredictable ifs took 0 msec; answer was 500000000
Same without ifs took 1969 msec; answer was 500000000
Unpredictable ifs took 0 msec; answer was 500000000
また、彼は-O3最適化のためにそのような結果を投稿しました:
Puzzling measurements:
Unpredictable ifs took 1890 msec; answer was 500000000
Unpredictable ifs took 2516 msec; answer was 500000000
Same without ifs took 1422 msec; answer was 500000000
Unpredictable ifs took 2516 msec; answer was 500000000
今、私は質問があります。ここで何が起こっているのですか?
より具体的には...固定関数はどのようにこれほど異なる時間を要するのでしょうか?私のコードに何か問題がありますか?Intelプロセッサにトリッキーなものはありますか?コンパイラは何か奇妙なことをしていますか?64ビットプロセッサで実行された32ビットコードが原因である可能性がありますか?
ご清聴ありがとうございました!
編集: g++-O1が他の2つの呼び出しで戻り値を再利用することを受け入れます。また、g++-O2とg++-O3には、最適化を除外する欠陥があることも認めます。測定された速度の大幅な多様性(450%!!!)は、依然として不思議なようです。
VS2010で作成されたコードの逆アセンブルを見ました。インラインでunpredictableIfs
3回行いました。インライン化されたコードはかなり似ていました。ループは同じでした。インラインではありませんでしnoIfs
た。それはnoIfs
少し展開しました。1回の反復で4つのステップが必要です。増分をジャンプするために使用noIfs
中に書かれたように計算します。unpredictableIfs
jne