likely, unlikely的作用
阿新 • • 發佈:2017-06-29
這樣的 har spa java asc 使用 設計 fad expect
在項目中看到了likely、unlikely宏的使用, 一直不是非常清楚它們的作用,所以就深究下。
likely表示被測試的表達式大多數情況下為true, unlikely則表示相反。
兩個宏定義:
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
這兩個宏常常在條件轉移的語句中使用,如if, else if等,這些語句生成的匯編代碼都帶有jmp指令.
- CPU流水線的一些基本知識.
- CPU流水線設計將一條指令的運行分成了好幾個階段,每一個階段都是獨立的邏輯電路。並且每一個階段都有自己的階段寄存器,所以各個階段就能夠實現真正的並行運行。
這裏借用下CSAPP上的插圖:
這裏每條指令被分成了3個階段, 指令I1的A階段運行完成後。指令I2進入了A階段運行,而指令I1則進入B階段運行。I1的B階段和I2的A階段是並行運行的。 - jmp指令對流水線帶來的影響
- 由於jmp指令的運行會導致CPU跳轉到還有一個內存地址,運行全新的指令,導致流水線裏面的指令失效。所以CPU須要flush掉流水線上的寄存器。這樣的操作須要幾個cycle來恢復流水線的運行. 這樣的影響被稱之為hazard, 詳細能夠參考hazard Wiki
- likely,unlikely帶來的優化
-
依據gcc手冊, 所以這兩個宏是用來告訴編譯器分支的可能走向,從而幫助CPU進行分支預測來增強CPU流水線性能的.
看下以下的代碼
int main (char *argv[], int argc) { int v; v = atoi(argv[1]); if (likely(a == 5)) a++; else a--; printf("%d\n", a); return 0; }
編譯。帶上-O2選項,得到的匯編代碼:
0000000000400510 <main>: 400510: 48 83 ec 08 sub $0
- 適用場景
- gcc手冊表示這兩條指令應該在程序猿對分支走向相當確定的情況下使用。只是大多數程序猿還是會預測失敗,所以建議經過大量profiling來確定可能性。
在linux內核代碼中likely和unlikely常常被用在錯誤代碼處理的情況, 由於發生錯誤的情況往往是少數的。
likely, unlikely的作用