是否可以在C#中使用分支预测提示?

cey*_*yko 18 .net c# clr optimization

例如,我知道它是为gcc定义的,并在Linux内核中用作:

#define likely(x)       __builtin_expect((x),1)
#define unlikely(x)     __builtin_expect((x),0)
Run Code Online (Sandbox Code Playgroud)

如果在C#中没有这样的东西是可能的,那么手动重新排序if语句是最好的选择,把最可能的情况放在第一位吗?有没有其他方法可以根据这种类型的外部知识进行优化?

在相关的说明中,CLR知道如何识别保护条款并假设将采用备用分支,这使得这种优化不适合用于保护条款,是否正确?

(请注意,我意识到这可能是微观优化;我只对学术目的感兴趣.)

Chr*_*ens 26

简答:不.

再答:你并不真的需要在大多数情况下.您可以通过更改语句中的逻辑提供提示.使用性能工具更容易,例如内置于Visual Studio的更高(和更昂贵)版本的工具,因为您可以捕获错误预测的分支计数器.我意识到这是出于学术目的,但很高兴知道JITer 非常擅长为您优化代码.作为一个例子(通过C#CLR中逐字逐句采用)

这段代码:

public static void Main() {
    Int32[] a = new Int32[5];
    for(Int32 index = 0; index < a.Length; index++) {
        // Do something with a[index]
    }
}
Run Code Online (Sandbox Code Playgroud)

看起来可能是低效的,因为a.Length是一个属性,因为我们知道在C#中,属性实际上是一组的两个方法(get_XXXset_XXX在这种情况下).但是,JIT知道它是一个属性,并将长度存储在局部变量中,或者内联方法,以防止开销.

...一些开发人员低估了JIT编译器的能力,并试图编写"聪明的代码"以试图帮助JIT编译器.但是,您提出的任何聪明尝试几乎肯定会对性能产生负面影响,并使您的代码更难以阅读,从而降低其可维护性.

除此之外,它实际上更进一步,并且在循环外部而不是在循环内部进行边界检查,这会降低性能.

我意识到它与你的问题没什么关系,但我想我想要做的是这样的微优化在C#中并没有真正帮助你,因为JIT通常做得更好,因为它完全是为此而设计的.(有趣的是,x86 JIT编译器比x64编译器执行更积极的优化)

本文解释了.NET 3.5 SP1中添加的一些优化,其中包括改进分支分支以改进预测和缓存局部性.

所有这一切,如果你想阅读一本关于编译器生成和CLR性能的好书,我推荐我从上面引用的书,CLR通过C#.

编辑:我应该提一下,如果目前在.NET中可以使用,您可以在EMCA-335标准工作草案中找到相关信息.没有标准支持这一点,并且在像IlDasm或CFF Explorer这样的内容中查看元数据没有显示任何可以提示分支预测的特殊元数据的迹象.

  • 虽然我很喜欢那本书,但我不喜欢你引用的内容。它实际上是准确的,但我不喜欢“聪明的代码”的语气,特别是考虑到当有人想知道为什么没有完成给定的优化时,人们同样轻蔑。我们可以想象一种神奇的完美抖动,它总是产生尽可能最有效的代码,并且更容易想象一种从未优化过任何东西的极其幼稚的抖动,我们知道真相介于两者之间。由于不知道中间点在哪里,人们只能在热点地区尝试这些东西,看看它们是否有效。 (3认同)