有没有可行的分支预测提示方法?请考虑以下示例:
if (unlikely_condition) {
/* ..A.. */
} else {
/* ..B.. */
}
这与做的有什么不同:
if (!unlikely_condition) {
/* ..B.. */
} else {
/* ..A.. */
}
或者是使用编译器特定提示的唯一方法? (例如海湾合作委员会的__builtin_expect)
编译器是否会根据条件的顺序对if
条件进行不同的处理?
答案 0 :(得分:26)
进行静态分支预测的规范方法是预测if
不分支(即执行每个if
子句,而不是else
),循环和后退 - {{ 1}}被采取。因此,如果您希望静态预测具有重要意义,请不要将常见情况放在goto
中。绕过一个未被捕获的循环并不容易;我从来没有尝试过,但我想把它放在一个else
条款应该可以很方便地工作。
许多编译器支持某种形式的else
,但仍需要使用某种#pragma unroll
来保护它以保护其他编译器。
分支预测提示理论上可以表达如何转换程序的流控制图并在可执行存储器中排列基本块的完整描述......所以有很多要表达的东西,而且大多数都不会非常便携。
正如GNU在#if
的文档中所建议的那样,配置文件引导的优化优于提示,而且工作量更少。
答案 1 :(得分:17)
在大多数情况下,以下代码
if (a)
{
...
}
else
{
...
}
实际上是
evaluate(A)
if (!A)
{
jmp p1
}
... code A
jmp p2
p1:
... code !A
p2:
请注意,如果A为true,则“代码A”已在管道中。处理器将提前看到“jmp p2”命令,并将p2代码加载到管道。
如果A为假,则“代码!A”可能不在pipleline中,因此可能会更慢。
结论:
evaluate(A)
do more stuff
if (A)
...
答案 2 :(得分:7)
优化本质上是一个编译器,所以你必须使用编译器功能来帮助它。语言本身并不关心(或授权)优化。
所以你可以做的最好的事情没有特定于编译器的扩展就是组织你的代码,使你的编译器在没有帮助的情况下“做正确的事情”。但是如果你想确定,请点击编译器扩展。 (您可以尝试在预处理器后面抽象它们,这样您的代码仍然可移植。)
答案 3 :(得分:5)
C ++ 20提供likely and unlikely attributes
允许编译器针对执行路径进行优化 包含该陈述的可能性比其他任何可能性都大 不包含此类声明的执行路径
答案 4 :(得分:1)
与你的工作保持一致。我喜欢用
if (!(someExpression))
但是编译器应该平等对待它。
答案 5 :(得分:1)
通过#ifdef
检查特定编译器并将这些内容隐藏在自定义宏后面有什么问题?如果没有支持这些优化提示的编译器,您可以#define
扩展为简单表达式。我最近做了一些与GCC通过内部函数支持的显式缓存预取类似的东西。