在 2.6 内核中,随处可以见到 likely() 和 unlikely() 的身影,那么为什么要用它们?它们之间有什么区别?
首先要明确:
if(likely(value)) 等价于 if(value)
if(unlikely(value)) 也等价于 if(value)
也就是说 likely() 和 unlikely() 从阅读和理解代码的角度来看,是一样的!!!
这两个宏在内核中定义如下:
__builtin_expect() 是 GCC (version >= 2.96)提供给程序员使用的,目的是将“分支转移”的信息提供给编译器,这样编译器可以对代码进行优化,以减少指令跳转带来的性能下降。
__builtin_expect((x),1) 表示 x 的值为真的可能性更大;
__builtin_expect((x),0) 表示 x 的值为假的可能性更大。
也就是说,使用 likely() ,执行 if 后面的语句 的机会更大,使用unlikely(),执行else 后面的语句的机会更大。
例如下面这段代码,作者就认为 prev 不等于 next 的可能性更大,
通过这种方式,编译器在编译过程中,会将可能性更大的代码紧跟着起面的代码,从而减少指令跳转带来的性能上的下降。
下面以两个例子来加深这种理解:
第一个例子: example1.c
在这个例子中,我们认为 x 为0的可能性更大
编译以后,通过 objdump 来观察汇编指令,在我的 2.4 内核机器上,结果如下:
# gcc -O2 -c example1.c
# objdump -d example1.o
可以看到,编译器使用的是 jne (不相等跳转)指令,并且 else block 中的代码紧跟在后面。
8: 75 07 jne 11 <testfun+0x11>
a: b8 06 00 00 00 mov $0x6,%eax
第二个例子: example2.c
在这个例子中,我们认为 x 不为 0 的可能性更大
编译以后,通过 objdump 来观察汇编指令,在我的 2.4 内核机器上,结果如下:
# gcc -O2 -c example2.c
# objdump -d example2.o
这次编译器使用的是 je (相等跳转)指令,并且 if block 中的代码紧跟在后面。
8: 74 07 je 11 <testfun+0x11>
a: b8 19 00 00 00 mov $0x19,%eax
在GTK+2.0源码中有很多这样的宏:G_LIKELY和G_UNLIKELY。比如下面这段代码:
if (G_LIKELY (acat == 1)) /* allocate through magazine layer */
{
ThreadMemory *tmem = thread_memory_from_self();
guint ix = SLAB_INDEX (allocator, chunk_size);
if (G_UNLIKELY (thread_memory_magazine1_is_empty (tmem, ix)))
{
thread_memory_swap_magazines (tmem, ix);
if (G_UNLIKELY (thread_memory_magazine1_is_empty (tmem, ix)))
thread_memory_magazine1_reload (tmem, ix);
}
mem = thread_memory_magazine1_alloc (tmem, ix);
}
在源码中,宏G_LIKELY和G_UNLIKELY 是这么定义的:
#define G_LIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 1))
#define G_UNLIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 0))
宏_G_BOOLEAN_EXPR的作用是把expr转换为0和1,即真假两种。要理解宏G_LIKELY和G_UNLIKELY ,很明显必须理解__builtin_expect。__builtin_expect是GCC(version>=2.9)引进的宏,其作用就是帮助编译器判断条件跳转的预期值,避免跳转造成时间乱费。拿上面的代码来说:
if (G_LIKELY (acat == 1)) //表示大多数情况下if里面是真,程序大多数直接执行if里面的程序
而
if (G_UNLIKELY (thread_memory_magazine1_is_empty (tmem, ix)))//表示大多数情况if里面为假,程序大多数直接执行else里面的程序
可能大家看到还是一头雾水,看下面一段就会明白其中的乐趣啦;
//test_builtin_expect.c
#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;
}
[lammy@localhost test_builtin_expect]$ gcc -fprofile-arcs -O2 -c test_builtin_expect.c
[lammy@localhost test_builtin_expect]$ objdump -d test_builtin_expect.o
test_builtin_expect.o: file format elf32-i386
Disassembly of section .text:
00000000 <test_likely>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 8b 45 08 mov 0x8(%ebp),%eax
6: 83 05 38 00 00 00 01 addl $0x1,0x38
d: 83 15 3c 00 00 00 00 adcl $0x0,0x3c
14: 85 c0 test %eax,%eax
16: 74 15 je 2d <test_likely+0x2d>//主要看这里
18: 83 05 40 00 00 00 01 addl $0x1,0x40
1f: b8 05 00 00 00 mov $0x5,%eax
24: 83 15 44 00 00 00 00 adcl $0x0,0x44
2b: 5d pop %ebp
2c: c3 ret
2d: 83 05 48 00 00 00 01 addl $0x1,0x48
34: b8 06 00 00 00 mov $0x6,%eax
39: 83 15 4c 00 00 00 00 adcl $0x0,0x4c
40: 5d pop %ebp
41: c3 ret
42: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
49: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi
00000050 <test_unlikely>:
50: 55 push %ebp
51: 89 e5 mov %esp,%ebp
53: 8b 55 08 mov 0x8(%ebp),%edx
56: 83 05 20 00 00 00 01 addl $0x1,0x20
5d: 83 15 24 00 00 00 00 adcl $0x0,0x24
64: 85 d2 test %edx,%edx
66: 75 15 jne 7d <test_unlikely+0x2d>//主要看这里
68: 83 05 30 00 00 00 01 addl $0x1,0x30
6f: b8 06 00 00 00 mov $0x6,%eax
74: 83 15 34 00 00 00 00 adcl $0x0,0x34
7b: 5d pop %ebp
7c: c3 ret
7d: 83 05 28 00 00 00 01 addl $0x1,0x28
84: b8 05 00 00 00 mov $0x5,%eax
89: 83 15 2c 00 00 00 00 adcl $0x0,0x2c
90: 5d pop %ebp
91: c3 ret
92: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
99: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi
000000a0 <_GLOBAL__I_65535_0_test_likely>:
a0: 55 push %ebp
a1: 89 e5 mov %esp,%ebp
a3: 83 ec 08 sub
2024年2月21日 22:44
Awesome article, it was exceptionally helpful! I simply began in this and I'm becoming more acquainted with it better. The post is written in very a good manner and it contains many useful information for me.