1. 程式人生 > >Likely和unlikely 分析

Likely和unlikely 分析

以前我有兩個同事寫過關於likely()和unlikely()兩個巨集函式的文件,但是我覺得每個人寫的都有自己更為清晰的地方,所以,將二者組合,以及參考網上http://blog.sina.com.cn/s/blog_70dd16910100w018.html得到以下內容,謝謝你們的勞動。

第一, 分析

這兩個巨集函式的函式含義:

例如在Linux 2.6.38核心include/linux/compiler.h中,這兩個巨集的定義如下:

#define likely(x)    __builtin_expect(!!(x), 1)
#define unlikely(x)  __builtin_expect(!!(x), 0)

____builtin_expect是gcc編譯器(版本>=2.96)提供給程式設計師使用,目的是使得程式設計師可以把分支預測的資訊提供給編譯器,以降低因為指令跳轉帶來的分支下降,它的返回值就是它的第一個引數(這個引數必須是整數)傳給它的值。

所以在linux2.6.38中,____builtin_expect的返回值就是x的值,所以:

if(likely(value))  等價於 if(value)

if(unlikely(value))等價於 if(value)

這樣我們在閱讀程式碼時,就可以把if(likely(value)),if(unlikely(value))看做if(value),便於我們閱讀程式碼。

下面我們來分析__builtin_expect()的機制,在gcc使用手冊中有下面一則例子:

if (__builtin_expect (x, 0))

            foo ();

這段程式暗示我們,既然我們期望__builtin_expect (x, 0)返回值為0,那麼我們不希望呼叫foo()函式。

它通過改變彙編指令的執行順序,來充分利用處理器的流水線。為了達到這樣的目的,它直接執行最有可能的分支指令,而儘可能的避免執行跳轉指令(jmp),因為jmp指令會重新整理CPU的流水線,而影響執行時間。

我們看下面的例子:

第二. 例項分析
//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;
}
執行如下命令:
    gcc -fprofile-arcs -O2 -c test_builtin_expect.c 

    objdump -d test_builtin_expect.o

<test_likely>:
00    push     %ebp
01    mov      %esp,%ebp
03    mov      0x8(%ebp),%eax
06    addl     $0x1,0x38
0d    adcl     $0x0,0x3c
14    test     %eax,%eax
16    jz       2d <test_likely+0x2d>//主要看這裡。此處的效果是eax不為零時,不需要跳轉。即x為真是不跳轉。
18    addl     $0x1,0x40
1f    mov      $0x5,%eax
24    adcl     $0x0,0x44
2b    pop      %ebp
2c    ret      
2d    addl     $0x1,0x48
34    mov      $0x6,%eax
39    adcl     $0x0,0x4c
40    pop      %ebp
41    ret      
42    lea      0x0(%esi,%eiz,1),%esi
49    lea      0x0(%edi,%eiz,1),%edi


<test_unlikely>:
50    push     %ebp
51    mov      %esp,%ebp
53    mov      0x8(%ebp),%edx
56    addl     $0x1,0x20
5d    adcl     $0x0,0x24
64    test     %edx,%edx
66    jne      7d <test_unlikely+0x2d>//主要看這裡。此處的效果是edx為零時,不需跳轉。即x為假時不跳轉。
68    addl     $0x1,0x30
6f    mov      $0x6,%eax
74    adcl     $0x0,0x34
7b    pop      %ebp
7c    ret      
7d    addl     $0x1,0x28
84    mov      $0x5,%eax
89    adcl     $0x0,0x2c
90    pop      %ebp
91    ret      
92    lea      0x0(%esi,%eiz,1),%esi
99    lea      0x0(%edi,%eiz,1),%edi