Linux, 工作, 生活, 家人

Linux

[Kernel] Linux Kernel 內的 Macro likely() 和 unlikely()

在讀 Linux Permier 中文版的時候. Page 2-41 有一段

使用 likely() 與 unlikely() 巨集透過編譯器告知 CPU 有哪些程式區段不需要預測(likely)或有哪些程式區段需要預測(unlikely).

我對這一段有些懷疑, 為什麼要這樣做? 上網做了一下功課.
對映原始的 define

#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)

這是使用 GCC 內的特殊 Function, 可以查 GCC Document

— 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 value of C must be a compile-time constant. The
semantics of the built-in are that it is expected that EXP == C.
For example:

if (__builtin_expect (x, 0))
foo ();

would indicate 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))
error ();

when testing pointer or floating-point values.

簡單的說,

if(likely(x)){
預期想執行的 Code
}else{
}

if(unlikely(x)){
}else{
預期想執行的 Code
}

這樣就可以利用 Compile 本身的功能最佳化 Processor 的 Pipeline (用 Branch Prediction)
在 x86 上是有用的.

不過我手上的 ARM Crosscompile 沒有一版可以產生不同結果的 Code.
不確定是因為 ARM9 不支援, 還是有其他因素.

2008.12.16 Update

這兩天在整理 Code, 結果發現我會有 ARM Crosscompile 會有相同結果的結論是錯的,
我仔細的做了一下檢查, 我原來的 Code 是這樣

11:1.c           ****    if (likely (a == 2))
32                            .loc 1 11 0
33 000c 020050E3              cmp     r0, #2
34 0010 1410A013              movne   r1, #20
35                    .LVL3:
36 0014 0A10A003              moveq   r1, #10
12:1.c           ****       a=10;
13:1.c           ****    else
14:1.c           ****       a=20;
15:1.c           ****

這邊其實最佳化就被 Compile 給和諧掉了, 所以這一段不管是用 likely or unlikely 都是執行三行指令.
如果改寫複雜一點的程式, 就會不一樣了.

if (unlikely (a == 2)) {
a=pow(5,5);
b=30; }
else{
a=20;
c=40; }

ARM Crosscompile 參數改用

arm-linux-gcc -mcpu=mpcore -c -O2 -g -Wa,-a,-ad  t-unlikely.c > 1
arm-linux-objdump -dS t-unlikely.o > 11

稍稍修改一下, 就可以知道輸出結果了.
arm-linux-objdump 的結果比較清楚.

Ref.
FAQ/LikelyUnlikely
Kernel : likely/unlikely macros

[Tags] Linux , Kernel , Marco, Likely, Unlikely [/Tags]

3 留言

  1. jsli

    現在手邊沒有 cross-compiler 可以試,不過 ARM 的 instruction set 有 conditional execution 的 flag, 可以取代部份的 branch, 再加上 ARM9 5-stage pipeline 和相對較小的 cache, Branch prediction 就沒那麼重要了。Branch prediction 通常是為了避免 pipeline stall 和 cache miss penalty, 這部份 x86 要嚴重多了。

  2. 匿名訪客

    最后结论说反了吧

  3. 匿名訪客

    long __builtin_expect (long EXP, long C)
    #define unlikely(x) __builtin_expect(!!(x), 0)
    the built-in are that it is expected that EXP == C
    ==> unlikely(x) 表示期望 x == 0

    上面的觀念…………有點問題

發佈留言