zoukankan      html  css  js  c++  java
  • [转] GCC __builtin_expect的作用

    http://blog.csdn.net/shuimuniao/article/details/8017971

    将流水线引入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

  • 相关阅读:
    [JSOI2007][BZOJ1031] 字符加密Cipher|后缀数组
    leetcode Flatten Binary Tree to Linked List
    leetcode Pascal's Triangle
    leetcode Triangle
    leetcode Valid Palindrome
    leetcode Word Ladder
    leetcode Longest Consecutive Sequence
    leetcode Sum Root to Leaf Numbers
    leetcode Clone Graph
    leetcode Evaluate Reverse Polish Notation
  • 原文地址:https://www.cnblogs.com/qiangxia/p/4290583.html
Copyright © 2011-2022 走看看