Linux内核likely()和unlikely()

Linux内核中多次出现likely()unlikely()的使用,他们的定义如下:

1
2
#define likely(x)     __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)

__builtin_expect是GCC提供的内置函数(built-in functions),函数原型是

1
long __builtin_expect(long exp, long c);

函数的返回值就是exp,不过他告诉编译器,代码期望的是exp == c, 如果exp == c条件成立的机会占绝大多数,那么程序运行性能将会得到提升,否则性能反而会下降

builtin_expect()用来引导gcc进行条件分支预测,在一条指令执行时,由于流水线的作用,CPU可以同时完成下一条指令的预取,这样可以提高CPU的利用率,在执行条件分支时,CPU也会预期下一条指令,但是如果预测的结果不为exp == c那么CPU预取的下一条指令就没用了,这样就降低了流水线的效率,跳转指令相对于顺序执行的指令会多消CPU时间,如果可以尽可能不执行跳转,也可以提高CPU性能。

表面上看if(likely(value))if(unlikely(value))都等同于if(value),也就是likely()unlikely()作用是一样的,但是实际上执行的效果是不同的(从指令预测的角度上来说),加likely的意思是value为真的可能性更大一些,那么预测执行if的可能性要大些,unlikely正好相反。

加上这种修饰,编译成二进制代码时likely使得if后面的执行语句紧跟着前面的程序,unlikely使得else后面的语句紧跟着前面的程序,这样就会被cache预读取,增加程序的执行速度。