likely和unlikely函數




     在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)  
<span style="font-family:SimHei;font-size:18px;">/* linux-2.6.38.8/include/linux/compiler.h */
# define likely(x)	__builtin_expect(!!(x), 1)
# define unlikely(x)	__builtin_expect(!!(x), 0)</span>

    __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.   
  3. int main(void)  
  4. {  
  5.     int a;  
  6.   
  7.     scanf("%d", &a);  
  8.   
  9.     if(__builtin_expect(a, 4))  
  10.     printf("if: a = %d\n", a);  
  11.     else  
  12.     printf("else: a = %d\n", a);  
  13.   
  14.     return 0;  
  15. }  
<span style="font-family:SimHei;font-size:18px;">#include <stdio.h>

int main(void)
{
    int a;

    scanf("%d", &a);

    if(__builtin_expect(a, 4))
	printf("if: a = %d\n", a);
    else
	printf("else: a = %d\n", a);

    return 0;
}
</span>

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

  1. else: a = 0  
  2.   
  3. if: a = 1  
  4.   
  5. if: a = 2  
  6.   
  7. if: a = 3  
  8.   
  9. if: a = 4  
<span style="font-family:SimHei;font-size:18px;">else: a = 0

if: a = 1

if: a = 2

if: a = 3

if: a = 4
</span>

    注意,在上例中只有輸入整數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  
<span style="font-family:SimHei;font-size:18px;">/* linux-2.6.38.8/include/linux/compiler.h */
# ifndef likely
#  define likely(x)	(__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 1))
# endif
# ifndef unlikely
#  define unlikely(x)	(__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 0))
# endif</span>

    (1)、先使用內置函數__builtin_constant_p忽略表達式x爲常量的情況 (這而的!!(x)爲什麼不寫成x呢?)

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

  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3.   
  4. #define VALUE 5  
  5.   
  6. int main(void)  
  7. {  
  8.     char *ptr = NULL;  
  9.     int num, count;  
  10.   
  11.     ptr = malloc(20);  
  12.     num = __builtin_constant_p(ptr) ? 20 : 20 + 10;  
  13.     printf("num = %d\n", num);  
  14.     free(ptr);  
  15.   
  16.     count = __builtin_constant_p(VALUE) ? 20 + VALUE : 10;  
  17.     printf("count = %d\n", count);  
  18.   
  19.     return 0;  
  20. }  
<span style="font-family:SimHei;font-size:18px;">#include <stdio.h>
#include <stdlib.h>

#define VALUE 5

int main(void)
{
    char *ptr = NULL;
    int num, count;

    ptr = malloc(20);
    num = __builtin_constant_p(ptr) ? 20 : 20 + 10;
    printf("num = %d\n", num);
    free(ptr);

    count = __builtin_constant_p(VALUE) ? 20 + VALUE : 10;
    printf("count = %d\n", count);

    return 0;
}
</span>

    例子的輸出結果: 

  1. num = 30  
  2. count = 25  
<span style="font-family:SimHei;font-size:18px;">num = 30
count = 25
</span>

    例子中的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.         })  
<span style="font-family:SimHei;font-size:18px;">/* linux-2.6.38.8/include/linux/compiler.h */
#define __branch_check__(x, expect) ({					\
			int ______r;					\
			static struct ftrace_branch_data		\
				__attribute__((__aligned__(4)))		\
				__attribute__((section("_ftrace_annotated_branch"))) \
				______f = {				\
				.func = __func__,			\
				.file = __FILE__,			\
				.line = __LINE__,			\
			};						\
			______r = likely_notrace(x);			\
			ftrace_likely_update(&______f, ______r, expect); \
			______r;					\
		})</span>

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

    函數__branch_check__的返回值爲______r的值,也就是參數x的值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章