【发布时间】:2013-02-04 14:38:48
【问题描述】:
我编写了一段 C 代码来说明关于优化和分支预测的讨论中的一个观点。然后我注意到比我预期的更多样化的结果。我的目标是用一种介于 C++ 和 C 之间的通用子集的语言编写它,这两种语言都符合标准并且相当可移植。它在不同的 Windows PC 上进行了测试:
#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 优化 Intel Core 2、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 /分析- /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
现在我有问题。这是怎么回事?
更具体地说......一个固定的功能怎么会花费如此不同的时间?我的代码有问题吗?英特尔处理器有什么棘手的问题吗?编译器是否在做一些奇怪的事情?可能是因为 32 位代码在 64 位处理器上运行?
感谢关注!
编辑: 我接受 g++ -O1 只是在其他 2 个调用中重用返回值。我也接受 g++ -O2 和 g++ -O3 存在缺陷,导致优化被排除在外。测量速度的显着差异(450% !!!)似乎仍然很神秘。
我查看了 VS2010 生成的代码的反汇编。它内联了unpredictableIfs 3 次。内联代码非常相似。循环是一样的。它没有内联noIfs。它确实推出了noIfs。一次迭代需要 4 个步骤。 noIfs 计算就像写在 unpredictableIfs 使用 jne 跳过增量。
【问题讨论】:
-
你真的检查过你的“if”和“noIfs”在编译后实际上是不同的吗?如今,许多编译器都知道,对于你正在做的事情,做一些数学运算比条件跳转更好......
-
@MatsPetersson 使用 VS2010 生成的代码完全不同。我将编辑帖子进行解释。
-
@ÖöTiib 请务必向我们展示您在使用 VS2010 编译时使用的命令行开关。
-
很难写出好的速度测试。编译器比你想象的要聪明得多。
-
@PeteBecker 这就是我问的原因。如果很难,那么值得学习。 ;)
标签: c++ c performance optimization measurement