当这两个代码片段执行更多工作时,第一个代码片段的运行速度如何比第二个代码片段快 3 倍?
此代码如何:
var check = 0;
for (var numerator = 0; numerator <= maxNumerator; numerator++)
{
check += numerator >= 0
? numerator - (int) ((numerator * qdi.Multiplier) >> qdi.Shift) * qdi.Number
: numerator - (int) -((-numerator * qdi.Multiplier) >> qdi.Shift) * qdi.Number;
}
return check;
运行速度比此代码快 3 倍:
var check = 0;
for (var numerator = 0; numerator <= maxNumerator; numerator++)
{
check += numerator >= 0
? (int) ((numerator * qdi.Multiplier) >> qdi.Shift)
: (int) -((-numerator * qdi.Multiplier) >> qdi.Shift);
}
return check;
第一个代码片段执行完全相同的快速除法运算(即乘法然后右移),但也执行减法和乘法,但 JIT 编译器似乎生成较慢的代码。
我有每个可用的反汇编代码。
较慢的代码在开始时压入 rbx 寄存器并从 rsp 中减去 10h,然后将其加回来并在最后弹出 rbx,而较快的代码则不会。
较慢的代码还使用 r11 寄存器来完成大多数事情,而较快的代码则使用 rdx。
有什么想法吗?
How can this code:
var check = 0;
for (var numerator = 0; numerator <= maxNumerator; numerator++)
{
check += numerator >= 0
? numerator - (int) ((numerator * qdi.Multiplier) >> qdi.Shift) * qdi.Number
: numerator - (int) -((-numerator * qdi.Multiplier) >> qdi.Shift) * qdi.Number;
}
return check;
run 3x faster than this code:
var check = 0;
for (var numerator = 0; numerator <= maxNumerator; numerator++)
{
check += numerator >= 0
? (int) ((numerator * qdi.Multiplier) >> qdi.Shift)
: (int) -((-numerator * qdi.Multiplier) >> qdi.Shift);
}
return check;
The first code snippet does exactly the same fast divide operation (thats the multiply then shift right) but also a subtraction and multiplication but but the JIT compiler appears to be producing slower code.
I have the disassembly code for each available.
The slower code pushes the rbx register and subtracts 10h from rsp at the start and then adds it back and pops rbx at the end whereas the faster codes doesn't.
The slower code also uses the r11 register for most things where the faster code uses rdx.
Any ideas?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
看来三元运算中使用的条件可能影响生成的代码。
看起来三元选项生成的代码效率比简单的 if/else 低。
因此,将第二个片段中的循环代码更改为:
or:
or:
将产生运行速度更快的代码。
实际上,我觉得有点令人不安的是,四分之三的组合会产生快速的代码,但另一种会产生缓慢的代码......有时。
It would appear that the condition used in a ternary operation can affect the code generated.
It would also appear that a ternary optionation can generate less efficient code than a simple if/else.
So changing the loop code in the second snippest to:
or:
or:
will produce the faster running code.
Actually I find it a bit disturbing that three out of four combinations produce fast code but the other can produce slow code... sometimes.
你测量得怎么样?您对汇编语言的描述听起来不像会产生巨大性能差异的东西。
不管怎样,如果它真的慢了很多,我怀疑 JIT 团队之外的任何人都可以准确地说出为什么会发生这种情况。我在进行 .NET 微基准测试时注意到,看似微不足道的代码更改可能会使代码运行速度显着加快或减慢。如果您可以使该代码(导致速度缓慢)尽可能简单,您可以在 Microsoft Connect 上向 MS 投诉。
您可以尝试将 qdi.Multiplier、qdi.Shift 和 qdi.Number (无论它们是什么)复制到局部变量,这有时会有所帮助。
How are you measuring? Your description of the assembly language doesn't sound like something that would make a huge performance difference.
Anyway, if it's really a lot slower, I doubt anyone outside the JIT team can say exactly why this is happening. I have noticed when doing .NET microbenchmarks that seemingly trivial code changes can make the code run significantly faster or slower. If you can make that code (that triggers slowness) as simple as possible, you could complain to MS about it on Microsoft Connect.
You could try copying qdi.Multiplier, qdi.Shift and qdi.Number (whatever they are) to local variables, that sometimes helps.