1. 程式人生 > >詳解likely和unlikely函式【轉】

詳解likely和unlikely函式【轉】

 核心原始碼:linux-2.6.38.8.tar.bz2

     在Linux核心中likely和unlikely函式有兩種(只能兩者選一)實現方式,它們的實現原理稍有不同,但作用是相同的,下面將結合linux-2.6.38.8版本的核心程式碼來進行講解。

    1、對__builtin_expect的封裝

    它們的原始碼如下: 

  1. /* linux-2.6.38.8/include/linux/compiler.h */

  2. # define likely(x) __builtin_expect(!!(x), 1)

  3. # define unlikely(x) __builtin_expect(!!(x), 0)

    __builtin_expect 是GCC的內建函式,用來對選擇語句的判斷條件進行優化,常用於一個判斷條件經常成立(如likely)或經常不成立(如unlikely)的情況。

    __builtin_expect的函式原型為long  __builtin_expect (long exp, long c),返回值為完整表示式exp的值,它的作用是期望表示式exp的值等於c(注意,如果exp == c條件成立的機會佔絕大多數,那麼效能將會得到提升,否則效能反而會下降)。

    在普通的應用程式中也可以使用__builtin_expect,如下面的例子: 

  1. #include <stdio.h>

  2. int main(void)

  3. {

  4. int a;

  5. scanf("%d", &a);

  6. if(__builtin_expect(a, 4))

  7. printf("if: a = %d\n", a);

  8. else

  9. printf("else: a = %d\n", a);

  10. return 0;

  11. }

    分別輸入整數0到4來進行5次測試,它們的輸出分別為: 

  1. else: a = 0

  2. if: a = 1

  3. if: a = 2

  4. if: a = 3

  5. if: a = 4

    注意,在上例中只有輸入整數0的時候才執行else後的列印語句,也就是說__builtin_expect(a, 4)函式的值就是表示式a的值。

    記住,它們只是用來提升效能的優化手段,並不會改變原來表示式的值。

    2、使用__branch_check__函式

    它們的原始碼如下: 

  1. /* linux-2.6.38.8/include/linux/compiler.h */

  2. # ifndef likely

  3. # define likely(x) (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 1))

  4. # endif

  5. # ifndef unlikely

  6. # define unlikely(x) (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 0))

  7. # endif

    (1)、先使用內建函式__builtin_constant_p忽略表示式x為常量的情況

    __builtin_constant_p也是GCC的內建函式,函式原型為int  __builtin_constant_p(exp),用於判斷表示式exp在編譯時是否是一個常量,如果是則函式的值為整數1,否則為0,如下面的例子:

  1. #include <stdio.h>

  2. #include <stdlib.h>

  3. #define VALUE 5

  4. int main(void)

  5. {

  6. char *ptr = NULL;

  7. int num, count;

  8. ptr = malloc(20);

  9. num = __builtin_constant_p(ptr) ? 20 : 20 + 10;

  10. printf("num = %d\n", num);

  11. free(ptr);

  12. count = __builtin_constant_p(VALUE) ? 20 + VALUE : 10;

  13. printf("count = %d\n", count);

  14. return 0;

  15. }

    例子的輸出結果: 

  1. num = 30

  2. count = 25

    例子中的ptr為指標變數,所以__builtin_constant_p(ptr)的值為0,num的值為30。

    (2)、函式__branch_check__的實現 

  1. /* linux-2.6.38.8/include/linux/compiler.h */

  2. #define __branch_check__(x, expect) ({ \

  3. int ______r; \

  4. static struct ftrace_branch_data \

  5. __attribute__((__aligned__(4))) \

  6. __attribute__((section("_ftrace_annotated_branch"))) \

  7. ______f = { \

  8. .func = __func__, \

  9. .file = __FILE__, \

  10. .line = __LINE__, \

  11. }; \

  12. ______r = likely_notrace(x); \

  13. ftrace_likely_update(&______f, ______r, expect); \

  14. ______r; \

  15. })

    使用它來檢查判斷條件並記錄likely判斷的預測資訊,之後根據預測資訊進行相應的優化以提升效能。

    函式__branch_check__的返回值為______r的值,也就是引數x的值。