分支预测优化之__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\n", 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
分支预测优化之__builtin_expect相关推荐
- Pentium Pro架构/流水线及其优化 (3) - 指令流水线/乱序执行核/高速缓存/分支预测/指令预取
Instruction Pipeline 关于Pentium Pro的指令流水线,我从4个来源看到3种不同的说法:11级,12级和14级(没有13级说,不大吉利吧).其实大同小异,不用纠结到底是多少级 ...
- c++20中的分支预测
一.分支预测 得益于CPU的流水线作业,使得计算机运算工的速度大有提高.但是,在一些情况下,意外的情况会打破流水线作业,此时,流水线反而成了一种负累,重新整装新的流水线,会花费更多的CPU时间.如果大 ...
- 《C语言杂记》编译优化之__builtin_expect
最近在研究压缩算法的时候,看到了以下代码: #define LIKELY(c) (__builtin_expect(!!(c), 1)) #define UNLIKELY(c) (__builtin_ ...
- #C++# #likely# #unlikely#减少CPU流水线分支预测错误带来的性能损失
目录 流水线技术 分支预测 什么是likely和unlikely likely/unlikely的原理 likely/unlikely的适用条件 C++20中的likely/unlikely 流水线技 ...
- 【linux】Valgrind工具集详解(十四):Cachegrind(缓存和分支预测分析器)
一.概述 Cachegrind,它模拟CPU中的一级缓存I1,Dl和二级缓存,能够精确地指出程序中cache的丢失和命中.如果需要,它还能够为我们提供cache丢失次数,内存引用次数,以及每行代码,每 ...
- 阿里程序员工作小技巧:理解CPU分支预测,提高代码效率
技术传播的价值,不仅仅体现在通过商业化产品和开源项目来缩短我们构建应用的路径,加速业务的上线速率,体现也会在优秀程序员在工作效率提升,产品性能优化和用户体验改善等小技巧方面的分享,以提高我们的工作能力 ...
- 阿里程序员工作小技巧 | 理解CPU分支预测,提高代码效率
技术传播的价值,不仅仅体现在通过商业化产品和开源项目来缩短我们构建应用的路径,加速业务的上线速率,也会体现在优秀程序员在工作效率提升.产品性能优化和用户体验改善等小技巧方面的分享,以提高我们的工作能力 ...
- Callgrind:调用图生成缓存和分支预测分析器
目录 6.1.概观 6.1.1.功能6.1.2.基本用法 6.2.高级用法 6.2.1.从一个程序运行多次分析转储6.2.2.限制收集事件的范围6.2.3.计算全球巴士事件6.2.4.避免循环6.2. ...
- Cachegrind:缓存和分支预测分析器
目录 5.1.概观5.2.使用Cachegrind,cg_annotate和cg_merge 5.2.1.运行Cachegrind5.2.2.输出文件5.2.3.运行cg_annotate5.2.4. ...
最新文章
- 30 分钟成交额破 3723 亿,天猫双 11 剁手主力军从哪儿来?
- 分类9个无理数并比较他们之间的分布差异
- 微信iOS 7.0.9版本更新:今天的朋友圈是一片欢乐的海洋!
- LeetCode刷题(5)
- springboot格式化时间
- jQuery 页面载入进度条收藏
- 美国基金教父约翰博格传记(1)
- 听音扒谱app_掌握这些,你也可以轻松扒谱(下)
- 谷歌引擎html,国内免费使用谷歌翻译引擎
- Android9怎么截图,华为mate9怎么截图/截屏 华为mate9多种截屏方法图文教程
- 拉格朗日对偶性(Lagrange duality)
- 小白入门知识图谱构建与应用
- 手机号,身份证号,姓名等校验
- 全新内测!mac剪映专业版v1.4.0重磅出击!
- oracle锁资源不够,Oracle解锁,解决“ora00054:资源正忙”错误
- php 已知概率抽奖,抽奖概率算法实现-用PHP来实现的
- 手机拍照技巧:全景拍摄,让手机拍出的照片妙趣横生
- 突破技术壁垒 自由收发Hotmail邮件
- Junit报错:Argument(s) are different! Wanted:
- 法国大数据分析协作初创企业Dataiku获1400万美元风险投资