内核中的 likely() 与 unlikely()

在 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 {         ...; }

通过这种方式,编译器在编译过程中,会将可能性更大的代码紧跟着起面的代码,从而减少指令跳转带来的性能上的下降。
下面以两个例子来加深这种理解:
第一个例子: example1.c

int testfun(int x) {         if(__builtin_expect(x, 0)) {                               ^^^--- We instruct the compiler, "else" block is more probable                 x = 5;                 x = x * x;         } else {                 x = 6;         }         return x; }

在这个例子中,我们认为 x 为0的可能性更大
编译以后,通过 objdump 来观察汇编指令,在我的 2.4 内核机器上,结果如下:
# gcc -O2 -c  example1.c # objdump -d  example1.o

Disassembly of section .text:
00000000 <testfun>:    0:   55                      push   %ebp    1:   89 e5                   mov    %esp,%ebp    3:   8b 45 08                mov    0x8(%ebp),%eax    6:   85 c0                   test   %eax,%eax    8:   75 07                   jne    11 <testfun+0x11>    a:   b8 06 00 00 00          mov    $0x6,%eax    f:   c9                      leave   10:   c3                      ret   11:   b8 19 00 00 00          mov    $0x19,%eax   16:   eb f7                   jmp    f <testfun+0xf>

可以看到,编译器使用的是 jne (不相等跳转)指令,并且 else block 中的代码紧跟在后面。
8:   75 07                   jne    11 <testfun+0x11> a:   b8 06 00 00 00          mov    $0x6,%eax
第二个例子: example2.c

int testfun(int x) {         if(__builtin_expect(x, 1)) {                               ^^^ --- We instruct the compiler, "if" block is more probable                 x = 5;                 x = x * x;         } else {                 x = 6;         }         return x; }

在这个例子中,我们认为 x 不为 0 的可能性更大 编译以后,通过 objdump 来观察汇编指令,在我的 2.4 内核机器上,结果如下: # gcc -O2 -c  example2.c # objdump -d  example2.o

Disassembly of section .text:
00000000 <testfun>:    0:   55                      push   %ebp    1:   89 e5                   mov    %esp,%ebp    3:   8b 45 08                mov    0x8(%ebp),%eax    6:   85 c0                   test   %eax,%eax    8:   74 07                   je     11 <testfun+0x11>    a:   b8 19 00 00 00          mov    $0x19,%eax    f:   c9                      leave   10:   c3                      ret   11:   b8 06 00 00 00          mov    $0x6,%eax   16:   eb f7                   jmp    f <testfun+0xf>

这次编译器使用的是 je (相等跳转)指令,并且 if block 中的代码紧跟在后面。    8:   74 07                   je     11 <testfun+0x11>    a:   b8 19 00 00 00          mov    $0x19,%eax

内核中的 likely() 与 unlikely()的更多相关文章

  1. Linux 2.6内核中新的锁机制--RCU

    转自:http://www.ibm.com/developerworks/cn/linux/l-rcu/ 一. 引言 众所周知,为了保护共享数据,需要一些同步机制,如自旋锁(spinlock),读写锁 ...

  2. Linux 内核中的 Device Mapper 机制

    本文结合具体代码对 Linux 内核中的 device mapper 映射机制进行了介绍.Device mapper 是 Linux 2.6 内核中提供的一种从逻辑设备到物理设备的映射框架机制,在该机 ...

  3. Unix内核中打开文件的表示

    Unix内核中已经打开文件,通过三种数据结构表示: 每个进程的进程表中的记录项,包含打开的文件的文件描述符表,与之关联的是: 文件描述符标识 指向一个文件表项的指针 内核为所有打开文件维持一张文件表, ...

  4. 内核中用于数据接收的结构体struct msghdr(转)

    内核中用于数据接收的结构体struct msghdr(转) 我们从一个实际的数据包发送的例子入手,来看看其发送的具体流程,以及过程中涉及到的相关数据结构.在我们的虚拟机上发送icmp回显请求包,pin ...

  5. 向linux内核中添加外部中断驱动模块

    本文主要介绍外部中断驱动模块的编写,包括:1.linux模块的框架及混杂设备的注册.卸载.操作函数集.2.中断的申请及释放.3.等待队列的使用.4.工作队列的使用.5.定时器的使用.6.向linux内 ...

  6. linux 驱动学习笔记02--应用实例:在内核中新增驱动代码目录和子目录

    下面来看一个综合实例,假设我们要在内核源代码 drivers 目录下为 ARM 体系结构新增如下用于 test driver 的树型目录:| --test  | -- cpu  | -- cpu.c ...

  7. [php-src]窥探Php内核中的变量

    内容均以php-5.6.14为例. 在看各种组合数据类型之前,有必要先熟悉下 Zend/zend_types.h 里面的自定义数据类型. #ifndef ZEND_TYPES_H // 防止多次 in ...

  8. [php-src]理解Php内核中的函数与INI

    内容均以php-5.6.14为例. 一. 函数结构 内核中定义一个php函数使用 PHP_FUNCTION 宏 包装,扩展也不例外,该宏在 ./main/php.h:343 有着一系列类似以 PHP ...

  9. Openvswitch原理与代码分析(5): 内核中的流表flow table操作

      当一个数据包到达网卡的时候,首先要经过内核Openvswitch.ko,流表Flow Table在内核中有一份,通过key查找内核中的flow table,即可以得到action,然后执行acti ...

  10. 在内核中异步请求设备固件firmware的测试代码

    在内核中异步请求设备固件firmware的测试代码 static void ghost_load_firmware_callback(const struct firmware *fw, void * ...

随机推荐

  1. ionic pull to refresh 下拉更新頁面

    有些項目都用到了下拉更新頁面的效果: 1. 在index.html 中添加ion-refresher 指令 且在我們需要更新內容的外面 添加 如 <ion-refresher pulling-t ...

  2. Bootstrap布局

    浮动 1.pull-left:左浮动;pull-right:右浮动;清除浮动:clearfix

  3. dreamweaver cs6 的破解方法

    dreamweaver cs6 的破解方法,很简单大家照着下面的方法做肯定能破解方法/步骤 安装DreamWeaver cs6 使用amtlib.dll破解下载amtlib.dll文件后,解压后得到 ...

  4. JS时间

    function checkStartTime(){ var d1 = new Date(); var endTime = document.getElementById("secCreat ...

  5. pect-shell中的自动交互

    这是我在ST写的自动登陆ssh的脚本, 分两个文件 文件1: sssh #!/bin/bash #xql 2011/01/4#auto ssh 138.198.230.170 case $1 in & ...

  6. Solaris网络配置

    /etc/hostname.interface:物理端口,里面包含一个主机名或主机的IP/etc/nodename:计算机名/etc/defaultdomain:主机域名/etc/defaultrou ...

  7. Python爬虫之豆瓣-新书速递-图书解析

    1- 问题描述 抓取豆瓣“新书速递”[1]页面下图书信息(包括书名,作者,简介,url),将结果重定向到txt文本文件下. 2- 思路分析[2] Step1 读取HTML Step2 Xpath遍历元 ...

  8. 2. XAML

    1. 什么是 XAML XAML 可以说是 XML 的一个特殊子集,使用相同的语法,只是 XML 可以自定义任何的节点和属性,但 XAML 是有所限制的,只能在规定的命名空间下使用. 2. names ...

  9. Curses library not found. Please install appropriate package

    今天安装mysql-5.5.3-m3的时候,报下面的错误: -- Could NOT find OpenSSL (missing: OPENSSL_LIBRARIES OPENSSL_INCLUDE_ ...

  10. OpenFileDialog使用方法

    OpenFileDialog基本属性 AddExtension 控制是否将扩展名自动添加到文件名上 CheckFileExists 指示用户指定不存在的文件时是否显示警告 CheckPathExist ...