我一直在研究Linux内核的某些部分,并找到了如下调用:
if (unlikely(fd < 0)) { /* Do something */ }
要么
if (likely(!err)) { /* Do something */ }
我找到了它们的定义:
#define likely(x) __builtin_expect((x),1) #define unlikely(x) __builtin_expect((x),0)
我知道它们是为了优化,但是它们如何工作?使用它们可以预期多少性能/尺寸下降?至少在瓶颈代码中(当然在用户空间中)值得麻烦(并且可能会失去可移植性)。
它们提示编译器发出指令,这些指令将导致分支预测偏向跳转指令的“可能”一侧。如果预测正确,这将是一个巨大的胜利,这意味着跳转指令基本上是免费的,将花费零个周期。另一方面,如果预测错误,则意味着需要清除处理器管道,这可能会花费多个周期。只要预测在大多数时间都是正确的,这将对性能有好处。
像所有这样的性能优化一样,您应该只在进行广泛的性能分析后才能执行此操作,以确保代码确实处于瓶颈,并且可能考虑到微观性质,因此代码正在紧密循环中运行。通常,Linux开发人员都非常有经验,所以我想他们会做到的。他们并不十分在意可移植性,因为它们只针对gcc,并且对要生成的程序集有着非常密切的了解。