优化分支预测:如何使用不同的编译器、解释器和硬件预测来泛化 运行 的代码?

Optimizing branch predictions: how to generalize code that could run wth different compiler, interperter, and hardware prediction?

我 运行 今天在一个由 If 语句引起的紧密循环中速度变慢,这让我有些吃惊,因为我预计 b运行ch 预测会成功地流水线化特定语句以最小化条件成本。

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

深入观察我知道 b运行ch 预测可以在几个级别上完成:

  1. 具有指令流水线的硬件本身
  2. C++ 风格的编译器
  3. 口译语言的口译员。
  4. 像java这样的半编译语言可能会做上面的两三个。

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

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

无论使用何种解释器,是否存在通常可以安全做出的某些假设?是否必须深入研究一种语言的复杂规范才能对 b运行ch 预测做出任何有意义的假设?

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

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

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

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

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

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

简答:

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

详情

此问题的 之一声称:

There is no way to do anything at the high level language to optimize for branch prediction, caching sure, sometimes you can, but branch prediction, no not at all.

然而,这根本不是真的。 most famous questions on Stack Overflow.

之一很好地说明了这一事实

所有分支预测器都通过识别重复代码执行的模式并根据需要使用此信息来预测结果 and/or 分支目标来工作。

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

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

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