在 2.6 内核中,随处能够见到 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 后面的语句的机会更大。

比如以下这段代码,作者就觉得 prev 不等于 next 的可能性更大,

if (likely(prev != next)) {
next->timestamp = now;
...
} else {
...;
}

通过这样的方式,编译器在编译过程中,会将可能性更大的代码紧跟着起面的代码,从而降低指令跳转带来的性能上的下降。

另外内核2.6.31.5中likely和unlikely另一种定义:
# ifndef likely
# define likely(x) (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 1))
# endif # ifndef unlikely
# define unlikely(x) (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 0))
# endif

举个样例(内核版本号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互换或不用都不会影响程序的正确性。

但可能会影响程序的效率。

Linux 内核中 likely 与 unlikely 的宏定义解析的更多相关文章

  1. Linux内核中的fastcall和asmlinkage宏

    代码中看见:#define _fastcall 所以了解下fastcall -------------------------------------------------------------- ...

  2. 《linux 内核全然剖析》 笔记 CODE_SPACE 宏定义分析

    在memory.c里面.遇到一个宏定义,例如以下: #define CODE_SPACE(addr) ((((addr)+4095)&~4095) < \ current->sta ...

  3. Linux内核中_IO,_IOR,_IOW,_IOWR宏的用法与解析【转】

    转自:http://blog.csdn.net/hzn407487204/article/details/7995041 在驱动程序里, ioctl() 函数上传送的变量 cmd 是应用程序用于区别设 ...

  4. Linux内核中_IO,_IOR,_IOW,_IOWR宏的用法与解析

    ref from : http://blog.csdn.net/zhuxiaoping54532/article/details/49680537 main 在驱动程序里, ioctl() 函数上传送 ...

  5. Linux内核中_IO,_IOR,_IOW,_IOWR宏的用法

    #define _IO(type,nr)        _IOC(_IOC_NONE,(type),(nr),0) #define _IOR(type,nr,size)    _IOC(_IOC_RE ...

  6. (十)Linux内核中的常用宏container_of

    Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址. Containe ...

  7. Linux内核中的常用宏container_of

    Container_of在Linux内核中是一个常用的宏,用于从包含在某个结构中的指针获得结构本身的指针,通俗地讲就是通过结构体变量中某个成员的首地址进而获得整个结构体变量的首地址. Containe ...

  8. Linux内核中的常用宏container_of其实很简单【转】

    转自:http://blog.csdn.net/npy_lp/article/details/7010752 开发平台:Ubuntu11.04 编 译器:gcc version 4.5.2 (Ubun ...

  9. 嵌入式C语言自我修养 01:Linux 内核中的GNU C语言语法扩展

    1.1 Linux 内核驱动中的奇怪语法 大家在看一些 GNU 开源软件,或者阅读 Linux 内核.驱动源码时会发现,在 Linux 内核源码中,有大量的 C 程序看起来“怪怪的”.说它是C语言吧, ...

随机推荐

  1. gulp-uglify的使用

    gulp教程之gulp-uglify 简介: 使用gulp-uglify压缩javascript文件,减小文件大小. 1.安装nodejs/全局安装gulp/项目安装gulp/创建package.js ...

  2. GPIO实验(一)

    目标:点亮LED1.看原理图,找到对应的引脚和寄存器2.a.配置寄存器为输入/出引脚    GPFCON[9:8]=0b01  b.设置输出高/低电平    GPDAT[4]=0b0 1.预处理2.编 ...

  3. 原声js实现addClass removeClass toggleClass效果

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  4. eclipse javaee 插件安装

    eclipese 精简版安装java ee插件 , 按图走  (eclipse 版本 : Indigo Service Release 1   (3.7.1)) java ee 在线安装地址: htt ...

  5. FreeRTOS 独立看门狗监测任务执行状态

    以下转载自安富莱电子: http://forum.armfly.com/forum.php 通过前面的几个章节,我们基本已经完成了 FreeRTOS 所有功能的讲解,本章节为大家介绍一种使用独立看门狗 ...

  6. 使用寄存器点亮LED——编程实战

    stm32的编程和stc89c51还是存在着很多思想上的不同的,在51单片机中,我们点亮LED灯,只用给对应IO高低电平就可以了,而stm32中,就一个简单的GPIO,我们也需要配置好几个寄存器,而且 ...

  7. Lo4j(二)级别和优化

    在log里面有日志级别: DEBUG Level: 指出细粒度信息事件对调试应用程序是非常有帮助的,就是输出debug的信息.INFO level: 表明消息在粗粒度级别上突出强调应用程序的运行过程, ...

  8. RDLC设计

    1.rdlc报表的日期格式"yyyy/mm/dd 00/00/00"转换为"yyyy-mm-dd" =System.Convert.ToDateTime(Fie ...

  9. Thrift RPC框架介绍

    u 简介 Thrift是一种开源的跨语言的RPC服务框架.Thrift最初由facebook公司开发的,在2007年facebook将其提交apache基金会开源了.对于当时的facebook来说创造 ...

  10. BusyBox init工作流程

    linux启动完成后,运行由Busybox产生的init进程. /sbin/init是系统启动的第一个用户进程,pid=1.init的工作是根据/etc/inittab脚本来进行系统的初始化工作,关机 ...