内核源码: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的封装

它们的源代码如下:

/* linux-2.6.38.8/include/linux/compiler.h */
# define likely(x)  __builtin_expect(!!(x), 1)
# 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,如下面的例子:

#include <stdio.h>int main(void)
{int a;scanf("%d", &a);if(__builtin_expect(a, 4))printf("if: a = %d\n", a);elseprintf("else: a = %d\n", a);return 0;
}

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

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

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

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

2、使用__branch_check__函数

它们的源代码如下:

/* linux-2.6.38.8/include/linux/compiler.h */
# 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

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

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

#include <stdio.h>
#include <stdlib.h>#define VALUE 5int main(void)
{char *ptr = NULL;int num, count;ptr = malloc(20);num = __builtin_constant_p(ptr) ? 20 : 20 + 10;printf("num = %d\n", num);free(ptr);count = __builtin_constant_p(VALUE) ? 20 + VALUE : 10;printf("count = %d\n", count);return 0;
}

例子的输出结果:

num = 30
count = 25

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

(2)、函数__branch_check__的实现

/* linux-2.6.38.8/include/linux/compiler.h */
#define __branch_check__(x, expect) ({                  \int ______r;                   \static struct ftrace_branch_data       \__attribute__((__aligned__(4)))        \__attribute__((section("_ftrace_annotated_branch"))) \______f = {               \.func = __func__,         \.file = __FILE__,         \.line = __LINE__,         \};                     \______r = likely_notrace(x);          \ftrace_likely_update(&______f, ______r, expect); \______r;                 \})

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

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

详解likely和unlikely函数相关推荐

  1. python open 打开是什么类型的文件-详解Python中open()函数指定文件打开方式的用法...

    文件打开方式 当我们用open()函数去打开文件的时候,有好几种打开的模式. 'r'->只读 'w'->只写,文件已存在则清空,不存在则创建. 'a'->追加,写到文件末尾 'b'- ...

  2. php打印出函数的内容吗,PHP打印函数集合详解以及PHP打印函数对比详解(精)

    1 echo();2 print();3 die();4 printf();5 sprintf();6 print_r();7 var_dump(); 1 echo() 可以同时输出多个字符串,可以多 ...

  3. python中groupby()函数讲解与示例_详解python中groupby函数通俗易懂

    一.groupby 能做什么? python中groupby函数主要的作用是进行数据的分组以及分组后地组内运算! 对于数据的分组和分组运算主要是指groupby函数的应用,具体函数的规则如下: df[ ...

  4. python函数的使用场景_详解python中strip函数的使用场景

    python strip()函数 介绍,需要的朋友可以参考一下 函数原型 声明:s为字符串,rm为要删除的字符序列 s.strip(rm) 删除s字符串中开头.结尾处,位于 rm删除序列的字符 s.l ...

  5. python中get函数是什么意思_详解python中get函数的用法(附代码)_后端开发

    strncmp函数用法详解_后端开发 strncmp函数为字符串比较函数,其函数语法为"int strncmp ( const char * str1, const char * str2, ...

  6. 详解c语言main函数、printf函数、scanf函数与va家族

    C语言入门与提升(1)--详解c语言main函数.printf函数与scanf函数,与va家族 前言: 为什么要学习C语言呢?C语言作为最古老的语言之一,走过了半个多世纪的风风雨雨,至今仍然长盛不衰, ...

  7. php simplexml_load_file 详解,php中simplexml_load_file函数用法实例讲解

    php中simplexml_load_file函数用法实例讲解 发布于 2015-02-07 06:53:40 | 136 次阅读 | 评论: 0 | 来源: 网友投递 PHP开源脚本语言PHP(外文 ...

  8. C语言return的用法详解,C语言函数返回值详解。 (本次转载仅供学习,感谢原创!!转发自C语言中文网,如有侵权请私信本人删除)

    C语言return的用法详解,C语言函数返回值详解 转载:http://c.biancheng.net/view/1855.html 函数的返回值是指函数被调用之后,执行函数体中的代码所得到的结果,这 ...

  9. oracle 总转横函数,详解Oracle行列转换函数-pivot函数和unpivot函数-多智时代

    今天主要介绍一下Oracle行转列及列转行常见函数,下面一起来看看吧! 行列转换 pivot函数:行转列函数 语法:pivot(任一聚合函数 for 需专列的值所在列名 in (需转为列名的值)): ...

  10. c语言getline函数什么意思,详解C++ cin.getline函数

    cin 虽然可以使用 cin 和 >> 运算符来输入字符串,但它可能会导致一些需要注意的问题. 当 cin 读取数据时,它会传递并忽略任何前导白色空格字符(空格.制表符或换行符).一旦它接 ...

最新文章

  1. 为什么华为在发布会不提鸿蒙,华为又要开发布会?这次没有手机,鸿蒙系统要当主角!...
  2. forward 和redirect的区别
  3. Java 14:查看更新的switch语句
  4. 36 SD配置-销售凭证设置-定义项目类别
  5. 数据库周刊第十七期来啦!
  6. python显示邮件发送成功失败_python stmp module 163邮箱发送邮件不成功
  7. (转)Java DecimalFormat 用法(数字格式化)
  8. c语言头文件 数学函数,头文件cmath中常用函数
  9. webservice 调用错误
  10. IBM的人工智能“沃森”首次确诊罕见白血病,只用了10分钟!
  11. git untracked working tree files would be overwritten by merge
  12. echarts 迁徙图
  13. 病毒分析 - 特征码提取
  14. 关于微信的几点更新与操作
  15. ONF推新版Atrium 获得OpenDaylight支持
  16. 程序员去哪接私活?分享10个兼职平台,人已赚麻
  17. 动态规划:奶牛吃草问题
  18. 办公技巧——PPT添加页码
  19. 安卓系统双屏异显_双屏异显在Android系统上的实现
  20. Vue 使用 yarn 报错

热门文章

  1. 好久没有写文章了,真相把自己解决问题的方法都写下来,可是没时间。
  2. 银行家算法JAVA版本
  3. lnmp一键安装包 安装php-fpm,LNMP一键安装包常用命令及配置文件路径
  4. 即食燕窝有营养价值吗?值得购买吗?
  5. 全球移动互联网大会北京站第二日感受分享
  6. 【前端浏览器】浏览器缓存(http缓存) 浏览器本地存储(总结)
  7. iOS C++/OC 混编
  8. 《2019秋招腾讯、招银面试问题》
  9. AUTOSAR汽车电子系统架构标准
  10. 诺基亚X1-01开机要求输入保密码