zoukankan      html  css  js  c++  java
  • __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

    -----------------------------------------------------------------------------------------------

    参考文献:

    http://my.oschina.net/moooofly/blog/175019

    http://bbs.csdn.net/topics/350111403

    http://velep.com/archives/795.html

    http://blog.csdn.net/linwhwylb/article/details/6084219

    http://blog.csdn.net/sunnybeike/article/details/6802579

    http://kernelnewbies.org/FAQ/LikelyUnlikely

    http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html

  • 相关阅读:
    [转]windows下mysql配置文件my.ini的位置
    [转]Oracle 11g不能导出空表的多种解决方法
    [转]ORACLE WITH AS 用法(相当于查询开始前构造临时表,提高效率)
    [转]基于WordPress的微信小程序支付功能开发
    从数据库优化到治病(2)治好心悸过程
    算命三十多年的资深命理师的人生感悟!
    从高维度看世界
    鸾书精华
    实用QPS和TPS高的高效分析方法
    windows 安装 mysql
  • 原文地址:https://www.cnblogs.com/LubinLew/p/GCC-__builtin_expect.html
Copyright © 2011-2022 走看看