• 转载 __builtin_expect — 分支预测优化


     1.引言

    在很多源码如Linux内核、Glib等,我们都能看到likely()和unlikely()这两个宏,通常这两个宏定义是下面这样的形式。

    #define likely(x)      __builtin_expect(!!(x), 1)
    #define unlikely(x)    __builtin_expect(!!(x), 0)

    可以看出这2个宏都是使用函数 __builtin_expect()实现的, __builtin_expect()函数是GCC的一个内建函数(build-in function).

    2. 函数声明

    函数__builtin_expect()是GCC v2.96版本引入的, 其声明如下:
    long __builtin_expect(long exp, long c);

    2.1. 功能描述

    由于大部分程序员在分支预测方面做得很糟糕,所以GCC 提供了这个内建函数来帮助程序员处理分支预测.

    你期望 exp 表达式的值等于常量 c, c 的值, 如果 c 的值为0(即期望的函数返回值), 那么 执行 if 分支的的可能性小, 否则执行 else 分支的可能性小(函数的返回值等于第一个参数 exp).

    GCC在编译过程中,会将可能性更大的代码紧跟着前面的代码,从而减少指令跳转带来的性能上的下降, 达到优化程序的目的.

    通常,你也许会更喜欢使用 gcc 的一个参数 '-fprofile-arcs' 来收集程序运行的关于执行流程和分支走向的实际反馈信息,但是对于很多程序来说,数据是很难收集的。

    2.2. 参数详解

      ① exp

        exp 为一个整型表达式, 例如: (ptr != NULL)

       ② c

         c 必须是一个编译期常量, 不能使用变量

    2.3. 返回值

      返回值等于 第一个参数 exp

    2.4. 使用方法

    与关键字if一起使用.首先要明确一点就是 if (value) 等价于 if (__builtin_expert(value, x)), 与x的值无关.

    例子如下:

    例子1 : 期望 x == 0, 所以执行func()的可能性小

    复制代码
    if (__builtin_expect(x, 0))
    {
        func();
    }
    else
    {
      //do someting
    }
    复制代码

    例子2 : 期望 ptr !=NULL这个条件成立(1), 所以执行func()的可能性小

    复制代码
    if (__builtin_expect(ptr != NULL, 1))
    {  
      //do something
    }
    else
    {
      func();
    复制代码

    例子3 : 引言中的likely()和unlikely()宏

      首先,看第一个参数!!(x), 他的作用是把(x)转变成"布尔值", 无论(x)的值是多少 !(x)得到的是true或false, !!(x)就得到了原值的"布尔值"

      使用 likely() ,执行 if 后面的语句 的机会更大,使用 unlikely(),执行 else 后面的语句的机会更大。

    复制代码
    #define likely(x)    __builtin_expect(!!(x), 1)
    #define unlikely(x)  __builtin_expect(!!(x), 0)
    
    int main(char *argv[], int argc)
    {
       int a;
    
       /* Get the value from somewhere GCC can't optimize */
       a = atoi (argv[1]);
    
       if (unlikely (a == 2))
      { a++;
    } else   {
       a--;   } printf ("%d ", a); return 0; }
    复制代码

      

     3. RATIONALE(原理)

    if else 句型编译后, 一个分支的汇编代码紧随前面的代码,而另一个分支的汇编代码需要使用JMP指令才能访问到.

    很明显通过JMP访问需要更多的时间, 在复杂的程序中,有很多的if else句型,又或者是一个有if else句型的库函数,每秒钟被调用几万次,

    通常程序员在分支预测方面做得很糟糕, 编译器又不能精准的预测每一个分支,这时JMP产生的时间浪费就会很大,

    函数__builtin_expert()就是用来解决这个问题的.

    具体从汇编角度来分析其原理的例子,大家可以参照http://kernelnewbies.org/FAQ/LikelyUnlikely,

    其对应的中文翻译版见http://velep.com/archives/795.html

    转自:https://www.cnblogs.com/LubinLew/p/GCC-__builtin_expect.html

  • 相关阅读:
    Java HttpClient使用小结
    【剑指offer】Q18:树的子结构
    poj3041-Asteroids , 二分图的最小顶点覆盖数 = 最大匹配数
    jquery.validate+jquery.form提交的三种方式
    "undefined reference to" 问题解决方法
    [Oracle]
    Effective_java之二:慎用重载函数
    C99规范
    迭代、递归替代循环
    1)Linux程序设计入门--基础知识
  • 原文地址:https://www.cnblogs.com/yylingyao/p/13674530.html
Copyright © 2020-2023  润新知