本文转载自:http://blog.csdn.net/npy_lp/article/details/7175517

内核源码:Linux-2.6.38.8.tar.bz2

参考文档:http://gcc.gnu.org/onlinedocs/gcc-4.6.2/gcc/Other-Builtins.html#Other-Builtins

linux内核中likely和unlikely函数有两种(只能两者选一)实现方式,它们的实现原理稍有不同,但作用是相同的,下面将结合linux-2.6.38.8版本的内核代码来进行讲解。

1、对__builtin_expect的封装

它们的源代码如下:

  1. /* linux-2.6.38.8/include/linux/compiler.h */
  2. # define likely(x)  __builtin_expect(!!(x), 1)
  3. # define unlikely(x)    __builtin_expect(!!(x), 0)

__builtin_expect 是GCC的内置函数,用来对选择语句的判断条件进行优化,常用于一个判断条件经常成立(如likely)或经常不成立(如unlikely)的情况。

__builtin_expect的函数原型为long  __builtin_expect (long exp, long c),返回值为完整表达式exp的值,它的作用是期望表达式exp的值等于c(注意,如果exp == c条件成立的机会占绝大多数,那么性能将会得到提升,否则性能反而会下降)。

在普通的应用程序中也可以使用__builtin_expect,如下面的例子:

  1. #include <stdio.h>
  2. int main(void)
  3. {
  4. int a;
  5. scanf("%d", &a);
  6. if(__builtin_expect(a, 4))
  7. printf("if: a = %d\n", a);
  8. else
  9. printf("else: a = %d\n", a);
  10. return 0;
  11. }

分别输入整数0到4来进行5次测试,它们的输出分别为:

  1. else: a = 0
  2. if: a = 1
  3. if: a = 2
  4. if: a = 3
  5. if: a = 4

注意,在上例中只有输入整数0的时候才执行else后的打印语句,也就是说__builtin_expect(a, 4)函数的值就是表达式a的值。

记住,它们只是用来提升性能的优化手段,并不会改变原来表达式的值。

2、使用__branch_check__函数

它们的源代码如下:

  1. /* linux-2.6.38.8/include/linux/compiler.h */
  2. # ifndef likely
  3. #  define likely(x) (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 1))
  4. # endif
  5. # ifndef unlikely
  6. #  define unlikely(x)   (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 0))
  7. # endif

(1)、先使用内置函数__builtin_constant_p忽略表达式x为常量的情况

__builtin_constant_p也是GCC的内置函数,函数原型为int  __builtin_constant_p(exp),用于判断表达式exp在编译时是否是一个常量,如果是则函数的值为整数1,否则为0,如下面的例子:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define VALUE 5
  4. int main(void)
  5. {
  6. char *ptr = NULL;
  7. int num, count;
  8. ptr = malloc(20);
  9. num = __builtin_constant_p(ptr) ? 20 : 20 + 10;
  10. printf("num = %d\n", num);
  11. free(ptr);
  12. count = __builtin_constant_p(VALUE) ? 20 + VALUE : 10;
  13. printf("count = %d\n", count);
  14. return 0;
  15. }

例子的输出结果:

  1. num = 30
  2. count = 25

例子中的ptr为指针变量,所以__builtin_constant_p(ptr)的值为0,num的值为30。

(2)、函数__branch_check__的实现

  1. /* linux-2.6.38.8/include/linux/compiler.h */
  2. #define __branch_check__(x, expect) ({                  \
  3. int ______r;                    \
  4. static struct ftrace_branch_data        \
  5. __attribute__((__aligned__(4)))     \
  6. __attribute__((section("_ftrace_annotated_branch"))) \
  7. ______f = {             \
  8. .func = __func__,           \
  9. .file = __FILE__,           \
  10. .line = __LINE__,           \
  11. };                      \
  12. ______r = likely_notrace(x);            \
  13. ftrace_likely_update(&______f, ______r, expect); \
  14. ______r;                    \
  15. })

使用它来检查判断条件并记录likely判断的预测信息,之后根据预测信息进行相应的优化以提升性能。

函数__branch_check__的返回值为______r的值,也就是参数x的值。

详解likely和unlikely函数【转】的更多相关文章

  1. SQL 中详解round(),floor(),ceiling()函数的用法和区别?

    SQL 中详解round(),floor(),ceiling()函数的用法和区别? 原创 2013年06月09日 14:00:21   摘自:http://blog.csdn.net/yueliang ...

  2. 第7.25节 Python案例详解:使用property函数定义与实例变量同名的属性会怎样?

    第7.25节 Python案例详解:使用property函数定义与实例变量同名的属性会怎样? 一.    案例说明 我们上节提到了,使用property函数定义的属性不要与类内已经定义的普通实例变量重 ...

  3. 第7.24节 Python案例详解:使用property函数定义属性简化属性访问代码实现

    第7.24节 Python案例详解:使用property函数定义属性简化属性访问代码实现 一.    案例说明 本节将通过一个案例介绍怎么使用property定义快捷的属性访问.案例中使用Rectan ...

  4. 详解wait和waitpid函数

    #include <sys/types.h> /* 提供类型pid_t的定义 */ #include <sys/wait.h> pid_t wait(int *status) ...

  5. Linux 信号详解一(signal函数)

    信号列表 SIGABRT 进程停止运行 SIGALRM 警告钟 SIGFPE 算述运算例外 SIGHUP 系统挂断 SIGILL 非法指令 SIGINT 终端中断 SIGKILL 停止进程(此信号不能 ...

  6. (译)详解javascript立即执行函数表达式(IIFE)

    写在前面 这是一篇译文,原文:Immediately-Invoked Function Expression (IIFE) 原文是一篇很经典的讲解IIFE的文章,很适合收藏.本文虽然是译文,但是直译的 ...

  7. 《Windows驱动开发技术详解》之派遣函数

    驱动程序的主要功能是负责处理I/O请求,其中大部分I/O请求是在派遣函数中处理的.用户模式下所有对驱动程序的I/O请求,全部由操作系统转化为一个叫做IRP的数据结构,不同的IRP数据会被“派遣”到不同 ...

  8. [二] java8 函数式接口详解 函数接口详解 lambda表达式 匿名函数 方法引用使用含义 函数式接口实例 如何定义函数式接口

    函数式接口详细定义 package java.lang; import java.lang.annotation.*; /** * An informative annotation type use ...

  9. 详解MySQL中concat函数的用法(连接字符串)

    MySQL中concat函数 使用方法: CONCAT(str1,str2,…) 返回结果为连接参数产生的字符串.如有任何一个参数为NULL ,则返回值为 NULL. 注意: 如果所有参数均为非二进制 ...

  10. 详解javascript立即执行函数表达式(IIFE)

    立即执行函数,就是在定义函数的时候直接执行,这里不是申明函数而是一个函数表达式 1.问题 在javascript中,每一个函数在被调用的时候都会创建一个执行上下文,在函数内部定义的变量和函数只能在该函 ...

随机推荐

  1. K大数查询(bzoj 3110)

    Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置 ...

  2. POJ Blue Jeans [枚举+KMP]

    传送门 F - Blue Jeans Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u ...

  3. LOJ#3083.「GXOI / GZOI2019」与或和_单调栈_拆位

    #3083. 「GXOI / GZOI2019」与或和 题目大意 给定一个\(N\times N\)的矩阵,求所有子矩阵的\(AND(\&)\)之和.\(OR(|)\)之和. 数据范围 \(1 ...

  4. mysql PROCEDURE ANALYSE() 用法

    PROCEDURE ANALYSE() 会让 MySQL 帮你去分析你的字段和其实际的数据,并会给你一些有用的建议.只有表中有实际的数据,这些建议才会变得有用,因为要做一些大的决定是需要有数据作为基础 ...

  5. lua 暂停写法

    由于lua 不支持暂停 用其他方法变相实现 -- 暂停 hock 写法 function _M.sleep(n) if n > 0 then os.execute("ping -c & ...

  6. 线段树区间更新,区间统计+离散化 POJ 2528 Mayor&#39;s posters

    题意:有一个非常长的板子(10000000长),在上面贴n(n<=10000)张海报.问最后从外面能看到几张不同的海报. 由于板子有10000000长,直接建树肯定会爆,所以须要离散化处理,对于 ...

  7. eclipse 配置执行hadoop 2.7 程序样例參考步骤

    前提:你搭建好了hadoop 2.x的linux环境,并可以成功执行.还有就是window可以訪问到集群.over 1. hfds-site.xml 添加属性:关闭集群的权限校验.windows的用户 ...

  8. C#中使用byte[]数据,生成Bitmap

    /// <summary> /// 使用byte[]数据,生成256色灰度 BMP 位图 /// </summary> /// <param name="ori ...

  9. uva 11468 - Substring(AC自己主动机+概率)

    题目链接:uva 11468 - Substring 题目大意:给出一些字符和各自字符相应的选择概率.随机选择L次后得到一个长度为L的字符串,要求该字符串不包括随意一个子串的概率. 解题思路:构造AC ...

  10. 【万里征程——Windows App开发】控件大集合1

    加入控件的方式有多种.大家更喜欢哪一种呢? 1)使用诸如 Blend for Visual Studio 或 Microsoft Visual Studio XAML 设计器的设计工具. 2)在 Vi ...