Linux内核中很多地方都用到了likely()与unlikely(),尤其是错误处理的地方,为何要用这两个宏呢?
大多数时候,linux内核会把一个变量与一个外部值比较来看某一条件是否已满足,这种比较的结果很大程度上是可以预测的。这样的例子很常见,例如检查合法性的代码。内核使用likely和unlikely两个宏分别表示返回的结果是true(1)或false(0)。这两个宏使用gcc可根据它的返回值来优化编译结果的特性来提升代码的性能。
这里有个例子,我们假设调用do_something()函数,在出错的情况下,我们调用handle_error来处理错误:
err = do_something(x, y, z);
if(err)
handle_error(err);
如果do_something很少出错,我们可以将代码重写为:
err = do_something(x, y, z);
if(unlikely(err))
handle_error(err);
下面具体分析likely和unlikely
首先要明确:
if(likely(value)) 等价于 if(value)
if(unlikely(value)) 也等价于 if(value)
也就是说 likely() 和 unlikely() 从阅读和理解代码的角度来看,是一样的!
这两个宏在内核中定义如下:
#define likely(x) __builtin_expect((x),1)
#define unlikely(x) __builtin_expect((x),0)
__builtin_expect() 是 GCC (version >= 2.96)提供给程序员使用的,目的是将“分支转移”的信息提供给编译器,这样编译器可以对代码进行优化,以减少指令跳转带来的性能下降。
__builtin_expect((x),1) 表示 x 的值为真的可能性更大;
__builtin_expect((x),0) 表示 x 的值为假的可能性更大。
也就是说,使用 likely() ,执行 if 后面的语句 的机会更大,使用unlikely(),执行else 后面的语句的机会更大。