likely和unlikely宏
来源:互联网 发布:spring源码深度解析pdf 编辑:程序博客网 时间:2024/09/21 09:22
if(likely(value)) 等价于 if(value)
if(unlikely(value)) 也等价于 if(value)
也就是说 ,当value值为真时执行if分支,为假时执行else分支,从阅读和理解代码的角度来看,是一样的!!!
以下为这两个宏的一般定义:
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
而__builtin_expect() 是 GCC (version >= 2.96)提供给程序员使用的,目的是将“分支转移”的信息提供给编译器,这样编译器可以对代码进行优化,以减少指令跳转带来的性能下降。__builtin_expect()在GCC的官方文档中解释如下(可跳过):
-- Built-in Function:long __builtin_expect (long EXP, long C)
You may use `__builtin_expect' to provide the compiler with branch
prediction information. In general, you should prefer to use
actual profile feedback for this (`-fprofile-arcs'), as
programmers are notoriously bad at predicting how their programs
actually perform. However, there are applications in which this
data is hard to collect.
The return value is the value of EXP, which should be an integral
expression. The value of C must be a compile-time constant. The
semantics of the built-in are that it is expected that EXP == C.
For example:
if (__builtin_expect (x, 0))
foo ();
would indicate that we do not expect to call `foo', since we
expect `x' to be zero. Since you are limited to integral
expressions for EXP, you should use constructions such as
if (__builtin_expect (ptr != NULL, 1))
error ();
when testing pointer or floating-point values.
也就是说,GCC的内建方法会判断 EXP == C 是否成立,成立则将if分支中的执行语句紧跟放在汇编跳转指令之后,否则将else分支中的执行语句紧跟汇编跳转指令之后。如下例子所示:
点击(此处)折叠或打开
- //test.c
- #define likely(x) __builtin_expect(!!(x),1)
- #define unlikely(x) __builtin_expect(!!(x),0)
-
- int test_unlikely(int x)
- {
- if(unlikely(x== 2))
- {
- x++;
- }
- else
- {
- x--;
- }
-
- return x;
- }
-
- int test_likely(int x)
- {
- if(likely(x== 2))
- {
- x++;
- }
- else
- {
- x--;
- }
-
- return x;
- }
编译并导出目标文件的汇编表示:
gcc -fprofile-arcs -O2 -c test.c
objdump -d test.o
得到如下汇编:
test.o: file format elf32-i386
Disassembly of section .text:
00000000 <test_likely>:
0: 55 push %ebp
1: 83 05 00 00 00 00 01 addl $0x1,0x0
8: 89 e5 mov %esp,%ebp
a: 83 15 04 00 00 00 00 adcl $0x0,0x4
11: 83 7d 08 02 cmpl $0x2,0x8(%ebp) //留意这里!!!判断 x == 2
15: 75 15 jne 2c <test_likely+0x2c> //跳转指令jne!!!x != 2 时才跳转!
17: 83 05 08 00 00 00 01 addl $0x1,0x8 //if分支代码 x++
1e: b8 03 00 00 00 mov $0x3,%eax
23: 83 15 0c 00 00 00 00 adcl $0x0,0xc
2a: 5d pop %ebp
2b: c3 ret
2c: 8b 45 08 mov 0x8(%ebp),%eax //跳转到这里,else分支代码 x--
2f: 5d pop %ebp
30: 83 e8 01 sub $0x1,%eax
33: 83 05 10 00 00 00 01 addl $0x1,0x10
3a: 83 15 14 00 00 00 00 adcl $0x0,0x14
41: c3 ret
42: 8d b4 26 00 00 00 00 lea 0x0(%esi),%esi
49: 8d bc 27 00 00 00 00 lea 0x0(%edi),%edi
00000050 <test_unlikely>:
50: 55 push %ebp
51: 89 e5 mov %esp,%ebp
53: 8b 45 08 mov 0x8(%ebp),%eax
56: 83 05 18 00 00 00 01 addl $0x1,0x18
5d: 83 15 1c 00 00 00 00 adcl $0x0,0x1c
64: 83 f8 02 cmp $0x2,%eax //留意这里!!!判断 x == 2
67: 74 13 je 7c <test_unlikely+0x2c> //跳转指令je!!!x == 2 时就跳转!
69: 83 e8 01 sub $0x1,%eax //else分支代码 x--
6c: 83 05 28 00 00 00 01 addl $0x1,0x28
73: 83 15 2c 00 00 00 00 adcl $0x0,0x2c
7a: 5d pop %ebp
7b: c3 ret
7c: 83 05 20 00 00 00 01 addl $0x1,0x20 //跳转到这里,if分支代码 x++
83: b0 03 mov $0x3,%al
85: 83 15 24 00 00 00 00 adcl $0x0,0x24
8c: 5d pop %ebp
8d: c3 ret
8e: 66 90 xchg %ax,%ax
00000090 <_GLOBAL__I_0_test_unlikely>:
90: 55 push %ebp
91: 89 e5 mov %esp,%ebp
93: 83 ec 08 sub $0x8,%esp
96: c7 04 24 00 00 00 00 movl $0x0,(%esp)
9d: e8 fc ff ff ff call 9e <_GLOBAL__I_0_test_unlikely+0xe>
a2: c9 leave
a3: c3 ret
注意:likely和unlikely所生成的跳转指令是不同的,分别是jne和je!!!
如上述例子分析所示,宏likely和宏unlikely唯一的作用就是选择“将if分支还是else分支放在跳转指令之后,从而优化程序的执行效率”。因为likely(EXP)代表条件表达式EXP很可能成立,而unlikely(EXP)代表条件表达式EXP很可能不成立,当程序员清楚EXP表达式多数情况成立(不成立)时,就可使用likely(unlikely),使if分支(else分支)紧跟跳转指令其后,从而在大多数情况下不用执行跳转指令,避开跳转指令所带来的开销,从而达到优化的目的。
- likely和unlikely宏
- likely和unlikely宏
- likely和unlikely宏
- 宏likely和unlikely
- likely和unlikely宏
- 内核中的likely和unlikely宏定义
- 内核中的likely和unlikely宏定义
- 内核中的likely和unlikely宏定义
- linux内核中的likely()和unlikely()宏
- 内核中的likely和unlikely宏定义
- linux中likely()和unlikely()宏
- linux宏定义likely和unlikely解析
- 有关likely和unlikely
- 有关likely和unlikely
- 有关likely和unlikely
- 有关likely和unlikely
- likely和unlikely
- likely和unlikely
- oracle database 11g 版本2的安装
- android setTag()/getTag()应用
- 写的一个算两个任意数乘积的代码
- 严苛模式(StrictMode)
- Lucene3.6 之 查询篇
- likely和unlikely宏
- 10个经典的面向对象设计原则
- JavaBean的生命周期
- 用友NC 成本分析项目设置模板参照
- Java 文件下载原理 + Struts2文件下载原理 详解:~~Myself
- 谷歌自带应用
- C语言输入输出函数之 fputs(...)
- [Java] 关于Java,你值得看的一些东西
- 获得高效管理 项目经理必知的五个常用工具