gpt4 book ai didi

c# - .NET 编译器中的分支消除与 Jit'ter

转载 作者:太空宇宙 更新时间:2023-11-03 18:33:36 25 4
gpt4 key购买 nike

对于我的一个项目,我使用了很多分支。思考:

if (foo) { do something } 
else if (bar) { do something }
else if (bar2) { do something }
... and so on

if (foo) { do something } 
if (bar) { do something }
if (bar2) { do something }
... and so on

我一直在想的是,进行子表达式和/或逻辑消除以加快速度是否有意义。为了完整起见,您可以假设所有这些都在一个函数中。说,如果 foobar有一个共同的子表达式,你可以这样写:

if (commonSubExpr) 
{
if (foo without commonSubExpr) { do something }
if (bar without commonSubExpr) { do something }
}
if (bar2) { do something }
... and so on

同样,您可以应用许多简单的 bool 逻辑规则来优化规则。

我的问题是:这样做是否有意义?或者我可以期望 JIT'ter 来处理这个问题吗?

(根据 excellent article by Eric Lippert,除了常量折叠之外,编译器并未对此进行优化 - 我认为情况仍然如此)。

更新+1

好吧,我不应该问这是否有意义,因为现在我有好人试图向我解释什么是过早的优化,这不是我所追求的……我的错误。请假设我知道过度设计、过早优化等问题——这正是我在这里试图避免的。

所以尝试 2...我想知道事情是如何工作的 以及我可以从编译器/JIT'ter 得到什么

我还注意到一些上下文可能对这里有帮助,所以这里有一些关于应用程序的信息:

在这种情况下,应用程序是一种在运行时使用 Reflection.Emit to IL 编译的领域特定语言。我有充分的理由不能使用现有的语言或现有的编译器。性能很关键,编译后会执行很多操作(这就是为什么首先将其编译为 IL,而不是简单地解释代码)。

我问这个问题的原因是因为我想知道我应该将编译器中的优化器设计到什么程度。如果 JIT'ter 负责消除子表达式,我将设计优化器只做基本的事情,如常量折叠,如果 .NET 希望在编译器中发生这种情况,我将在编译器中设计它。根据我的预期,优化器将具有完全不同的设计。由于分支可能是最重要的性能消耗者,而且实现对我的软件设计有巨大影响,所以我特地决定询问这个问题。

我知道在实现编译器之前没有办法对此进行测试 - 这需要大量工作 - 所以我想在开始实现之前直接了解我的基础知识。我不知道如何测试它的原因是因为我不知道 JIT'ter 在什么情况下优化了哪些代码;我希望 .NET 运行时中的某些触发器会导致某些优化(使测试结果不可靠)...如果您知道解决这个问题的方法,请告诉我。

表达式 foo , bar等可以是您通常在代码中看到的任何形式,但您可以假设它是一个函数。所以,它可以是 if (StartDate < EndDate) 的形式, 但不能是类似 if (method1() < method2()) 的东西.解释一下:在后一种情况下,编译器不能简单地对方法的返回值做出假设(在优化之前,您需要了解有关返回值的信息),因此子表达式消除一点也不简单。

因此,作为子表达式消除的示例:

if (int1 < int2 && int1 < int3) {
//...
}
else if (int1 < int2 && int1 < int3) {
//...
}

可以重写为:

if (int1 < int2)
{
if (int1 < int3) {
//...
}
else if (int1 < int3) {
//...
}
}

总而言之:我想知道这些子表达式消除优化是否有意义 - 或者它们是否由 JIT'ter 处理。

最佳答案

So, it can be of the form if (StartDate < EndDate)

不,它不能。您的编译器需要生成对 DateTime.op_LessThan() 方法的调用。生成对方法的调用的问题在于您无法 100% 确定该方法不会产生可观察到的副作用。 DateTime.op_LessThan 没有,但这不是您的编译器可以自行找到的东西。您必须在编译器中对该规则进行硬编码。

然而,抖动可以,它确实知道该方法的代码是什么样的。而且它非常小,它会将方法内联到单个 CPU 指令中。其平均执行时间少于一个 CPU 周期。处理器中内置的分支预测逻辑可确保分支不太可能使流水线停滞。

很难让编译器中的优化器产生返回。它只能消除非常简单的代码的公共(public)子表达式,没有副作用,但这样的代码已经运行得非常快了。 C# 编译器是一个值得遵循的好模型,它不会优化并且让工作变得不稳定。 this answer 中描述了抖动执行的优化。 .是的,常见的子表达式消除就是一种它知道如何执行的优化。

然而,它是否应用优化是不可预测的,这取决于它需要在方法中生成哪些其他代码。我没有检查过这个具体案例,我宁愿怀疑它是否会由于分支。如果您还想为 && 和 || 提供短路评估,那么它远不止这些。运营商。您可以找到的唯一方法是查看实际生成的机器代码。选择您要使用平台目标设置验证的抖动。构建测试代码的发布配置。然后Tools + Options,Debugging,General,取消勾选“Suppress JIT optimization”选项。并查看带有断点和 Debug + Windows + Disassembly 的机器码。注意伪造的测试代码,如果抖动可以优化太多,它通常会运行得不切实际。并注意在这上面浪费太多时间:)

关于c# - .NET 编译器中的分支消除与 Jit'ter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18783941/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com