哪种代码更适合分支预测优化?


10

给定分支预测以及编译器优化的效果,哪种代码倾向于提供出色的性能?

请注意,bRareExceptionPresent表示不常见的情况。这不是逻辑的正常路径。

/* MOST COMMON path must branch around IF clause */

bool SomeFunction(bool bRareExceptionPresent)
{
  // abort before function
  if(bRareExceptionPresent)
  {
     return false;
  }    
  .. function primary body ..    
  return true;
}

/* MOST COMMON path does NOT branch */

bool SomeFunction(bool bRareExceptionPresent)
{
  if(!bRareExceptionPresent)
  {
    .. function primary body ..
  }
  else
  {
    return false;
  }
  return true;
}

9
我要走到这里,说没有任何区别。
罗伯特·哈维

7
这可能取决于您要编译的特定CPU,因为它们具有不同的流水线架构(延迟插槽与无延迟插槽)。您花费在思考上的时间可能比运行时节省的时间要多得多-先配置文件,然后进行优化。

2
几乎可以肯定,这是过早的微优化。
罗伯特·哈维

2
@MichaelT是的,分析确实是了解目标平台上的代码在其上下文中性能实际发生状况的唯一可靠方法。但是,我很好奇一个人是否普遍被优先考虑。
dyasta

1
@RobertHarvey:它是过早微优化,除了在情况下两个条件被满足:(1)循环是倍称为十亿(未百万); (2)具有讽刺意味的是,当循环体在机器代码方面很小时。条件#2意味着,与在有用工作上花费的时间相比,在开销上花费的时间比例并不小。好消息是,通常,在同时满足两个条件的情况下,本质上无分支的SIMD(矢量化)将解决所有性能问题。
rwong

Answers:


10

在当今世界,这根本无关紧要。

动态分支预测(几十年来一直在想的事情(请参阅1996年发布的《系统工作负载的动态分支预测方案分析》))非常普遍。

一个示例可以在ARM处理器中找到。来自Arm信息中心的分支预测

为了提高分支预测精度,采用了静态和动态技术的组合。

那么问题是“手臂处理器中的动态分支预测是什么?” 对动态分支预测的连续阅读显示,它使用2位预测方案(在本文中进行了描述)建立有关是否强采用或不采用分支的信息。

随着时间的流逝(有时,我指的是通过该块的次数),这会积累有关代码执行方式的信息。

对于静态预测,它着眼于代码本身的外观以及在测试上进行分支的方式-到上一条指令或代码中的另一条指令:

ARM1136JF-S处理器中使用的方案预测,不会采用所有前向条件分支,而会采用所有后向分支。在所有分支中约有65%之前,有足够的非分支周期可以完全预测。

正如Sparky所提到的,这是基于对循环(而不是循环)的理解。循环向后分支(循环的末尾有一个分支,可在顶部重新启动)-通常这样做。

试图再次猜测编译器的危险是您不知道该代码实际上将如何编译(和优化)。在大多数情况下,这并不重要。使用动态预测时,通过该函数两次,它将预测跳过保护语句以过早返回。如果两个冲洗管道的性能至关重要,则还需要担心其他事情。

与另一种样式相比,阅读一种样式所花费的时间可能更重要-使代码干净以便人类可以阅读,因为无论您编写代码有多杂乱或理想化,编译器都会做的很好。


7
一个著名的stackoverflow问题表明,即使在今天,分支预测也很重要。
Florian Margaine 2013年

3
@FlorianMargaine虽然很重要,但是在真正重要的情况下,似乎需要了解您要编译的内容及其工作方式(arm vs x86 vs mips ...)。从一开始就编写试图进行这种微优化的代码可能是在错误的前提下进行的,无法达到预期的效果。

当然,我们不要引用DK。但是我认为,当您已经超出分析阶段时,这个问题显然是在优化意义上的。:-)
Florian Margaine

2
@MichaelT不错的答案,我非常同意你的结论。这种预分析/抽象优化肯定会适得其反。它最终成为一种猜测游戏,由于非理性的原因导致人们做出设计决策。不过,我仍然感到好奇; o
dyasta 2013年


9

我的理解是,CPU第一次遇到分支时,它将预测(如果支持)不采用前向分支,而采用后向分支。这样做的理由是假定采用了循环(通常向后分支)。

在某些处理器上,您可以在汇编指令中提示一条更可能的路径。此刻的细节让我此刻不解。

另外,某些C编译器还支持静态分支预测,因此您可以告诉编译器哪个分支更有可能。反过来,它可能会重新组织生成的代码,或使用修改后的指令来利用此信息(甚至完全忽略它)。

__builtin_expect((long)!!(x), 1L)  /* GNU C to indicate that <x> will likely be TRUE */
__builtin_expect((long)!!(x), 0L)  /* GNU C to indicate that <x> will likely be FALSE */

希望这可以帮助。


3
“我的理解是,CPU第一次遇到分支时,它将预测(如果支持)不采用前向分支而采用后向分支。” 这是一个非常有趣的想法。您是否有证据表明这确实是在通用体系结构中实现的?
blubb

5
直接从马口中拉出:默认情况下,未取用向前分支。向后分支默认为take。并且在同一页面上:“前缀0x3E –静态预测所采用的分支”。
MSalters 2013年

是否有可用于平台的不可知论杂语__builtin_expect
MarcusJ
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.