在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)
<span style="font-family:SimHei;font-size:18px;">/* linux-2.6.38.8/include/linux/compiler.h */
# define likely(x) __builtin_expect(!!(x), 1)
# define unlikely(x) __builtin_expect(!!(x), 0)</span>

__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. }
<span style="font-family:SimHei;font-size:18px;">#include <stdio.h>

int main(void)
{
int a; scanf("%d", &a); if(__builtin_expect(a, 4))
printf("if: a = %d\n", a);
else
printf("else: a = %d\n", a); return 0;
}
</span>

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

  1. else: a = 0
  2. if: a = 1
  3. if: a = 2
  4. if: a = 3
  5. if: a = 4
<span style="font-family:SimHei;font-size:18px;">else: a = 0

if: a = 1

if: a = 2

if: a = 3

if: a = 4
</span>

注意,在上例中只有输入整数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
<span style="font-family:SimHei;font-size:18px;">/* 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</span>

(1)、先使用内置函数__builtin_constant_p忽略表达式x为常量的情况 (这而的!!(x)为什么不写成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. }
<span style="font-family:SimHei;font-size:18px;">#include <stdio.h>
#include <stdlib.h> #define VALUE 5 int 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;
}
</span>

例子的输出结果:

  1. num = 30
  2. count = 25
<span style="font-family:SimHei;font-size:18px;">num = 30
count = 25
</span>

例子中的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. })
<span style="font-family:SimHei;font-size:18px;">/* 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; \
})</span>

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

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

最新文章

  1. 企业SOA架构设计理论
  2. Codeforces Round #323 (Div. 1) A. GCD Table
  3. C#集合u
  4. hdu 4283 You Are the One 区间dp
  5. Bootstrap 基础学习笔记(一)
  6. php中关于js保存文件至本地的问题
  7. Centos6.4安装Mono和MonoDevelop
  8. 热门usb无线网卡
  9. 【SDK编程】
  10. 201521123101 《Java程序设计》第11周学习总结
  11. 使用json文件给es中导入数据
  12. a标签href无值 onclick事件跳转
  13. jenkins在windows下的最快安装方法
  14. vue 中的通过搜索框进行数据过滤的过程
  15. nginx接入let&#39;s encrypt
  16. 从字符集发展史看Unicode和UTF-8的区别
  17. Connection is read-only. Queries leading to data modification are not allowed
  18. 修改.net core MVC默认端口
  19. Mac上安装Git
  20. 理解 Linux 的处理器负载均值

热门文章

  1. Mysql字符集与校对规则
  2. 集合 Properties 的 简单例子(Spring)
  3. 生日聚会 BZOJ 1037
  4. R语言入门视频笔记--4--R的数据输入
  5. [转发]Android 系统稳定性 - ANR(一)
  6. LeetCode OJ--Valid Palindrome
  7. BZOJ 1090 字符串折叠(Hash + DP)
  8. 下载安装webstrom及激活
  9. chmod u g x o 777
  10. JS实现根据密码长度 显示安全条