我一直在深入研究Linux内核的一些部分,发现了这样的调用:
if (unlikely(fd < 0))
{
/* Do something */
}
or
if (likely(!err))
{
/* Do something */
}
我找到了它们的定义:
#define likely(x) __builtin_expect((x),1)
#define unlikely(x) __builtin_expect((x),0)
我知道它们是为了优化,但它们是如何工作的呢?使用它们可以减少多少性能/大小?至少在瓶颈代码中(当然是在用户空间中),这样做是否值得(可能还会失去可移植性)。
long __builtin_expect(long EXP, long C);
这个构造告诉编译器表达式EXP . xml
最有可能的值是c。返回值是EXP。
__builtin_expect用于条件句
表达式。在几乎所有的情况下,它将被用于
上下文的布尔表达式在这种情况下,它是很多
定义两个helper宏更方便:
#define unlikely(expr) __builtin_expect(!!(expr), 0)
#define likely(expr) __builtin_expect(!!(expr), 1)
这些宏可以用于
if (likely(a > 1))
参考:https://www.akkadia.org/drepper/cpumemory.pdf
根据Cody的评论,这与Linux无关,但这是对编译器的一个提示。会发生什么取决于体系结构和编译器版本。
Linux中的这个特殊特性在驱动程序中被误用了。正如osgx在hot属性语义中指出的那样,在一个块中调用的任何热函数或冷函数都可以自动提示该条件是否可能。例如,dump_stack()被标记为冷,所以这是多余的,
if(unlikely(err)) {
printk("Driver error found. %d\n", err);
dump_stack();
}
gcc的未来版本可能会根据这些提示选择性地内联一个函数。也有建议说,它不是布尔值,而是一个分数,就像在最有可能,等等。一般来说,应该优先使用一些替代机制,如冷。没有理由在炎热的道路以外的任何地方使用它。编译器在一种架构上的功能在另一种架构上可能完全不同。
long __builtin_expect(long EXP, long C);
这个构造告诉编译器表达式EXP . xml
最有可能的值是c。返回值是EXP。
__builtin_expect用于条件句
表达式。在几乎所有的情况下,它将被用于
上下文的布尔表达式在这种情况下,它是很多
定义两个helper宏更方便:
#define unlikely(expr) __builtin_expect(!!(expr), 0)
#define likely(expr) __builtin_expect(!!(expr), 1)
这些宏可以用于
if (likely(a > 1))
参考:https://www.akkadia.org/drepper/cpumemory.pdf