看内核时总遇到if(likely( )){}或是if(unlikely( ))这样的语句,最初不解其意,现在有所了解,所以也想介绍一下。


likely() 与 unlikely()是内核(我看的是2.6.22.6版本,2.6的版本应该都有)中定义的两个宏。位于/include/linux/compiler.h中,

具体定义如下:

#define likely(x) __builtin_expect(!!(x), 1)

#define unlikely(x) __builtin_expect(!!(x), 0)


__builtin_expect是gcc(版本>=2.96,网上写的,我没验证过)中提供的一个预处理命令(这个名词也是网上写的,我想叫函数更好些),有利于代码优化。gcc(version 4.4.0)具体定义如下:

long __builtin_expect (long exp, long c) [Built-in Function]


注解为:

You may use __builtin_expect to provide the compiler with branch prediction information. In general, you should prefer to use actual profile feedback for this (‘-fprofile-arcs’), as programmers are notoriously bad at predicting how their programs actually perform. However, there are applications in which this data is hard to collect.The return value is the value of exp, which should be an integral expression. The semantics of the built-in are that it is expected that exp == c.


它的意思是:我们可以使用这个函数人为告诉编绎器一些分支预测信息“exp==c” 是“很可能发生的”。


#define likely(x) __builtin_expect(!!(x), 1)也就是说明x==1是“经常发生的”或是“很可能发生的”。

使用likely ,执行if后面语句的可能性大些,编译器将if{}是的内容编译到前面, 使用unlikely ,执行else后面语句的可能性大些,编译器将else{}里的内容编译到前面。这样有利于cpu预取,提高预取指令的正确率,因而可提高效率。


举个例子(内核版本2.6.22.6):/kernel/shed.c中有一段:

if (likely(!active_balance)) {

/* We were unbalanced, so reset the balancing interval */

sd->balance_interval = sd->min_interval;

} else {

/*

* If we've begun active balancing, start to back off. This

* case may not be covered by the all_pinned logic if there

* is only 1 task on the busy runqueue (because we don't call

* move_tasks).

*/

if (sd->balance_interval max_interval)

sd->balance_interval *= 2;

}


编译过程中,会将if后面{}里的内容编译到前面,else 后面{}里的内容编译到后面。若将likely换成unlikely 则正好相反。


总之,likely与unlikely互换或不用都不会影响程序的正确性。但可能会影响程序的效率。

 

if(likely(foo))  //认为foo通常为1

if(unlikely(foo)) //认为foo通常为0

 


首先明确:

 if (likely(value))等价于if (value)

 if (unlikely(value))等价于if (value)


也就是说likely()和unlikely()从阅读和理解的角度是一样的。


这两个宏在内核中定义如下:


<linux/compiler>


#define likely(x) __builtin_expect(!!(x), 1)

#define unlikely(x) __builtin_expect(!!(x), 0)

这里的__built_expect()函数是gcc(version >= 2.96)的内建函数,提供给程序员使用的,目的是将"分支转移"的信息提供给编译器,这样编译器对代码进行优化,以减少指令跳转带来的性能下降。

__buildin_expect((x), 1)表示x的值为真的可能性更大.

__buildin_expect((x), 0)表示x的值为假的可能性更大.

也就是说,使用likely(),执行if后面的语句的机会更大,使用unlikely(),执行else后面的语句机会更大一些。通过这种方式,编译器在编译过程中,会将可能性更大的代


码紧跟着后面的代码,从而减少指令跳转带来的性能上的下降。


比如 :

if (likely(a>b)) {

  fun1();


}

if (unlikely(a<b)) {

 fun2();

}


  这里就是程序员可以确定 a>b 在程序执行流程中出现的可能相比较大,因此运用了likely()告诉编译器将fun1()函数的二进制代码紧跟在前面程序的后面,这样就


cache在预取数据时就可以将fun1()函数的二进制代码拿到cache中。这样,也就添加了cache的命中率。


  同样的,unlikely()的作用就是告诉编译器,a<b 的可能性很小所以这里在编译时,将fun2()的二进制代码尽量不要和前边的编译在一块。


  咱们不用对likely和unlikely感到迷惑,须要知晓的就是 if(likely(a>b)) 和 if(a>b)在功能上是等价的,同样 if(unlikely(a<b)) 和 if(a<b) 的功能也是一样的。不一样的只是他们声称的二进制代码有所不一样,这一点咱们也可以从他们的汇编代码中看到。


  比如下面的代码:


  #include <stdio.h>


  #define unlikely(x) __builtin_exp ect(!!(x), 0)


  #define likely(x) __builtin_exp ect(!!(x), 1)


int main()


  {


  int a=2,b=4;


  if(unlikely(a<b)) {


  printf("in the unlikely,is not your exp ecting!\n");


  } else {


  printf("in the unlikely, is your exp ecting\n");


  }


  if(likely(a<b)) {


  printf("in the likely, is your exp ecting\n");


  }


  return 0;


  }


  执行结果:


  in the unlikely,is not your exp ecting!


  in the likely, is your exp ecting


  总之,likely和unlikely的功能就是添加 cache的命中率,提高系统执行速度