Edw*_*rey 43 .net c# compiler-construction performance jit
为什么要注释这个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;
}
Run Code Online (Sandbox Code Playgroud)
在时序背后是非常不同的汇编代码:循环中的13对7指令.该平台是运行.NET 4.0 x64的Windows 7.启用了代码优化,测试应用程序在VS2010之外运行.[ 更新: Repro项目,对验证项目设置很有用.]
消除中间布尔值是一个基本的优化,是我1980年代龙书中最简单的一个.在生成CIL或JITing x64机器代码时,如何不应用优化?
有没有"真正的编译器,我希望你优化这段代码,请"切换?虽然我同情过早优化类似于对金钱的热爱的情绪,但我可以看到试图描述一个复杂算法的挫败感,这个算法在整个惯例中分散.你可以通过热点工作,但没有暗示更广泛的温暖区域可以通过手动调整我们通常认为理所当然的编译器来大大改善.我当然希望我在这里遗漏一些东西.
更新: x86也会出现速度差异,但取决于方法即时编译的顺序.请参阅为什么JIT订单会影响性能?
汇编代码(根据要求):
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]
Run Code Online (Sandbox Code Playgroud)
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]
Run Code Online (Sandbox Code Playgroud)
问题应该是"我为什么在我的机器上看到这样的差异?".我不能重现如此巨大的速度差异,并怀疑你的环境有特定的东西.很难说它可能是什么.可以是你前一段时间设置的一些(编译器)选项而忘记它们.
我创建了一个控制台应用程序,在发布模式下重建(x86)并在VS外部运行.结果几乎相同,两种方法均为1.77秒.这是确切的代码:
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
int count = 0;
for (uint i = 0; i < 1000000000; ++i)
{
// 1st method
var isMultipleOf16 = i % 16 == 0;
count += isMultipleOf16 ? 1 : 0;
// 2nd method
//count += i % 16 == 0 ? 1 : 0;
}
sw.Stop();
Console.WriteLine(string.Format("Ellapsed {0}, count {1}", sw.Elapsed, count));
Console.ReadKey();
}
Run Code Online (Sandbox Code Playgroud)
请任何有5分钟复制代码,重建,在VS外部运行并在结果中发布评论的人.我想避免说"它适用于我的机器".
编辑
为了确保我已经创建了64位 Winforms应用程序,结果与问题类似 - 第一种方法比第二种方法(1.05秒)慢(1.57秒).我观察到的差异是33% - 仍然很多.似乎.NET4 64位JIT编译器中存在一个错误.
这是 .NET Framework 中的一个错误。
好吧,实际上我只是猜测,但我在Microsoft Connect上提交了一份错误报告来看看他们怎么说。在 Microsoft 删除该报告后,我在 GitHub 上的roslyn项目上重新提交了该报告。
更新: Microsoft 已将该问题移至coreclr项目。从对该问题的评论来看,称其为 bug 似乎有点过分了;这更多的是缺少优化。