• C/C++ 分支预测(likely unlikely)


    看一些代码时,会遇到likely unlikely, 查了查网上的资料,结合自己的理解记录一下。

    1. 一些概念

      指令周期是指执行一条指令所需要的时间,一般由若干个机器周期组成,是从取指令、分析指令到指令执行完所需的全部。

      预取指令具体方法就是在不命中时,当数据从主存储器中取出送往CPU的同时,把主存储器相邻几个单元中的数据(称为一个数据块)都取出来送入Cache中。预取指令可以更好的利用 cpu资源。简单说就是从内存取指令很慢, cpu要等待这个过程。如果能提前预测可能执行的指令,就提前从内存把指令读到 cache, 由于 cache的访问速度较内存快,cpu要执行时就不用等很长时间了。

      如果开发人员可以告诉编译器,哪个分支更有可能发生(likely) 或者 非常不可能发生(unlikely), 可以帮助编译器进行代码编译

    2. 看看代码

    unlikely.cpp:

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 
     4 #define likely(x) __builtin_expect(!!(x), 1) //gcc内置函数, 帮助编译器分支优化
     5 #define unlikely(x) __builtin_expect(!!(x), 0)
     6 
     7 int main(int argc, char* argv[]){
     8     int x = 0;
     9     x = atoi(argv[1]);
    10 
    11     if (unlikely(x == 3)){  //告诉编译器这个分支非常不可能为true
    12         x = x + 9;
    13     }
    14     else{
    15         x = x - 8;
    16     }
    17 
    18     printf("x=%d
    ", x);
    19     return 0;
    20 }

    3. 分析一下

    gcc版本:gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3

    编译:gcc -O2 unlikely.cpp -o unlikely

    反汇编一下,看看汇编:objdump -S unlikely

     1 08048380 <main>:
     2  8048380:   55                      push   %ebp
     3  8048381:   89 e5                   mov    %esp,%ebp
     4  8048383:   83 e4 f0                and    $0xfffffff0,%esp
     5  8048386:   83 ec 10                sub    $0x10,%esp
     6  8048389:   8b 45 0c                mov    0xc(%ebp),%eax
     7  804838c:   c7 44 24 08 0a 00 00    movl   $0xa,0x8(%esp)
     8  8048393:   00
     9  8048394:   c7 44 24 04 00 00 00    movl   $0x0,0x4(%esp)
    10  804839b:   00
    11  804839c:   8b 40 04                mov    0x4(%eax),%eax
    12  804839f:   89 04 24                mov    %eax,(%esp)
    13  80483a2:   e8 c9 ff ff ff          call   8048370 <strtol@plt>
    14  80483a7:   83 f8 03                cmp    $0x3,%eax
    15  80483aa:   74 1f                   je     80483cb <main+0x4b>
    16  80483ac:   83 e8 08                sub    $0x8,%eax
    17  80483af:   89 44 24 08             mov    %eax,0x8(%esp)
    18  80483b3:   c7 44 24 04 60 85 04    movl   $0x8048560,0x4(%esp)
    19  80483ba:   08
    20  80483bb:   c7 04 24 01 00 00 00    movl   $0x1,(%esp)
    21  80483c2:   e8 99 ff ff ff          call   8048360 <__printf_chk@plt>
    22  80483c7:   31 c0                   xor    %eax,%eax
    23  80483c9:   c9                      leave
    24  80483ca:   c3                      ret
    25  80483cb:   b8 0c 00 00 00          mov    $0xc,%eax
    26  80483d0:   eb dd                   jmp    80483af <main+0x2f>
    27  80483d2:   90                      nop
    28  80483d3:   90                      nop

     我们从汇编代码可以看到,代码并不是按照顺序生成的。

    unlikely分支(x==3)非常不可能发生,汇编代码生成到了最后。

    这个对于庞大的代码还是非常有用的,毕竟在代码预期阶段,可以根据局部性原理把最可能发生的分支对应的指令缓存进来。

  • 相关阅读:
    oracle lpad函数和rpad函数
    OREACLE SUBSTR()函数应用-截取字符函数
    oracle常用数值函数
    Oracle 分析函数row_number() over (partition by order by )
    oracle中decode函数用法
    oracle数据字典信息整理
    python学习遇到的英文词汇
    读书随想
    常用css列表
    爬虫趣事
  • 原文地址:https://www.cnblogs.com/xudong-bupt/p/7337240.html
Copyright © 2020-2023  润新知