运维经–目录
__builtin_expect 分支预测
1.CPU流水线设计
CPU流水线设计,大大减少了取指令等待时间,但分支判断导致CPU执行跳转指令,降低了流水线的效率。
gcc引入了__builtin_expect
,作用是允许程序员将最有可能执行的分支告诉编译器。
2.定义
/*
* Using __builtin_constant_p(x) to ignore cases where the return
* value is always the same. This idea is taken from a similar patch
* written by Daniel Walker.
*/
# ifndef likely
# define likely(x) (__branch_check__(x, 1, __builtin_constant_p(x)))
# endif
# ifndef unlikely
# define unlikely(x) (__branch_check__(x, 0, __builtin_constant_p(x)))
# endif
if(likely(value)) //等价于 if(value)
if(unlikely(value)) //也等价于 if(value)
3.例子
#define LIKELY(x) __builtin_expect(!!(x), 1)
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
int test_likely(int x)
{
if(LIKELY(x))
{
x = 5;
}
else
{
x = 6;
}
return x;
}
int test_unlikely(int x)
{
if(UNLIKELY(x))
{
x = 5;
}
else
{
x = 6;
}
return x;
}
$ gcc -fprofile-arcs -O2 -c like.c -o like.o
$ objdump -d like.o
0000000000000000 <test_likely>:
0: 48 83 05 00 00 00 00 addq $0x1,0x0(%rip) # 8 <test_likely+0x8>
7: 01
8: 85 ff test %edi,%edi
a: b8 05 00 00 00 mov $0x5,%eax
f: 74 07 je 18 <test_likely+0x18> // 此处的效果是eax不为零时,不需要跳转。即x为真是不跳转。
11: f3 c3 repz retq
13: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
18: 48 83 05 00 00 00 00 addq $0x1,0x0(%rip) # 20 <test_likely+0x20>
1f: 01
20: b8 06 00 00 00 mov $0x6,%eax
25: c3 retq
26: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
2d: 00 00 00
0000000000000030 <test_unlikely>:
30: 48 83 05 00 00 00 00 addq $0x1,0x0(%rip) # 38 <test_unlikely+0x8>
37: 01
38: 85 ff test %edi,%edi
3a: 75 14 jne 50 <test_unlikely+0x20> // 此处的效果是edx为零时,不需跳转。即x为假时不跳转。
3c: 48 83 05 00 00 00 00 addq $0x1,0x0(%rip) # 44 <test_unlikely+0x14>
43: 01
44: b8 06 00 00 00 mov $0x6,%eax
49: c3 retq
4a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
50: b8 05 00 00 00 mov $0x5,%eax
55: c3 retq
Disassembly of section .text.startup: