【问题标题】:Optimizing branch predictions: how to generalize code that could run wth different compiler, interperter, and hardware prediction?优化分支预测:如何概括可以使用不同编译器、解释器和硬件预测运行的代码?
【发布时间】:2016-04-16 06:35:30
【问题描述】:

我今天在一个由 If 语句引起的紧密循环中遇到了一些减速,这让我有些惊讶,因为我希望分支预测能够成功地流水线化特定语句以最小化条件的成本。

当我坐下来思考为什么没有更好地处理它时,我意识到我根本不知道如何处理分支预测。我非常了解分支预测的概念及其好处,但问题是我不知道谁在实施它以及他们使用什么方法来预测条件的结果。 p>

深入了解我知道分支预测可以在几个层次上完成:

  1. 带有指令流水线的硬件本身
  2. C++ 风格的编译器
  3. 解释语言的翻译。
  4. 像 java 这样的半编译语言可以做到以上两三点。

但是,由于可以在许多领域进行优化,因此我不确定如何预测分支预测。例如,如果我用 Java 编写,我的条件是在编译时、解释时还是在解释后由硬件优化的!?更有趣的是,这是否意味着如果有人使用不同的运行时环境?在不同的解释器中使用不同的分支预测算法是否会导致基于条件的紧密循环显示出显着不同的性能,具体取决于运行它的解释器吗?

因此,我的问题是,如果软件可以在非常不同的计算机上运行,​​这可能意味着不同的分支预测,那么如何概括围绕分支预测的优化?如果硬件和解释器可以改变他们的方法,那么分析和使用任何一种被证明最快的方法都不能保证。让我们忽略 C++,因为您有编译级别的能力来强制执行此操作,如果有人仍然需要优化其中的紧密循环,请查看解释语言。

无论使用何种口译员,是否有某些通常可以安全做出的假设?是否必须深入研究一种语言的复杂规范才能对分支预测做出任何有意义的假设?

【问题讨论】:

  • 这有点宽泛。非常一般地,分析并获得它将运行的硬件的平均值,并尝试从中进行优化。
  • 我不会以解释语言为目标,因为它们具有“隐藏开销”,可能涉及您无法控制的分支。
  • 关于您可以采取的唯一“可移植”措施是尽可能避免条件分支。见stackoverflow.com/a/17828251/1196549

标签: optimization branch-prediction


【解决方案1】:

简答:

为了帮助提高分支预测器的性能,请尝试构建您的程序,使条件语句不依赖于显然是随机的数据。

详情

other answers 对此问题的其中一个声明:

没有办法在高级语言中做任何事情来优化分支预测,缓存当然,有时你可以,但是分支预测,一点也不。

然而,这根本不是真的。 most famous questions on Stack Overflow 之一很好地说明了这一事实。

所有分支预测器的工作原理是识别重复代码执行的模式,并根据需要使用此信息来预测分支的结果和/或目标。

使用高级语言编写代码时,应用程序程序员通常不必担心尝试优化条件分支。例如 gcc 有 __builtin_expect 函数,它允许程序员指定条件分支的预期结果。但是即使应用程序程序员确定他们知道特定分支的典型结果,通常也没有必要使用注释。在热循环中使用该指令不太可能帮助提高性能。如果分支确实有很强的偏差,那么即使没有程序员注释,预测器也能在大多数情况下正确预测结果。

在大多数现代处理器上,分支预测器的性能都非常好(即使在复杂的工作负载上也能达到 95% 以上的准确率)。所以作为一个微优化,试图提高分支预测的准确性可能不是应用程序程序员想要关注的事情。通常,编译器会更好地生成适用于它所针对的特定硬件平台的最佳代码。

但是分支预测器依赖于识别模式,如果应用程序以不存在模式的方式编写,那么分支预测器将表现不佳。如果可以修改应用程序以便有一个模式,那么分支预测器就有机会做得更好。如果您发现分支确实预测不佳的情况,您可能可以在高级语言级别考虑这一点。

【讨论】:

    【解决方案2】:

    像缓存和流水线这样的分支预测是为了使代码运行得更快,通常可以克服系统中的瓶颈(所有 dram 都是超慢的廉价 dram,X 和 Y 之间的所有总线层等)。

    没有办法在高级语言中做任何事情来优化分支预测,缓存当然,有时你可以,但是分支预测,一点也不。为了进行预测,核心必须在管道中拥有分支以及在它之前的指令,并且跨架构和实现不可能找到一个有效的规则。通常甚至不在高级语言的一种架构和实现中。

    您也可能很容易陷入这样一种情况,即调整分支预测,而您可能希望使用缓存或管道或其他优化来代替调整。并且整体性能首先是特定于应用程序的,然后是针对该应用程序进行调整的,而不是通用的。

    尽管我喜欢在高级语言级别宣扬和进行优化,但分支预测属于过早优化类别。如果尚未启用,只需在核心中启用它,有时它会为您节省几个周期,大多数情况下它不会,并且根据实现,它可能会花费更多的周期而不是节省的时间。就像缓存一样,它与命中与未命中有关,如果它猜对了,那么您的代码在更快的内存中就可以更快地到达管道,如果它猜错了,那么您已经烧毁了可能被之前的代码使用的总线周期将要运行。

    缓存通常是一个好处(尽管编写高级代码并不难,表明它会降低性能而不是节省),因为代码通常在分支之前线性地运行一些指令。同样,为了克服惩罚,经常访问数据。分支不是我们每条指令都做的事情,我们分支到的地方没有一个共同的答案。

    您的后端可以尝试调整分支预测,方法是让预分支决策在分支前几个周期发生,但都在管道大小内,并针对获取行或缓存行对齐进行调整。这再次与核心中其他功能的调整混淆了。

    【讨论】:

    • “没有办法在高级语言中做任何事情来优化分支预测”我不同意。您可以在高级语言中做的一件事是通过查找或算术表达问题来消除分支。这有助于分支预测在其余分支上更好地工作,因为有更多“历史”可用。我使用这种方法对瓶颈代码进行了巨大的性能改进。
    • 它必须是直接代码,没有函数调用,你能做的数学非常有限,等等。当然你可以维持一点点但不能长时间。可能已经优化并且没有那么多行,使下一个分支更快。
    • “直接代码,没有函数调用”,无论如何,分支预测可能会产生最大的不同。非常适合紧凑的循环,但对于一般代码不太有趣。
    猜你喜欢
    • 2018-07-02
    • 2019-06-15
    • 2015-11-24
    • 2014-07-31
    • 1970-01-01
    • 2013-04-21
    • 2019-06-04
    • 2017-01-30
    • 2022-01-10
    相关资源
    最近更新 更多