【问题标题】:Is it possible to use branch prediction hinting in C#?是否可以在 C# 中使用分支预测提示?
【发布时间】:2012-02-11 00:51:57
【问题描述】:

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

#define likely(x)       __builtin_expect((x),1)
#define unlikely(x)     __builtin_expect((x),0)

如果在 C# 中不可能有这样的事情,那么手动重新排序 if 语句的最佳替代方案是,将最可能的情况放在首位?有没有其他方法可以基于这种外部知识进行优化?

在相关说明中,CLR 知道如何识别保护子句并假设将采用备用分支,这使得这种优化不适用于保护子句,对吗?

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

【问题讨论】:

  • 当 C# 编译到 IL 时,你会怎么做呢?
  • 答案是“不,不可能”。 Oded 指出了这种不可能的理由。
  • 我想我希望它可以在 IL 中完成,因为 IL 被编译为本地代码,可以使用提示指令。或者,任何其他类似的技术,即使不是在处理器级别也会感兴趣(尽管我不确定这是否可能)。
  • @Oded, Heath:这并不是不可能的。 MSIL 携带各种元数据,描述局部变量的类型、异常尝试/捕获块等。如果 .NET 设计者为它包含了编码,那么就有可能拥有用于分支预测的元数据。
  • @BenVoigt - 没错,但是,没有这样的编码,所以实际上,这目前是不可能的。

标签: c# .net optimization clr


【解决方案1】:

简短回答:不。

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

这段代码:

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

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

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

除其他外,它实际上走得更远,并在循环外而不是循环内进行边界检查,这会降低性能。

我意识到这与您的问题没有直接关系,但我想我想说的是,像这样的微优化在 C# 中对您没有太大帮助,因为 JIT 通常会这样做更好,因为它正是为此而设计的。 (有趣的是,x86 JIT 编译器比 x64 编译器执行更积极的优化)

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

综上所述,如果您想阅读一本关于编译器生成内容和 CLR 性能的好书,我推荐我从上面引用的书,CLR via C#。

编辑:我应该提一下,如果当前在 .NET 中可以做到这一点,您可以在 EMCA-335 standardworking draft 中找到信息。没有支持这一点的标准,并且在 IlDasm 或 CFF Explorer 之类的东西中查看元数据不会显示任何可以暗示分支预测的特殊元数据的迹象。

【讨论】:

  • 虽然这令人失望,但关于 JITing 的信息令人放心。感谢您的提示,由于我对 CLR 不太熟悉,因此我肯定会查看这本书,但对最近“幕后”实际发生的事情非常感兴趣。
  • 虽然我很喜欢那本书,但我不喜欢你给出的报价。它实际上是准确的,但我不喜欢“聪明的代码”的语气,特别是考虑到当有人想知道为什么没有完成给定的优化时人们同样不屑一顾。我们可以想象一个神奇的完美抖动,它总是产生最有效的代码,更容易想象一个从未优化过任何东西的可怕天真,我们知道真相介于两者之间。不知道中间点在哪里,人们只能在热点尝试这些东西,看看它们是否有效。
  • @JonHanna - 我想我在很大程度上同意你的看法。我认为开发人员不应该忽视 JITer 正在做什么。有点遗憾的是,我们实际上并不确切知道什么是优化的。我知道这并不完美。我也知道这并不可怕。你说的很简洁,但我们根本不知道它优化到什么程度。知道的唯一方法(对于框架的单个版本)是使用 Windbg 之类的东西来查看它正在做的事情。不过,说起来容易做起来难。
  • 另一方面,如果我们对我们所知道的事情走得太远,我们最终可能会对我们面前的情况(特定的框架、机器、网络速度等)过度优化到损害整体质量。无论执行者的技术或知识如何,都不能过多或过少地依赖实施细节(无论是通过推理还是分析得出),这是一种不完美的平衡。
  • “(在本例中为get_Lengthset_Length)”。不,在这种情况下只有get_Length。如果你有时间,请修复。
猜你喜欢
  • 2020-12-16
  • 2018-06-15
  • 2014-07-17
  • 2021-03-04
  • 2011-04-11
  • 2019-07-17
  • 2019-09-13
相关资源
最近更新 更多