__builtin_expect详解
在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轉(zhuǎn)換為0和1,即真假兩種。要理解宏G_LIKELY和G_UNLIKELY ,很明顯必須理解__builtin_expect。__builtin_expect是GCC(version>=2.9)引進(jìn)的宏,其作用就是幫助編譯器判斷條件跳轉(zhuǎn)的預(yù)期值,避免跳轉(zhuǎn)造成時間亂費(fèi)。拿上面的代碼來說:
if (G_LIKELY (acat == 1))???? //表示大多數(shù)情況下if里面是真,程序大多數(shù)直接執(zhí)行if里面的程序
而
if (G_UNLIKELY (thread_memory_magazine1_is_empty (tmem, ix)))//表示大多數(shù)情況if里面為假,程序大多數(shù)直接執(zhí)行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??? $0x8,%esp
a6: c7 04 24 00 00 00 00 movl?? $0x0,(%esp)
ad: e8 fc ff ff ff?????? call?? ae <_GLOBAL__I_65535_0_test_likely+0xe>
b2: c9?????????????????? leave
b3: c3?????????????????? ret???
[lammy@localhost test_builtin_expect]$
兩個函數(shù)編譯生成的匯編語句所使用到的跳轉(zhuǎn)指令不一樣,仔細(xì)分析下會發(fā)現(xiàn)__builtin_expect實際上是為了滿足在大多數(shù)情況不執(zhí)行跳轉(zhuǎn)指令,所以__builtin_expect僅僅是告訴編譯器優(yōu)化,并沒有改變其對真值的判斷。
這種用法在linux內(nèi)核中也經(jīng)常用到,國外也有一篇相關(guān)的文章,大家不妨看看:http://kernelnewbies.org/FAQ/LikelyUnlikely
不知大家注意到?jīng)]有,我在生產(chǎn)匯編時用的是gcc -fprofile-arcs -O2 -c test_builtin_expect.c,而不是gcc -O2 -c test_builtin_expect.c,具體可以參考http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的__builtin_expect详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: alarm项目bug
- 下一篇: arm for asterisk1.8