青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

posts - 200, comments - 8, trackbacks - 0, articles - 0

__builtin_expect 解惑

Posted on 2014-09-29 21:31 鑫龍 閱讀(7734) 評論(0)  編輯 收藏 引用 所屬分類: linux內核
轉自:http://my.oschina.net/moooofly/blog/175019

最近看 GLib 的代碼遇到這個東東,網上搜索一圈,發現很多人都寫過這個,自己今天才研究到,汗顏一下,掃盲一個點,留此記錄為證!

首先看一篇最官方的講解:

======
likely() and unlikely()

What are they ?
      In Linux kernel code, one often find calls to likely() and unlikely(), in conditions, like :
1
2
3
4
5
6
bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx);
if (unlikely(!bvl)) {
  mempool_free(bio, bio_pool);
  bio = NULL;
  goto out;
}
      In fact, these functions are hints for the compiler that allows it to correctly optimize the branch, by knowing which is the likeliest one. The definitions of these macros, found in include/linux/compiler.h are the following :
1
2
#define likely(x)       __builtin_expect(!!(x), 1)
#define unlikely(x)     __builtin_expect(!!(x), 0)
The GCC documentation explains the role of __builtin_expect() :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- 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.
How does it optimize things ?
      It optimizes things by ordering the generated assembly code correctly, to optimize the usage of the processor pipeline. To do so, they arrange the code so that the likeliest branch is executed without performing any jmp instruction (which has the bad effect of flushing the processor pipeline).

To see how it works, let's compile the following simple C user space program with gcc -O2 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#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;
}
Now, disassemble the resulting binary using objdump -S (comments added by me) :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
080483b0 <main>:
 // Prologue
 80483b0:       55                      push   %ebp
 80483b1:       89 e5                   mov    %esp,%ebp
 80483b3:       50                      push   %eax
 80483b4:       50                      push   %eax
 80483b5:       83 e4 f0                and    $0xfffffff0,%esp
 //             Call atoi()
 80483b8:       8b 45 08                mov    0x8(%ebp),%eax
 80483bb:       83 ec 1c                sub    $0x1c,%esp
 80483be:       8b 48 04                mov    0x4(%eax),%ecx
 80483c1:       51                      push   %ecx
 80483c2:       e8 1d ff ff ff          call   80482e4 <atoi@plt>
 80483c7:       83 c4 10                add    $0x10,%esp
 //             Test the value
 80483ca:       83 f8 02                cmp    $0x2,%eax
 //             --------------------------------------------------------
 //             If 'a' equal to 2 (which is unlikely), then jump,
 //             otherwise continue directly, without jump, so that it
 //             doesn't flush the pipeline.
 //             --------------------------------------------------------
 80483cd:       74 12                   je     80483e1 <main+0x31>
 80483cf:       48                      dec    %eax
 //             Call printf
 80483d0:       52                      push   %edx
 80483d1:       52                      push   %edx
 80483d2:       50                      push   %eax
 80483d3:       68 c8 84 04 08          push   $0x80484c8
 80483d8:       e8 f7 fe ff ff          call   80482d4 <printf@plt>
 //             Return 0 and go out.
 80483dd:       31 c0                   xor    %eax,%eax
 80483df:       c9                      leave
 80483e0:       c3                      ret
Now, in the previous program, replace the unlikely() by a likely(), recompile it, and disassemble it again (again, comments added by me) :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
080483b0 <main>:
 //             Prologue
 80483b0:       55                      push   %ebp
 80483b1:       89 e5                   mov    %esp,%ebp
 80483b3:       50                      push   %eax
 80483b4:       50                      push   %eax
 80483b5:       83 e4 f0                and    $0xfffffff0,%esp
 //             Call atoi()
 80483b8:       8b 45 08                mov    0x8(%ebp),%eax
 80483bb:       83 ec 1c                sub    $0x1c,%esp
 80483be:       8b 48 04                mov    0x4(%eax),%ecx
 80483c1:       51                      push   %ecx
 80483c2:       e8 1d ff ff ff          call   80482e4 <atoi@plt>
 80483c7:       83 c4 10                add    $0x10,%esp
 //             --------------------------------------------------
 //             If 'a' equal 2 (which is likely), we will continue
 //             without branching, so without flusing the pipeline. The
 //             jump only occurs when a != 2, which is unlikely.
 //             ---------------------------------------------------
 80483ca:       83 f8 02                cmp    $0x2,%eax
 80483cd:       75 13                   jne    80483e2 <main+0x32>
 //             Here the a++ incrementation has been optimized by gcc
 80483cf:       b0 03                   mov    $0x3,%al
 //             Call printf()
 80483d1:       52                      push   %edx
 80483d2:       52                      push   %edx
 80483d3:       50                      push   %eax
 80483d4:       68 c8 84 04 08          push   $0x80484c8
 80483d9:       e8 f6 fe ff ff          call   80482d4 <printf@plt>
 //             Return 0 and go out.
 80483de:       31 c0                   xor    %eax,%eax
 80483e0:       c9                      leave
 80483e1:       c3                      ret
How should I use it ?
      You should use it only in cases when the likeliest branch is very very very likely, or when the unlikeliest branch is very very very unlikely.

======

看完最權威的,下面看下“民間”的說法:

======
likely,unlikely宏與GCC內建函數__builtin_expect()

在 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()

首先要明確:
  • if(likely(value)) 等價于 if(value)
  • if(unlikely(value)) 也等價于 if(value)
       __builtin_expect() 是 GCC (version >= 2.96)提供給程序員使用的,目的是將“分支轉移”的信息提供給編譯器,這樣編譯器可以對代碼進行優化,以減少指令跳轉帶來的性能下降。

__builtin_expect((x),1) 表示 x 的值為真的可能性更大;
__builtin_expect((x),0) 表示 x 的值為假的可能性更大。

      也就是說,使用 likely() ,執行 if 后面的語句 的機會更大,使用 unlikely(),執行 else 后面的語句的機會更大。通過這種方式,編譯器在編譯過程中,會將可能性更大的代碼緊跟著起面的代碼,從而減少指令跳轉帶來的性能上的下降。

======

看完一圈別 人寫的東西,自己也要輸出點干貨,列舉 GLib-2.35.4 中  gmacros.h 代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*
 * The G_LIKELY and G_UNLIKELY macros let the programmer give hints to
 * the compiler about the expected result of an expression. Some compilers
 * can use this information for optimizations.
 *
 * The _G_BOOLEAN_EXPR macro is intended to trigger a gcc warning when
 * putting assignments in g_return_if_fail (). 
 */
#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
#define _G_BOOLEAN_EXPR(expr)                   \
 G_GNUC_EXTENSION ({                            \
   int _g_boolean_var_;                         \
   if (expr)                                    \
      _g_boolean_var_ = 1;                      \
   else                                         \
      _g_boolean_var_ = 0;                      \
   _g_boolean_var_;                             \
})
// 為條件判斷提供程序員期望的結果-- 用于編譯器優化
#define G_LIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 1))
#define G_UNLIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 0))
#else
#define G_LIKELY(expr) (expr)
#define G_UNLIKELY(expr) (expr)
#endif
由上可以看出, GLib 中使用  _G_BOOLEAN_EXPR(expr) 代替了 !!(expr) 。但功能上是一樣的。
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            免费在线观看成人av| 亚洲欧美另类在线观看| 曰韩精品一区二区| 一区二区三区在线高清| 国产欧美一区二区三区另类精品 | 亚洲综合视频网| a4yy欧美一区二区三区| 亚洲综合不卡| 久久久久国产精品午夜一区| 母乳一区在线观看| 欧美日韩在线观看一区二区三区| 欧美www视频| 欧美日韩精品一本二本三本| 欧美视频在线免费| 狠狠干成人综合网| 亚洲日本欧美| 午夜精品短视频| 久久这里有精品15一区二区三区| 浪潮色综合久久天堂| 亚洲国产天堂网精品网站| 亚洲区欧美区| 亚洲伊人第一页| 欧美一区二区三区的| 亚洲欧美国产精品va在线观看| 午夜精品成人在线| 亚洲国产精品一区在线观看不卡| 亚洲一区久久| 欧美日韩国产二区| 在线观看欧美成人| 午夜日韩在线| 9l国产精品久久久久麻豆| 久久在线视频| 国产精品黄色在线观看| 亚洲国产欧美一区二区三区丁香婷| 午夜精品久久久久久久99樱桃| 亚洲国产精品精华液2区45| 欧美一区二区三区久久精品茉莉花 | 国产日韩欧美自拍| 亚洲精品视频一区| 久久频这里精品99香蕉| 亚洲欧美日韩一区二区在线| 欧美日本在线视频| 亚洲高清一区二| 久久久免费精品| 亚洲综合色自拍一区| 欧美亚洲成人网| 悠悠资源网亚洲青| 欧美伊久线香蕉线新在线| 99re热这里只有精品免费视频| 欧美aⅴ99久久黑人专区| 尤物在线观看一区| 美女啪啪无遮挡免费久久网站| 亚洲欧美网站| 国产精品美女主播| 一本大道久久a久久综合婷婷| 久久久一二三| 久久精品99久久香蕉国产色戒| 国产欧美一区二区三区在线老狼| 亚洲一区欧美激情| 一区二区三区日韩精品| 欧美性天天影院| 亚洲欧美日韩一区在线观看| 亚洲男人影院| 国产区在线观看成人精品| 一本色道久久88亚洲综合88| 日韩网站在线| 国产精品卡一卡二| 久久精品成人一区二区三区 | 欧美韩日一区| 欧美不卡在线| 9久草视频在线视频精品| 亚洲第一精品久久忘忧草社区| 欧美在线亚洲综合一区| 韩国av一区二区三区四区| 欧美福利视频一区| 美女国产一区| 亚洲一级黄色| 久久精品一本| 麻豆精品精华液| 亚洲一区bb| 国产亚洲欧美色| 男人的天堂亚洲| 欧美第一黄色网| 中文高清一区| 久久aⅴ国产欧美74aaa| 亚洲国产精品嫩草影院| 亚洲毛片一区| 国产在线麻豆精品观看| 亚洲电影网站| 国产精品欧美经典| 久久中文欧美| 久久久av水蜜桃| 亚洲国产精品成人| 夜夜嗨av一区二区三区中文字幕| 国产日韩欧美在线| 亚洲第一综合天堂另类专| 国产精品视频九色porn| 在线视频精品| 久久视频一区| 亚洲欧美日韩一区在线| 免费成人黄色av| 欧美一区网站| 欧美日韩免费在线| 女女同性女同一区二区三区91| 欧美午夜久久久| 亚洲国产精品va在线观看黑人| 国产噜噜噜噜噜久久久久久久久 | 欧美日韩国产一区二区三区地区 | 亚洲国产精品va在线观看黑人| 国产精品视频导航| 欧美成人午夜| 国产欧美日韩精品专区| 亚洲人成亚洲人成在线观看图片| 国产一区二区按摩在线观看| 99re热精品| 亚洲美女av网站| 理论片一区二区在线| 欧美专区在线| 欧美午夜电影在线观看| 欧美搞黄网站| 樱花yy私人影院亚洲| 亚洲综合精品四区| 亚洲综合色婷婷| 欧美色精品在线视频| 亚洲人成人99网站| 亚洲精品午夜| 欧美国产精品中文字幕| 欧美成人一区二区三区在线观看| 久久国产精品第一页| 亚洲精品乱码久久久久久日本蜜臀 | 欧美精品乱码久久久久久按摩| 久久成人这里只有精品| 国产精品久久久爽爽爽麻豆色哟哟| 亚洲人体大胆视频| 亚洲精品中文在线| 欧美大片在线看免费观看| 欧美成人午夜免费视在线看片 | 精品999网站| 久久九九99| 美女视频一区免费观看| 国产亚洲精品综合一区91| 午夜免费在线观看精品视频| 欧美一区二区三区播放老司机| 国产精品视频久久一区| 亚洲视频福利| 欧美在线视频不卡| 一区二区三区我不卡| 免费看av成人| 亚洲精品中文字幕有码专区| 宅男精品导航| 国产精品午夜电影| 久久av二区| 亚洲第一精品夜夜躁人人爽| 日韩亚洲不卡在线| 国产精品初高中精品久久| 亚洲欧美日产图| 蜜桃久久av一区| 99在线观看免费视频精品观看| 欧美亚州一区二区三区| 欧美影片第一页| 亚洲国产欧美国产综合一区| 亚洲午夜精品久久久久久浪潮| 国产精品中文在线| 久久色中文字幕| 亚洲色无码播放| 久久在线免费观看视频| 99日韩精品| 国内精品久久久久久| 欧美国产日产韩国视频| 亚洲视频综合在线| 美女成人午夜| 亚洲一区三区在线观看| 狠狠色丁香久久婷婷综合_中| 欧美国产国产综合| 午夜欧美大片免费观看| 亚洲欧洲在线播放| 久久九九久精品国产免费直播| 亚洲国产二区| 国产精品色一区二区三区| 另类av一区二区| 午夜精品久久久久久| 亚洲国产欧美国产综合一区| 久久成人18免费观看| 日韩视频久久| 激情成人在线视频| 国产精品a久久久久久| 午夜在线精品偷拍| 亚洲激情啪啪| 免费人成网站在线观看欧美高清| 亚洲一区二区三区777| 亚洲第一精品在线| 国产日韩欧美在线播放不卡| 欧美区在线观看| 蜜臀av在线播放一区二区三区| 亚洲欧美日韩国产综合| 夜夜嗨av一区二区三区| 91久久精品美女高潮| 久久青青草综合| 亚洲欧美日韩一区二区在线| 一本色道久久综合|