内核中的 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. 查询数据库后台Block 的Sql存储过程

    查询数据库后台Block 的Sql存储过程 SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER OFF GO /*记录SQL Server的阻塞情况 wang 200 ...

  2. C# 打印异常

    1. [代码]函数:将异常打印到LOG文件     跳至 [1] [2] [4] [全屏预览] ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ...

  3. 解读CSS布局之-水平垂直居

    对一个元素水平垂直居中,在我们的工作中是会经常遇到的,也是CSS布局中很重要的一部分,本文就来讲讲CSS水平垂直居中的一些方法.由于我们大搜车的日常工作中已经不再需要理会低版本IE,所以本文所贴出的方 ...

  4. Linux manual中命令标号的含义

    如果查看Linux manual(例如,执行:man open), 会发现文档中有这样的表达方式:read(2), write(2), lseek(2), fcntl(2)等,括号中的数值表达什么含义 ...

  5. memcache和memcahced的区别

    Memcache是什么?Memcache是一个自由和开放源代码.高性能.分配的内存对象缓存系统.用于加速动态web应用程序,减轻数据库负载.它可以应对任意多个连接,使用非阻塞的网络IO.由于它的工作机 ...

  6. ADO.NET(很精彩全面)

    记录一下地址方便以后看http://www.cnblogs.com/liuhaorain/archive/2012/02/06/2340409.html

  7. Knockout.Js官网学习(html绑定、css绑定)

    Html绑定 html绑定到DOM元素上,使得该元素显示的HTML值为你绑定的参数.如果在你的view model里声明HTML标记并且render的话,那非常有用. 简单示例 <div dat ...

  8. silverlight 退出当前页面、跳转到主页面

    1.退出当前页面 private void imgExit_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { if (Message ...

  9. 百度分享如何自定义分享url和内容?

    百度分享默认分享的是当前页的url,但也可以在同一个页面中分享多个不同的url,仅需进行如下简单的配置. 默认的代码如下: <div id="bdshare" class=& ...

  10. 正确使用stl map的erase方法

    先声明:下面的文章是针对windows的用法,因为std::map的erase函数的windows的实现版本是返回一个std::map的迭代器,但是STL标准里面的该函数的返回值确是: map.era ...