1.引言
在很多源碼如Linux內核、Glib等,我們都能看到likely()和unlikely()這兩個宏,通常這兩個宏定義是下面這樣的形式。
#define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0)
可以看出這2個宏都是使用函數 __builtin_expect()實現的, __builtin_expect()函數是GCC的一個內建函數(build-in function).
2. 函數聲明
函數__builtin_expect()是GCC v2.96版本引入的, 其聲明如下:
long __builtin_expect(long exp, long c);
2.1. 功能描述
由於大部分程序員在分支預測方面做得很糟糕,所以GCC 提供了這個內建函數來幫助程序員處理分支預測.
你期望 exp 表達式的值等於常量 c, 看 c 的值, 如果 c 的值為0(即期望的函數返回值), 那么 執行 if 分支的的可能性小, 否則執行 else 分支的可能性小(函數的返回值等於第一個參數 exp).
GCC在編譯過程中,會將可能性更大的代碼緊跟着前面的代碼,從而減少指令跳轉帶來的性能上的下降, 達到優化程序的目的.
通常,你也許會更喜歡使用 gcc 的一個參數 '-fprofile-arcs' 來收集程序運行的關於執行流程和分支走向的實際反饋信息,但是對於很多程序來說,數據是很難收集的。
2.2. 參數詳解
① exp
exp 為一個整型表達式, 例如: (ptr != NULL)
② c
c 必須是一個編譯期常量, 不能使用變量
2.3. 返回值
返回值等於 第一個參數 exp
2.4. 使用方法
與關鍵字if一起使用.首先要明確一點就是 if (value) 等價於 if (__builtin_expert(value, x)), 與x的值無關.
例子如下:
例子1 : 期望 x == 0, 所以執行func()的可能性小
if (__builtin_expect(x, 0)) { func(); }
else
{
//do someting
}
例子2 : 期望 ptr !=NULL這個條件成立(1), 所以執行func()的可能性小
if (__builtin_expect(ptr != NULL, 1)) {
//do something
}
else
{
func();
}
例子3 : 引言中的likely()和unlikely()宏
首先,看第一個參數!!(x), 他的作用是把(x)轉變成"布爾值", 無論(x)的值是多少 !(x)得到的是true或false, !!(x)就得到了原值的"布爾值"
使用 likely() ,執行 if 后面的語句 的機會更大,使用 unlikely(),執行 else 后面的語句的機會更大。
#define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0) int main(char *argv[], int argc) { int a; /* Get the value from somewhere GCC can't optimize */ a = atoi (argv[1]); if (unlikely (a == 2))
{ a++;
} else {
a--; } printf ("%d\n", a); return 0; }
3. RATIONALE(原理)
if else 句型編譯后, 一個分支的匯編代碼緊隨前面的代碼,而另一個分支的匯編代碼需要使用JMP指令才能訪問到.
很明顯通過JMP訪問需要更多的時間, 在復雜的程序中,有很多的if else句型,又或者是一個有if else句型的庫函數,每秒鍾被調用幾萬次,
通常程序員在分支預測方面做得很糟糕, 編譯器又不能精准的預測每一個分支,這時JMP產生的時間浪費就會很大,
函數__builtin_expert()就是用來解決這個問題的.
具體從匯編角度來分析其原理的例子,大家可以參照http://kernelnewbies.org/FAQ/LikelyUnlikely,
其對應的中文翻譯版見http://velep.com/archives/795.html
-----------------------------------------------------------------------------------------------
參考文獻:
http://my.oschina.net/moooofly/blog/175019
http://bbs.csdn.net/topics/350111403
http://velep.com/archives/795.html
http://blog.csdn.net/linwhwylb/article/details/6084219
http://blog.csdn.net/sunnybeike/article/details/6802579
http://kernelnewbies.org/FAQ/LikelyUnlikely
http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html