linux宏定义likely和unlikely解析
来源:互联网 发布:spark要用java吗? 编辑:程序博客网 时间:2024/05/19 10:37
在看linux内核代码的时候,经常会看到likely(x)和unlikely(x)宏的使用。那这两个宏有什么作用呢?
这两个宏在内核中的定义如下:
# define likely(x) __builtin_expect(!!(x), 1)
# define unlikely(x) __builtin_expect(!!(x), 0)
可见这里使用了gcc的内建函数__builtin_expect()。
__builtin_expect (long exp, long c)函数:
该函数用来引导gcc进行条件分支预测。在一条指令执行时,由于流水线的作用,CPU可以同时完成下一条指令的取指,这样可以提高CPU的利用率。在执行条件分支指令时,CPU也会预取下一条执行,但是如果条件分支的结果为跳转到了其他指令,那CPU预取的下一条指令就没用了,这样就降低了流水线的效率。
另外,跳转指令相对于顺序执行的指令会多消耗CPU时间,如果可以尽可能不执行跳转,也可以提高CPU性能。
使用__builtin_expect (long exp, long c)函数可以帮助gcc优化程序编译后的指令序列,使汇编指令尽可能的顺序执行,从而提高CPU预取指令的正确率和执行效率。
例如,__builtin_expect(exp, 1) 表示程序执行过程中,exp取到1的可能性比较大。该函数的返回值为exp自身。
likely(x)等价于x,即if(likely(x))等价于if(x),但是它告诉gcc,x取1的可能性比较大。
unlikely(x)等价于x,即if(unlikely(x))等价于if(x),但是它告诉gcc,x取0的可能性比较大。
程序示例:
我们可以写一个简单的应用程序,看看__builtin_expect()函数的作用:
写一个函数testfunc():
这个函数中指明了if条件成立的可能性比较大,gcc可以据此优化程序指令序列。
在main()函数中调用该函数,编译程序(使用-O3选项),查看反汇编后的汇编代码:
这个函数中指明了else条件成立的可能性比较大,gcc可以据此优化程序指令序列。
在main()函数中调用该函数,编译程序(使用-O3选项),查看反汇编后的汇编代码:
从汇编代码中可以看出,如果else成立,即x==0,则第一条跳转指令不成功,指令得以顺序执行。而如果if成立,则需要多执行一次跳转。
这两个宏在内核中的定义如下:
# define likely(x) __builtin_expect(!!(x), 1)
# define unlikely(x) __builtin_expect(!!(x), 0)
可见这里使用了gcc的内建函数__builtin_expect()。
__builtin_expect (long exp, long c)函数:
该函数用来引导gcc进行条件分支预测。在一条指令执行时,由于流水线的作用,CPU可以同时完成下一条指令的取指,这样可以提高CPU的利用率。在执行条件分支指令时,CPU也会预取下一条执行,但是如果条件分支的结果为跳转到了其他指令,那CPU预取的下一条指令就没用了,这样就降低了流水线的效率。
另外,跳转指令相对于顺序执行的指令会多消耗CPU时间,如果可以尽可能不执行跳转,也可以提高CPU性能。
使用__builtin_expect (long exp, long c)函数可以帮助gcc优化程序编译后的指令序列,使汇编指令尽可能的顺序执行,从而提高CPU预取指令的正确率和执行效率。
例如,__builtin_expect(exp, 1) 表示程序执行过程中,exp取到1的可能性比较大。该函数的返回值为exp自身。
内核中likely(x)和unlikely(x)宏:
知道__builtin_expect()函数的作用之后,我们就知道内核中likely(x)和unlikely(x)宏的作用了,通过likely(x)和unlikely(x)宏定义,我们可以得出他们的作用:likely(x)等价于x,即if(likely(x))等价于if(x),但是它告诉gcc,x取1的可能性比较大。
unlikely(x)等价于x,即if(unlikely(x))等价于if(x),但是它告诉gcc,x取0的可能性比较大。
程序示例:
我们可以写一个简单的应用程序,看看__builtin_expect()函数的作用:
写一个函数testfunc():
- int testfunc(int x)
- {
- if (__builtin_expect(!!(x), 1)) ///
- {
- x = 123;
- }
- else
- {
- x = 456;
- }
- return x;
- }
在main()函数中调用该函数,编译程序(使用-O3选项),查看反汇编后的汇编代码:
- 00400780 <testfunc>:
- 400780: 10800003 beqz a0,400790 <testfunc+0x10>
- 400784: 2402007b li v0,123
- 400788: 03e00008 jr ra
- 40078c: 00000000 nop
- 400790: 03e00008 jr ra
- 400794: 240201c8 li v0,456
从汇编代码中可以看出,如果if成立,即x==1,则第一条跳转指令不成功,指令得以顺序执行。而如果else成立,则需要多执行一次跳转。
如果testfunc()如下实现:- int testfunc(int x)
- {
- if (__builtin_expect(!!(x), 0)) ///
- {
- x = 123;
- }
- else
- {
- x = 456;
- }
- return x;
- }
在main()函数中调用该函数,编译程序(使用-O3选项),查看反汇编后的汇编代码:
- 00400780 <testfunc>:
- 400780: 14800002 bnez a0,40078c <testfunc+0xc>
- 400784: 2402007b li v0,123
- 400788: 240201c8 li v0,456
- 40078c: 03e00008 jr ra
- 400790: 00000000 nop
其他说明:
likely(x)宏传入__builtin_expect(!!(x), 0)的第一个参数为!!x,这样写是因为__builtin_expect的第一个参数需要为long型,而我们如果想传入指针或字符串类型,则需要使用!!x将x变成long型,例如,如果一个指针ptr==NULL,则!ptr=1,而!!ptr=0。
注意有些gcc版本没有实现__builtin_expect内建函数,所以这个函数不会起实际作用,相应的,likely(x)和unlikely(x)也就没有效果了。
阅读全文
0 0
- linux宏定义likely和unlikely解析
- Linux 内核中 likely 与 unlikely 的宏定义解析
- 关于Linux Kernel中的宏定义likely和unlikely
- 关于Linux Kernel中的宏定义likely和unlikely
- 关于Linux Kernel中的宏定义likely和unlikely
- 关于Linux Kernel中的宏定义likely和unlikely
- 内核中的likely和unlikely宏定义
- 内核中的likely和unlikely宏定义
- 内核中的likely和unlikely宏定义
- 内核中的likely和unlikely宏定义
- linux likely & unlikely 宏
- linux内核中的likely()和unlikely()宏
- linux中likely()和unlikely()宏
- likely和unlikely宏
- likely和unlikely宏
- likely和unlikely宏
- 宏likely和unlikely
- likely和unlikely宏
- knockout click点击事件及事件源解释
- 数学笔记18——定积分的应用3(均值、权重、概率)
- JavaScript prototype 属性
- python多进程笔记4
- QT之qss教程-QProgressBar
- linux宏定义likely和unlikely解析
- Android基础之EditText在ListView中的使用
- S5PV210开发 -- GPIO
- 2017/11/9 c语言学习之路
- 手机格式,省份证格式,过滤图标,过滤qq图像
- 新 CentOS 6.5 6.9 环境下搭建直播模拟测试环境 ffmpeg+nginx=rtmp (傻瓜式环境搭建)
- Javacore分析
- PHP面向对象的程序设计2
- 【Android进阶】Android Binder之ServiceManager注册服务解析1