Android 本地代码中的LIKELY和UNLIKELY宏
阅读Android Frameworks中的C++代码时,经常会碰到在条件判断语句中使用了LIKELY和UNLIKELY这两个宏,找到这两个宏的定义如下:
view plain copy to clipboard print ?- #defineLIKELY(exp)(__builtin_expect((exp)!=0,true))
- #defineUNLIKELY(exp)(__builtin_expect((exp)!=0,false))
long __builtin_expect (long exp, long c)是GCC的内建函数,解析如下:
你可以使用__builtin_expect给编译器提供分支预测的信息,通常,你因该明确使用这个编译选项(‘-fprofile- arcs’),因为很多程序员在如何预测他们编写的代码实际如何执行方面都很糟糕,使用这个宏可以很方面地让编译器优化分支跳转的代码。
这个函数的返回值就是exp:一个整形表达式,c必须是一个常量,该内建函数从语义上是表明:我们期望exp == c。
所以,如果你不考虑程序执行的效率,加不加LIKELY和UNLIKELY宏,执行的结果是一样的:
view plain copy to clipboard print ?- if (LIKELY(exp))
- {
- }
- else
- {
- }
和
view plain copy to clipboard print ?- if (exp)
- {
- }
- else
- {
- }
执行的结果是一样的。
那为什么还要使用这两个宏定义? 以汽车的速度为例子,如果速度超过200公里/小时表示有异常发生,代码可以这样写:
view plain copy to clipboard print ?- if (speed>=200){
- //异常处理代码
- .....
- stop();
- }else {
- //正常处理代码
- continue ();
- }
也可以这样写:
view plain copy to clipboard print ?- if (speed<200){
- //正常处理代码
- continue ();
- }else {
- //异常处理代码
- .....
- stop();
- }
这两个方案执行后都是正确的,但是显然效率是不一样的,因为大多数情况下,汽车的速度不会超过200公里/小时,当采用第一个方案时,大多数情况 下,代码执行到这里时CPU都要执行分支跳转的操作,这破坏了CPU的指令执行流水线,对性能的影响是显而易见的。而第二个方案则避免了这一问题,因为大 多数时候都是顺序执行的。
对于第一种方案,我们可以加上UNLIKELY宏来让编译器来优化:
view plain copy to clipboard print ?- if (UNLIKELY(speed>=200)){
- //异常处理代码
- .....
- stop();
- }else {
- //正常处理代码
- continue ();
- }
加上UNLIKELY宏后,相当于告诉编译器:速度大于200是很少出现的。这样编译器在编译代码时,会适当地调整条件判断的方式,让CPU的指令 执行顺序尽可能不被打乱,已达到优化性能的效果。
所以,对于第二种方案,我们同样可以加上LIKELY宏:
view plain copy to clipboard print ?- if (LIKELY(speed<200)){
- //正常处理代码
- continue ();
- }else {
- //异常处理代码
- .....
- stop();
- }
更多相关文章
- android 横竖屏切换问题解决方案
- Android高效加载大图、多图解决方案,有效避免程序内存溢出现象
- (4.1.12)Android高效加载大图、多图解决方案,有效避免程序OOM
- Cocos2dx android 部分代码的理解
- 【Android】内嵌html页面与native代码简单交互
- WebView 键盘遮挡输入框解决方案
- Android代码混淆常见配置