zoukankan      html  css  js  c++  java
  • __builtin_expect详解[转]

    转自:http://babybandf.blog.163.com/blog/static/619935320105942336930/

    在GTK+2.0源码中有很多这样的宏:G_LIKELY和G_UNLIKELY。比如下面这段代码:

    if (G_LIKELY (acat == 1))       /* allocate through magazine layer */
          {
            ThreadMemory *tmem = thread_memory_from_self();
            guint ix = SLAB_INDEX (allocator, chunk_size);
            if (G_UNLIKELY (thread_memory_magazine1_is_empty (tmem, ix)))
              {
                thread_memory_swap_magazines (tmem, ix);
                if (G_UNLIKELY (thread_memory_magazine1_is_empty (tmem, ix)))
                  thread_memory_magazine1_reload (tmem, ix);
              }
            mem = thread_memory_magazine1_alloc (tmem, ix);
          }

    在源码中,宏G_LIKELY和G_UNLIKELY 是这么定义的:

    #define G_LIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 1))
    #define G_UNLIKELY(expr) (__builtin_expect (_G_BOOLEAN_EXPR(expr), 0))

    宏_G_BOOLEAN_EXPR的作用是把expr转换为0和1,即真假两种。要理解宏G_LIKELY和G_UNLIKELY ,很明显必须理解__builtin_expect。__builtin_expect是GCC(version>=2.9)引进的宏,其作用就是帮助编译器判断条件跳转的预期值,避免跳转造成时间乱费。拿上面的代码来说:

    if (G_LIKELY (acat == 1))     //表示大多数情况下if里面是真,程序大多数直接执行if里面的程序

    if (G_UNLIKELY (thread_memory_magazine1_is_empty (tmem, ix)))//表示大多数情况if里面为假,程序大多数直接执行else里面的程序

    可能大家看到还是一头雾水,看下面一段就会明白其中的乐趣啦;

    //test_builtin_expect.c 
    #define LIKELY(x) __builtin_expect(!!(x), 1)
    #define UNLIKELY(x) __builtin_expect(!!(x), 0)
    
    int test_likely(int x)
    {
     if(LIKELY(x))
     {
        x = 5;
     }
     else
     {
        x = 6;
     }
      
     return x;
    }
    
    int test_unlikely(int x)
    {
     if(UNLIKELY(x))
     {
        x = 5;
     }
     else
     {
        x = 6;
     }
      
     return x;
    }
    [lammy@localhost test_builtin_expect]$ gcc -fprofile-arcs -O2 -c test_builtin_expect.c 
    [lammy@localhost test_builtin_expect]$ objdump -d test_builtin_expect.o
    test_builtin_expect.o:       file format elf32-i386

    Disassembly of section .text:
    00000000 <test_likely>:
       0: 55                   push   %ebp
       1: 89 e5                mov    %esp,%ebp
       3: 8b 45 08             mov    0x8(%ebp),%eax
       6: 83 05 38 00 00 00 01 addl   $0x1,0x38
       d: 83 15 3c 00 00 00 00 adcl   $0x0,0x3c
    14: 85 c0                test   %eax,%eax
    16: 74 15                je     2d <test_likely+0x2d>//主要看这里
    18: 83 05 40 00 00 00 01 addl   $0x1,0x40
    1f: b8 05 00 00 00       mov    $0x5,%eax
    24: 83 15 44 00 00 00 00 adcl   $0x0,0x44
    2b: 5d                   pop    %ebp
    2c: c3                   ret   
    2d: 83 05 48 00 00 00 01 addl   $0x1,0x48
    34: b8 06 00 00 00       mov    $0x6,%eax
    39: 83 15 4c 00 00 00 00 adcl   $0x0,0x4c
    40: 5d                   pop    %ebp
    41: c3                   ret   
    42: 8d b4 26 00 00 00 00 lea    0x0(%esi,%eiz,1),%esi
    49: 8d bc 27 00 00 00 00 lea    0x0(%edi,%eiz,1),%edi
    00000050 <test_unlikely>:
    50: 55                   push   %ebp
    51: 89 e5                mov    %esp,%ebp
    53: 8b 55 08             mov    0x8(%ebp),%edx
    56: 83 05 20 00 00 00 01 addl   $0x1,0x20
    5d: 83 15 24 00 00 00 00 adcl   $0x0,0x24
    64: 85 d2                test   %edx,%edx
    66: 75 15                jne    7d <test_unlikely+0x2d>//主要看这里
    68: 83 05 30 00 00 00 01 addl   $0x1,0x30
    6f: b8 06 00 00 00       mov    $0x6,%eax
    74: 83 15 34 00 00 00 00 adcl   $0x0,0x34
    7b: 5d                   pop    %ebp
    7c: c3                   ret   
    7d: 83 05 28 00 00 00 01 addl   $0x1,0x28
    84: b8 05 00 00 00       mov    $0x5,%eax
    89: 83 15 2c 00 00 00 00 adcl   $0x0,0x2c
    90: 5d                   pop    %ebp
    91: c3                   ret   
    92: 8d b4 26 00 00 00 00 lea    0x0(%esi,%eiz,1),%esi
    99: 8d bc 27 00 00 00 00 lea    0x0(%edi,%eiz,1),%edi
    000000a0 <_GLOBAL__I_65535_0_test_likely>:
    a0: 55                   push   %ebp
    a1: 89 e5                mov    %esp,%ebp
    a3: 83 ec 08             sub    $0x8,%esp
    a6: c7 04 24 00 00 00 00 movl   $0x0,(%esp)
    ad: e8 fc ff ff ff       call   ae <_GLOBAL__I_65535_0_test_likely+0xe>
    b2: c9                   leave
    b3: c3                   ret   
    [lammy@localhost test_builtin_expect]$

    两个函数编译生成的汇编语句所使用到的跳转指令不一样,仔细分析下会发现__builtin_expect实际上是为了满足在大多数情况不执行跳转指令,所以__builtin_expect仅仅是告诉编译器优化,并没有改变其对真值的判断。

    这种用法在linux内核中也经常用到,国外也有一篇相关的文章,大家不妨看看:http://kernelnewbies.org/FAQ/LikelyUnlikely

    不知大家注意到没有,我在生产汇编时用的是gcc -fprofile-arcs -O2 -c test_builtin_expect.c,而不是gcc -O2 -c test_builtin_expect.c,具体可以参考http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html

  • 相关阅读:
    百度地图画线----可以加上起始位置和终点位置(当前例子没有加)
    android更新SDK时候丢失annotations.jar 导致支持库报错
    java批量转换图片格式
    自定义环形进度条
    第三方账号登录--QQ登录,以及QQ微博账号登录
    矩阵的基本运算,相乘,逆,转置,伴随
    中值滤波和均值滤波C++代码
    opengl 反走样 混合 多重采样 blend multisample
    四元数和欧拉角,轴角对之间的相互转化
    PHP 接口(interface) 和 抽象类(abstract class)
  • 原文地址:https://www.cnblogs.com/xlmeng1988/p/2760337.html
Copyright © 2011-2022 走看看