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, ))
{
func();
}
else
{
  //do someting
}

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

if (__builtin_expect(ptr != NULL, ))
{  
  //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[]); if (unlikely (a == ))
  {
a++;
}
else
  {
   a--;
  }
printf ("%d\n", a); return ;
}

 

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

__builtin_expect — 分支预测优化的更多相关文章

  1. GCC的分支预测优化__builtin_expect

    智能指针笔记 GCC的原子操作函数 将流水线引入cpu,可以提高cpu的效率.更简单的说,让cpu可以预先取出下一条指令,可以提供cpu的效率.如下图所示: 取指令 执行指令 输出结果 取指令 执行 ...

  2. [开发笔记]GCC 分支预测优化

    #define likely(x) __builtin_expect(!!(x),1)#define unlikely(x) __builtin_expect(!!(x),0) 用于优化在做分支判断的 ...

  3. 现代中央处理器(CPU)是怎样进行分支预测的?

    人们一直追求CPU分支预测的准确率,论文Simultaneous Subordinate Microthreading (SSMT)中给了一组数据,如果分支预测的准确率是100%,大多数应用的IPC会 ...

  4. CPU 分支预测

    去年在安宁庄的时候, 有个同事阐述了一个观点:php中的if else  在执行时考虑到效率的原因,不会按我们的代码的顺序一条一条去试,而是随机找出一个分支,执行,如果不对,再随机找到一个分支 当时由 ...

  5. 分支预测(branch prediction)

    记录一个在StackOverflow上看到一个十分有趣的问题:问题. 高票答案的优化方法: 首先找到罪魁祸首: if (data[c] >= 128) sum += data[c]; 优化方案使 ...

  6. 从一段 Dubbo 源码到 CPU 分支预测的一次探险之旅

    每个时代,都不会亏待会学习的人. 大家好,我是 yes. 这次本来是打算写一篇 RocketMQ 相关文章的,但是被插队了,我也是没想到的. 说来也是巧最近在看 Dubbo 源码,然后发现了一处很奇怪 ...

  7. 如何在代码层面提供CPU分支预测效率

    关于分支预测的基本概念和详细算法可以参考我之前写的知乎回答,基本概念不再阐述了~~ https://www.zhihu.com/question/486239354/answer/2410692045 ...

  8. 【CPU微架构设计】利用Verilog设计基于饱和计数器和BTB的分支预测器

    在基于流水线(pipeline)的微处理器中,分支预测单元(Branch Predictor Unit)是一个重要的功能部件,它负责收集和分析分支/跳转指令的执行结果,当处理后续分支/跳转指令时,BP ...

  9. 【操作系统之十二】分支预测、CPU亲和性(affinity)

    一.分支预测 当包含流水线技术的处理器处理分支指令时就会遇到一个问题,根据判定条件的真/假的不同,有可能会产生转跳,而这会打断流水线中指令的处理,因为处理器无法确定该指令的下一条指令,直到分支执行完毕 ...

随机推荐

  1. Istio

    什么是Istio Istio是Service Mesh(服务网格)的主流实现方案.该方案降低了与微服务架构相关的复杂性,并提供了负载均衡.服务发现.流量管理.断路器.监控.故障注入和智能路由等功能特性 ...

  2. Python的安装与小程序的编写

    Python的安装 在此之前,我完全不了解Python,为了完成任务,在慌忙之中了解了一下Python,通过百度,一步步安装好Python 过程 1.从官网中找到下载菜单并下载最新版本 2.双击pyt ...

  3. airflow 笔记

    首先是一个比较好的英文网站,可能要fq:http://site.clairvoyantsoft.com/installing-and-configuring-apache-airflow/ ===== ...

  4. DirectX11--教程项目无法编译、运行的解决方法

    综述 对于Win10系统的大多数用户来说,可以直接编译本教程对应的项目并运行.但也有部分用户由于某些原因可能会出现无法编译的情况. DirectX11 With Windows SDK完整目录 欢迎加 ...

  5. 关于FastDBF库读写ArcGis dbf文件的小bug

    该库托管于GitHub,地址:https://github.com/SocialExplorer/FastDBF 贡献者应该都是老外,所以…… 1.解析文件头,字段名部分如果有中文命名字段会出错 在D ...

  6. c\c++里struct字节对齐规则

    规则一.: 每个成员变量在其结构体内的偏移量都是成员变量类型的大小的倍数.   规则二: 如果有嵌套结构体,那么内嵌结构体的第一个成员变量在外结构体中的偏移量,是内嵌结构体中那个数据类型大小最大的成员 ...

  7. junit测试

    /**ssm框架测试service**/ import com.alibaba.fastjson.JSON; import com.raycloud.waimai.customer.center.po ...

  8. application.properties 文件和 application.yml 文件的区别

    yml文件的好处,天然的树状结构,方便查看,最终会转成application.properties 注意点: 1,原有的key,例如spring.jpa.properties.hibernate.di ...

  9. Centos6.8 yum安装MySQL5.6

    第一步:安装仓库wget http://repo.mysql.com//mysql57-community-release-el6-8.noarch.rpmrpm -ivh mysql-communi ...

  10. USACO Training Section 1.1 题解(共4题)

    第一题 题目传送门:你的飞碟在这儿 分析 水题一道,输入两个字符串,将它们转换为数字并同时相乘,然后判断一下它们是不是对于47同余就可以了. 代码 #include<bits/stdc++.h& ...