gcc/linux內核中likely、unlikely和__attribute__(section(""))屬性

查看linux內核源碼,你會發現有不少if (likely(""))...及if (unlikely(""))...語句,這些語句實際上是編譯器的一種優化方式,具體分析以下:html

likely及unlikely是一個宏定義:linux

#define likely(x)  __builtin_expect(!!(x), 1)程序員

#define unlikely(x)  __builtin_expect(!!(x), 0)express

 

likely()的 意思是認爲這個分支最有可能發生,如if (likely(x == 0)){...},這個語句表示x等於0最有可能發生,其實語意就至關於if (x == 0){...},只不過likely針架構

對程序指令運行作了優化,不去作一些無謂的指令跳轉;unlikely()意思相反,就是最不可能發生,注意if (unlikely(x == 0))仍是至關於if (x==0)的邏輯。app

 

若是須要更進一步瞭解likely()就必需要深刻了解__bulitin_expect(!!(x), 1)函數。ide

— Built-in Function: long __builtin_expect (long exp, long c)

    You may use __builtin_expect to provide the compiler with branch prediction information. In general, you should prefer to use actual profile feedback for this (-fprofile-arcs), as programmers are notoriously bad at predicting how their programs actually perform.
   However, there are applications in which this data is hard to collect. The return value is the value of exp, which should be an integral expression. The semantics of the built-in are that it is expected that exp == c. For example: if (__builtin_expect (x, 0)) foo (); indicates that we do not expect to call foo, since we expect x to be zero. Since you are limited to integral expressions for exp, you should use constructions such as if (__builtin_expect (ptr != NULL, 1)) foo (*ptr); when testing pointer or floating-point values.

文檔連接:https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#Other-Builtins函數

 

從gcc官方文檔來看,內建函數long __builtin_expect (long exp, long c)主要用於優化程序的分支預測,減小程序的指令跳轉,現代處理器通常都是流水線架構,工具

不少芯片級的優化是靠流水線預取完成的,因此咱們的程序優化也是須要儘可能減小跳轉。測試

 

文檔也提到了因爲大部分程序員根本就不瞭解本身程序的運行狀況,因此推薦咱們在編譯時加上-fprofile-arcs選項去評估咱們的程序分支運行狀況;-fprofile-arcs選

項是代碼覆蓋率測試工具gcov使用時須要增長的編譯選項,gcov可以去統計及分析咱們的程序的分支運行狀況,關於gcov的使用這裏不作介紹,只須要知道gcov是

一個測試統計工具,配合-fprofile-arcs工具使用,__builtin_expect 根據gcov的分析結果來作實際的分支預測優化。

 

這裏能夠你們還會有疑問,爲何#define likely(x)  __builtin_expect(!!(x), 1)中要使用!!(x),這實際上是由於函數__builtin_expect (long exp, long c)指望是

exp == c,這時的1至關於bool值true,因此exp須要是一個bool表達式,經過!!能夠變成bool表達式而不改變原有函數,這樣纔可以正確的與1或0(bool值)作匹配

判斷;試想若是沒有!!,即#define likely(x)  __builtin_expect((x), 1),那麼likely(10)本來是但願表達式是true,可是根據函數的處理邏輯10 != 1,那麼優化會

以false的結果來優化,這樣就陰差陽錯了!!!

 

 

最後講述一下__attribute__(section(""))屬性,這個屬性比較好理解,就是爲某個函數或變量指定section,好比:

int __attribute__(section(".test.data")) value = 0;

這樣的話變量value將會被放在.test.data段中;

void __attribute__((section(".test.text"))) func(void){}

這樣函數func會被放入.test.text段中。

 

查看section信息能夠經過以下命令:readelf -S xxx,能夠查看可執行文件也能夠是目標文件.o,關於section這裏不過多介紹,只要大概知道通常咱們的代碼都是

放在.text段,全局變量通常放在.data段,咱們經過__attribute__((""))定義的符號就放在咱們特定的section裏面。

相關文章
相關標籤/搜索