.NET JITter是否在数学表达式中执行基元的优化?

时间:2012-07-13 20:54:49

标签: c# optimization jit

我有一些C#代码执行一些涉及原始数据类型的计算,例如:

public sealed class Calculation
{
    private readonly int a, b, c;

    public Calculation(int _a, int _b, int _c)
    {
        this.a = _a; this.b = _b; this.c = _c;
    }

    public int DoCalculation(int rfactor, int lfactor)
    {
        return (a / rfactor) + (b / lfactor) + ((a/b)*(rfactor+lfactor));
    }
}

如果{a,b,c}是编译时常量,则可以在CIL级别对DoCalculation(...)方法中的表达式进行大幅优化。我想知道JITer是否会优化DoCalculation(...)方法,类似于给出“readonly”提示的编译时常量优化。

2 个答案:

答案 0 :(得分:4)

不,因为变量不是常量。它们的价值在jitting时是未知的。只读它不会改变它们的运行时值是未知的事实,并且可能在实例之间有所不同。

答案 1 :(得分:4)

你的例子不是很好,但是,这种优化肯定会发生。在不止一个级别上,C#编译器首先获得一个镜头。它将使用文字值评估简单表达式,并将其替换为结果。它也是在编译时检测溢出的方式。

抖动优化器也是这样做的,通常是内联方法的结果。但是,对于你的DoCalculation()方法不会发生这种情况,它太复杂了,不允许内联。但是很简单,比如:

    public static int DoCalculation(int a, int b) {
        return a * b;
    }

肯定会内联和优化。像Console.WriteLine(Calculation.DoCalculation(4,5))生成:

00000003  call        5927D408 
00000008  mov         ecx,eax 
0000000a  mov         edx,14h                      // <=== here
0000000f  mov         eax,dword ptr [ecx] 
00000011  mov         eax,dword ptr [eax+38h] 
00000014  call        dword ptr [eax+14h] 

注意结果4 * 5 = 20 = 0x14是如何预先计算的。

没有严格的规则可以确定方法何时可以内联,以及在优化程序放弃之前表达式的相关性。这可能会发生变化,具体取决于抖动的类型(x86 vs x64 vs ARM)。

如果此代码深入您的关键路径,并且分析器告诉您它负责执行时间的80%以上(不要跳过分析器!)那么值得花些时间修补一下用这个方法,看看你得到了什么。调试Release模式构建并确保允许优化器运行。工具+选项,调试,常规,取消&#34;抑制模块负载的JIT优化&#34;选项。

小的更改可能会产生很大的影响,当您通过看似微不足道的编辑将代码速度提高一倍时感觉相当不错。或者没有,经过一天的尝试,你无处可去,没有保证。但你肯定会发展出一种感觉&#34;对于什么样的代码运行良好,经验和洞察力非常有价值。