likely和unlikely

来源:互联网 发布:断食四天减肥知乎 编辑:程序博客网 时间:2024/06/06 03:44
首先明确:
       likely与unlikely互换或不用都不会影响程序的正确性。但可能会影响程序的效率。
在阅读linux内核代码时经常出现likely()和unlikely()两个宏函数,位于/include/linux/compiler.h中
  #define likely(x)    __builtin_expect(!!(x), 1)  
  #define unlikely(x)  __builtin_expect(!!(x), 0)  
  这里的__built_expect()函数是gcc(version >= 2.96)的内建函数,提供给程序员使用的,目的是将"分支转移"的信息提供给编译器,这样编译器对代码进行优化,以减少指令跳转带来的性能下降。
       在一条指令执行时,由于流水线的作用,CPU可以同时完成下一条指令的取指,这样可以提高CPU的利用率。在执行条件分支指令时,CPU也会预取下一条执行,但是如果条件分支的结果为跳转到了其他指令,那CPU预取的下一条指令就没用了,这样就降低了流水线的效率。因此跳转指令相对于顺序执行的指令会多消耗CPU时间,如果可以尽可能不执行跳转,也可以提高CPU性能。
       __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的功能就是添加cache的命中率,提高系统执行速度。
原创粉丝点击