__builtin_expect — 分支预测优化
2015-07-07 15:41
549 查看
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. 返回值
返回值等于 第一个参数 exp2.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
-----------------------------------------------------------------------------------------------
参考文献:
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
相关文章推荐
- UITextView加边框
- sequence-ID in Dynamic Lookup
- USRP X300 and X310 Configuration Guide
- wp ui线程执行
- Test for Required Behavior, Not Incidental Behavior
- String类、StringBuilder类、StringBuffer类
- Vector与ArrayList,Stringbuffer和StringBuilder和String
- @Responsebody与@RequestBody
- ORA-12514: TNS:listener does not currently know of service requested in connect
- 关于UGUI RectTransform的几个参数的获取和修改(待补充)
- 连接池 druid(阿里巴巴的框架)
- string和stringbuilder区别
- IOS学习之旅-UI基础设置
- leetcode 日经贴,Cpp code -Implement Queue using Stacks
- 【iOS发展-70】点菜系统案例:使用文本框inputView和inputAccessoryView串联UIPickerView、UIDatePicker和UIToolBar
- 此请求已被阻止,因为当用在 GET 请求中时,会将敏感信息透漏给第三方网站。若要允许 GET 请求,请将 JsonRequestBehavior 设置为 AllowGet。
- Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面
- MySQL数据库中tinyint字段值为1,读取出来为true的问题
- easyui常现错误
- UESTC OJ 1647Battery Charging 模拟题