【发布时间】:2012-01-24 22:03:44
【问题描述】:
背景
以下用 C++ 编写的数值软件的关键循环主要通过其中一个成员比较两个对象:
for(int j=n;--j>0;)
asd[j%16]=a.e<b.e;
a 和 b 属于 ASD 类:
struct ASD {
float e;
...
};
我正在研究将此比较放在轻量级成员函数中的效果:
bool test(const ASD& y)const {
return e<y.e;
}
并像这样使用它:
for(int j=n;--j>0;)
asd[j%16]=a.test(b);
编译器正在内联这个函数,但问题是,汇编代码会有所不同,并导致超过 10% 的运行时开销。我不得不质疑:
问题
-
为什么编译器会产生不同的汇编代码?
-
为什么生成的程序集比较慢?
编辑:通过实施@KamyarSouri 的建议(j%16)已经回答了第二个问题。汇编代码现在看起来几乎相同(请参阅http://pastebin.com/diff.php?i=yqXedtPm)。唯一的区别是第 18、33、48 行:
000646F9 movzx edx,dl
材质
- 测试代码:http://pastebin.com/03s3Kvry
- MSVC10 上带有 /Ox /Ob2 /Ot /arch:SSE2 的程序集输出:
此图表显示了我的代码 50 次测试运行的 FLOP/s(最大比例因子)。
生成绘图的 gnuplot 脚本:http://pastebin.com/8amNqya7
编译器选项:
/Zi /W3 /WX- /MP /Ox /Ob2 /Oi /Ot /Oy /GL /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" / Gm- /EHsc /MT /GS- /Gy /arch:SSE2 /fp:precise /Zc:wchar_t /Zc:forScope /Gd /analyze-
链接器选项: /增量:没有“kernel32.lib”“user32.lib”“gdi32.lib”“winspool.lib”“comdlg32.lib”“advapi32.lib”“shell32.lib”“ole32.lib”“oleaut32.lib”“ uuid.lib" "odbc32.lib" "odbccp32.lib" /ALLOWISOLATION /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /SUBSYSTEM:CONSOLE /OPT:REF /OPT:ICF /LTCG /TLBID:1 / DYNAMICBASE /NXCOMPAT /MACHINE:X86 /ERRORREPORT:QUEUE
【问题讨论】:
-
好问题。发布用于产生此结果的优化和其他相关编译器设置可能具有指导意义。
-
哦,伙计……似乎有人学会了提出一流问题的艺术……只是这一次,我脑子里没有答案……
-
@Johannes Gerer:与
a.e<b.e相比,j%10可能需要相当长的时间。您可以尝试通过将j%10替换为j%16之类的东西来重新进行测试吗? -
好吧,在这种情况下,它显然是一个 M$ 编译器,所以这可能是一大块问题。但正如其他人所暗示的那样,编译器可能至少部分认为它处于调试模式,或者优化“已关闭”。
-
是的,从 Mystical 的帖子来看,这似乎主要是“运气不好”。优化有一定的统计性质——同样的优化在 99% 的时间里“获胜”,但在 1% 的时间里会咬你一口。并且对 xor 实现有点粗心通常无关紧要,但在这种情况下可能会发生(或者问题可能是不相关的,并且由于缓存边界的轻微差异等原因。我什至见过程序运行的情况多次重新编译时以不同的速度,这取决于它如何映射到内存。
标签: c++ performance assembly compiler-optimization inlining