在 GCC 手冊中對 __builtin_expect() 的描述是這樣的:
因爲大部分程序員在分支預測方面作得很糟糕,因此 GCC 提供了這個內建函數來幫助程序員處理分支預測,優化程序。其第一個參數 exp 爲一個整型表達式,這個內建函數的返回值也是這個 exp ,而 c 爲一個編譯期常量。這個函數的語義是:你指望 exp 表達式的值等於常量 c ,從而 GCC 爲你優化程序,將符合這個條件的分支放在合適的地方。通常狀況下,你也許會更喜歡使用 gcc 的一個參數 '-fprofile-arcs' 來收集程序運行的關於執行流程和分支走向的實際反饋信息。
由於這個程序只提供了整型表達式,因此若是你要優化其餘類型的表達式,能夠採用指針的形式。
likely 和 unlikely 是 gcc 擴展的跟處理器相關的宏: 程序員
1
2
|
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
|
如今處理器都是流水線的,有些裏面有多個邏輯運算單元,系統能夠提早取多條指令進行並行處理,但遇到跳轉時,則須要從新取指令,這相對於不用從新去指令就下降了速度。
因此就引入了 likely 和 unlikely ,目的是增長條件分支預測的準確性,cpu 會提早裝載後面的指令,遇到條件轉移指令時會提早預測並裝載某個分 支的指令。unlikely 表示你能夠確認該條件是極少發生的,相反 likely 表示該條件多數狀況下會發生。編譯器會產生相應的代碼來優化 cpu 執行效率。
所以程序員在編寫代碼時能夠根據判斷條件發生的機率來優化處理器的取指操做。
例如: 函數
1
2
3
4
5
|
int
x, y;
if
(unlikely(x > 0))
y = 1;
else
y = -1;
|
上面的代碼中 gcc 編譯的指令會預先讀取 y = -1 這條指令,這適合 x 的值大於 0 的機率比較小的狀況。 若是 x 的值在大部分狀況下是大於 0 的,就應該用 likely(x > 0),這樣編譯出的指令是預先讀取 y = 1 這條指令了。這樣系統在運行時就會減小從新取值了。 性能
======
內核中的 likely() 與 unlikely()
首先要明確: 優化
__builtin_expect() 是 GCC (version >= 2.96)提供給程序員使用的,目的是將「分支轉移」的信息提供給編譯器,這樣編譯器能夠對代碼進行優化,以減小指令跳轉帶來的性能降低。
__builtin_expect((x),1) 表示 x 的值爲真的可能性更大;
__builtin_expect((x),0) 表示 x 的值爲假的可能性更大。
也就是說,使用 likely() ,執行 if 後面的語句 的機會更大,使用 unlikely(),執行 else 後面的語句的機會更大。經過這種方式,編譯器在編譯過程當中,會將可能性更大的代碼緊跟着起面的代碼,從而減小指令跳轉帶來的性能上的降低。ui