【问题标题】:Does the .NET JITter perform optimization of primitives in mathematical expressions?.NET JITter 是否对数学表达式中的基元进行优化?
【发布时间】:2012-07-13 18:15:09
【问题描述】:

我有一些 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} 是编译时常量,则 DoCalculation(...) 方法中的表达式可以在 CIL 级别进行极大优化。我想知道 JITer 是否会优化 DoCalculation(...) 方法,类似于给出“只读”提示的编译时间常数优化。

【问题讨论】:

  • 尝试使用和不使用readonly 进行分析。在发布模式等。

标签: c# optimization jit


【解决方案1】:

您的示例不是一个很好的示例,但是是的,这种优化肯定会发生。在不止一个级别上,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+% 的执行时间(不要跳过分析器!),那么值得您花时间修补方法,看看你得到了什么。调试发布模式构建并确保允许优化器运行。工具+选项,调试,常规,取消勾选“Suppress JIT optimization on module load”选项。

小改动可以产生大影响,当您通过看似微不足道的编辑将代码速度提高一倍时,感觉非常好。或者不是,经过一天的尝试,你一无所获,没有保证。但您肯定会对哪种代码运行良好产生一种“感觉”,一种非常宝贵的经验和洞察力。

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 并不是所有的 JIT 优化在 jitting 时都需要完整的知识,频率分析就是其中之一。 (重要编辑)
    • jitted 代码必须处理所有可能的Calculation 实例。每个实例的字段可以不同。这些值在运行时可以是任何东西(想想通过反射创建的实例)。
    • 是否有任何文档明确指出所有实例必须相同?一些 Java JITers 没有这个限制。
    • 这不是很准确。这些变量当然可以是常量,这取决于如何调用构造函数+方法。当它们都被内联并且方法参数是常量时,这些变量也是常量。抖动知道如何做到这一点。
    猜你喜欢
    • 2021-07-12
    • 2012-06-12
    • 1970-01-01
    • 1970-01-01
    • 2021-08-06
    • 2019-01-09
    • 1970-01-01
    • 1970-01-01
    • 2022-06-23
    相关资源
    最近更新 更多