【发布时间】:2012-05-09 07:27:35
【问题描述】:
为什么注释掉这个 for 循环的前两行并取消注释第三行会导致 42% 的加速?
int count = 0;
for (uint i = 0; i < 1000000000; ++i) {
var isMultipleOf16 = i % 16 == 0;
count += isMultipleOf16 ? 1 : 0;
//count += i % 16 == 0 ? 1 : 0;
}
时间的背后是截然不同的汇编代码:循环中有 13 条与 7 条指令。该平台是运行 .NET 4.0 x64 的 Windows 7。启用了代码优化,并且测试应用在 VS2010 之外运行。 [更新:Repro project,用于验证项目设置。]
消除中间布尔值是一项基本优化,是我 1980 年代最简单的优化之一Dragon Book。生成 CIL 或 JIT 处理 x64 机器码时,如何优化没有得到应用?
是否有“真正的编译器,我希望你优化这段代码,请”开关?虽然我对过早优化类似于love of money 的观点表示同情,但我可以看到尝试分析一个复杂算法时的挫败感,这种算法在其例程中散布着这样的问题。您将通过热点工作,但没有任何迹象表明可以通过手动调整我们通常认为编译器理所当然的内容来大大改善更广泛的温暖区域。我当然希望我在这里遗漏了一些东西。
更新: x86 也存在速度差异,但取决于方法的即时编译顺序。见Why does JIT order affect performance?
汇编代码(根据要求):
var isMultipleOf16 = i % 16 == 0;
00000037 mov eax,edx
00000039 and eax,0Fh
0000003c xor ecx,ecx
0000003e test eax,eax
00000040 sete cl
count += isMultipleOf16 ? 1 : 0;
00000043 movzx eax,cl
00000046 test eax,eax
00000048 jne 0000000000000050
0000004a xor eax,eax
0000004c jmp 0000000000000055
0000004e xchg ax,ax
00000050 mov eax,1
00000055 lea r8d,[rbx+rax]
count += i % 16 == 0 ? 1 : 0;
00000037 mov eax,ecx
00000039 and eax,0Fh
0000003c je 0000000000000042
0000003e xor eax,eax
00000040 jmp 0000000000000047
00000042 mov eax,1
00000047 lea edx,[rbx+rax]
【问题讨论】:
-
我很想看看不同的汇编代码。可以发一下吗?
-
你测试过 bool isMultipleOf16 = ...吗?
-
@David.Chu.ca - 这不会有什么不同 -
var是“编译器,请推断这个变量的类型,并假装我写了那个”。在这种情况下,它会为自己推断出bool。 -
@EdwardBrey:既然你是在 Debug 模式下这样做的,那么所有的赌注都没有了
-
@EdwardBrey:我目前找不到源,但我相信如果您连接了调试器,抖动和/或其他优化器设置会有所不同完全 (也就是说,如果您从 Visual Studio 运行,即使您在“发布”模式下编译)。尝试从命令行(而不是 VS)运行您的代码,看看会发生什么。
标签: c# .net performance compiler-construction jit