我一直在挖掘Linux内核的某些部分,发现这样的调用:
if (unlikely(fd < 0))
{
/* Do something */
}
Run Code Online (Sandbox Code Playgroud)
要么
if (likely(!err))
{
/* Do something */
}
Run Code Online (Sandbox Code Playgroud)
我找到了它们的定义:
#define likely(x) __builtin_expect((x),1)
#define unlikely(x) __builtin_expect((x),0)
Run Code Online (Sandbox Code Playgroud)
我知道它们是为了优化,但它们是如何工作的?使用它们可以预期性能/尺寸减少多少?至少在瓶颈代码中(当然在用户空间中)是否值得麻烦(并且可能失去可移植性).
具体来说,如果我有一系列if... else if语句,并且我事先知道每个语句将评估的相对概率,true它按照概率的顺序对它们进行排序有多大差异?例如,我应该更喜欢这个:
if (highly_likely)
//do something
else if (somewhat_likely)
//do something
else if (unlikely)
//do something
Run Code Online (Sandbox Code Playgroud)
对此?:
if (unlikely)
//do something
else if (somewhat_likely)
//do something
else if (highly_likely)
//do something
Run Code Online (Sandbox Code Playgroud)
很明显,排序版本会更快,但是为了便于阅读或存在副作用,我们可能希望对它们进行非最佳排序.在您实际运行代码之前,很难判断CPU在分支预测方面的表现如何.
因此,在尝试这个过程中,我最终回答了我自己的问题,但我还想听听其他意见/见解.
重要提示:此问题假定if语句可以任意重新排序,而不会对程序的行为产生任何其他影响.在我的回答中,三个条件测试是互斥的,不会产生副作用.当然,如果必须按某种顺序评估陈述以达到某些预期的行为,那么效率问题就没有实际意义.
我理解这里解释的内容以及这些内容包括CPU对静态分支预测的提示.
我想知道英特尔CPU上的这些是如何相关的,因为英特尔CPU已经放弃了对这里提到的静态预测提示的支持.此外,如果我理解它现在如何工作,路径中的分支指令的数量将是编译器可以控制的唯一事物,并且在运行时决定预测,获取和解码哪个分支路径.
鉴于此,是否存在代码中的分支提示对于针对最近的英特尔处理器的软件仍然有用的情况,可能使用条件返回或者在嵌套的if/else语句的情况下避免关键路径中的分支指令数量?
此外,如果这些仍然相关,那么gcc和其他流行编译器的任何细节都会受到赞赏.
PS我不是为了过早优化或者用这些宏来编写代码,但是我对这个主题很感兴趣,因为我正在使用一些时间关键代码,并且仍然希望尽可能减少代码混乱.
谢谢
请考虑以下代码:
void error_handling();
bool method_impl();
bool method()
{
const bool res = method_impl();
if (res == false) {
error_handling();
return false;
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
我知道当时method_impl()会返回true99.999%(是的,三位小数),但我的编译器没有.method()在时间消耗方面是部分关键.
method()(并使其不太可读)以确保只有在method_impl()返回时才会发生跳转false?如果有,怎么样?c++ ×2
gcc ×2
optimization ×2
assembly ×1
boost ×1
c ×1
if-statement ×1
intel ×1
linux ×1
linux-kernel ×1
performance ×1