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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值