分支预测的加速是否取决于谓词的复杂性?



假设我有一个函数IsTrue(),它返回一个bool。如果程序员决定IsTrue()通常会返回true,那么在那些典型的情况下,她可能会使用GCC的__builtin_expect或类似的方法来加速指令。

举以下两个例子:

// example 1
const bool result = IsTrue();
if (__builtin_expect(result, true))
  // do something
  ;
// example 2
if (__builtin_expect(IsTrue(), true))
  // do something
  ;

假设IsTrue是非平凡的,它们之间有什么区别吗?将IsTrue()放置在__builtin_expect参数列表中是否会导致在IsTrue的结果已知之前对指令缓存进行评估,或者分支预测仅在计算IsTrue的结果之后应用?

所有现代处理器都采用超标量流水线,它在实际执行的指令之后预计算指令。通过使用__builtin_expect,编译器对指令进行重新排序,这样预期的(可能的)路径就不会使用导致超标量管道丢失的跳转,从而使所有预先计算的结果都变得无用。

编辑:这当然是简化了。现代处理器也有分支预测,因此它们试图预测代码将遵循哪条路径,但没有跳跃的路径仍然是首选(这对缓存也更好,因为执行的代码路径紧凑)。还要注意,这些速度上的变化通常是非常微小的,如果你的代码不是经常执行,或者确实需要尽可能多的速度,你就不需要麻烦了。

正如GCC文档所说,与使用__builtin_expect进行编写相比,更喜欢使用概要文件引导的优化(PGO、-fprofile-generate,然后运行测试用例并使用-fprofile-use进行重建)进行构建。

CPU内置的分支预测将缓存程序"典型"执行路径中的大多数分支。静态分支预测主要在所有分支上提供强数据时起作用,因此当编译器可以在先进行几个测试中的一个测试之间进行选择时,它可以安排最有效的序列。这不仅考虑了解析为什么值,还考虑了最频繁地选择哪个else if语句。

CCD_ 16很少有什么不同。对于分支程序,-fprofile-use通常会在无需编程的情况下提供10-30%的即时提升。

IsTrue()放置在__builtin_expect参数列表中是否会导致在IsTrue的结果已知之前对指令缓存进行评估,还是仅在计算出IsTrue的结果之后才应用分支预测?

__builtin_expect发生在编译时。指令缓存甚至还不存在。编译器会猜测IsTruetrue,然后在运行时,CPU会做出另一个更明智的猜测。

最新更新