GCC __builtin_expect的作用

 將流水線引入cpu,可以提高cpu的效率。更簡單的說,讓cpu可以預先取出下一條指令,可以提供cpu的效率。如下圖所示:
+--------------------------------
|取指令 | 執行指令 | 輸出結果
+--------------------------------
|             | 取指令     | 執行
+--------------------------------
可見,cpu流水錢可以減少cpu等待取指令的耗時,從而提高cpu的效率。
        如果存在跳轉指令,那麼預先取出的指令就無用了。cpu在執行當前指令時,從內存中取出了當前指令的下一條指令。執行完當前指令後,cpu發現不是要執行下一條指令,而是執行offset偏移處的指令。cpu只能重新從內存中取出offset偏移處的指令。因此,跳轉指令會降低流水線的效率,也就是降低cpu的效率。
        綜上,在寫程序時應該儘量避免跳轉語句。那麼如何避免跳轉語句呢?答案就是使用__builtin_expect。
        這個指令是gcc引入的,作用是"允許程序員將最有可能執行的分支告訴編譯器"。這個指令的寫法爲:__builtin_expect(EXP, N)。意思是:EXP==N的概率很大。一般的使用方法是將__builtin_expect指令封裝爲LIKELY和UNLIKELY宏。這兩個宏的寫法如下。
        #define LIKELY(x) __builtin_expect(!!(x), 1) //x很可能爲真
        #define UNLIKELY(x) __builtin_expect(!!(x), 0) //x很可能爲假

如下是一個實際的例子。

  1. //test_builtin_expect.c

  2. #define LIKELY(x) __builtin_expect(!!(x), 1)

  3. #define UNLIKELY(x) __builtin_expect(!!(x), 0)

  4.  
  5. int test_likely(int x)

  6. {

  7. if(LIKELY(x))

  8. {

  9. x = 5;

  10. }

  11. else

  12. {

  13. x = 6;

  14. }

  15.  
  16. return x;

  17. }

  18.  
  19. int test_unlikely(int x)

  20. {

  21. if(UNLIKELY(x))

  22. {

  23. x = 5;

  24. }

  25. else

  26. {

  27. x = 6;

  28. }

  29.  
  30. return x;

  31. }


運行如下命令:
        gcc -fprofile-arcs -O2 -c test_builtin_expect.c
        objdump -d test_builtin_expect.o
輸出的彙編碼爲:


 
  1. <test_likely>:

  2. 00 push %ebp

  3. 01 mov %esp,%ebp

  4. 03 mov 0x8(%ebp),%eax

  5. 06 addl $0x1,0x38

  6. 0d adcl $0x0,0x3c

  7. 14 test %eax,%eax

  8. 16 jz 2d <test_likely+0x2d>//主要看這裏。此處的效果是eax不爲零時,不需要跳轉。即x爲真是不跳轉。

  9. 18 addl $0x1,0x40

  10. 1f mov $0x5,%eax

  11. 24 adcl $0x0,0x44

  12. 2b pop %ebp

  13. 2c ret

  14. 2d addl $0x1,0x48

  15. 34 mov $0x6,%eax

  16. 39 adcl $0x0,0x4c

  17. 40 pop %ebp

  18. 41 ret

  19. 42 lea 0x0(%esi,%eiz,1),%esi

  20. 49 lea 0x0(%edi,%eiz,1),%edi

  21.  
  22. <test_unlikely>:

  23. 50    push     %ebp

  24. 51    mov      %esp,%ebp

  25. 53    mov      0x8(%ebp),%edx

  26. 56    addl     $0x1,0x20

  27. 5d    adcl     $0x0,0x24

  28. 64    test     %edx,%edx

  29. 66    jne      7d <test_unlikely+0x2d>//主要看這裏。此處的效果是edx爲零時,不需跳轉。即x爲假時不跳轉。

  30. 68    addl     $0x1,0x30

  31. 6f    mov      $0x6,%eax

  32. 74    adcl     $0x0,0x34

  33. 7b    pop      %ebp

  34. 7c    ret

  35. 7d    addl     $0x1,0x28

  36. 84    mov      $0x5,%eax

  37. 89    adcl     $0x0,0x2c

  38. 90    pop      %ebp

  39. 91    ret

  40. 92    lea      0x0(%esi,%eiz,1),%esi

  41. 99    lea      0x0(%edi,%eiz,1),%edi


        可見,編譯器利用程序員作出的判斷,生成了高效的彙編碼。即,跳轉語句不生效的概率很大。

 

參考資料:http://hi.baidu.com/uu_dou/item/e9f6f41d570d817b7a5f25c7

轉至:https://blog.csdn.net/shuimuniao/article/details/8017971

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章