在项目中看到了likely、unlikely宏的使用, 一直不是非常清楚它们的作用,所以就深究下。

likely表示被測试的表达式大多数情况下为true, unlikely则表示相反。

两个宏定义:

#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)

这两个宏常常在条件转移的语句中使用,如if, else if等,这些语句生成的汇编代码都带有jmp指令.

CPU流水线的一些基本知识.
CPU流水线设计将一条指令的运行分成了好几个阶段,每一个阶段都是独立的逻辑电路。并且每一个阶段都有自己的阶段寄存器,所以各个阶段就能够实现真正的并行运行。

这里借用下CSAPP上的插图:



这里每条指令被分成了3个阶段, 指令I1的A阶段运行完成后。指令I2进入了A阶段运行,而指令I1则进入B阶段运行。I1的B阶段和I2的A阶段是并行运行的。
jmp指令对流水线带来的影响
由于jmp指令的运行会导致CPU跳转到还有一个内存地址,运行全新的指令,导致流水线里面的指令失效。所以CPU须要flush掉流水线上的寄存器。这样的操作须要几个cycle来恢复流水线的运行. 这样的影响被称之为hazard, 详细能够參考hazard Wiki
likely,unlikely带来的优化

依据gcc手冊, 所以这两个宏是用来告诉编译器分支的可能走向,从而帮助CPU进行分支预測来增强CPU流水线性能的.

看下以下的代码


int main (char *argv[], int argc) {
int v; v = atoi(argv[1]); if (likely(a == 5))
a++;
else
a--; printf("%d\n", a); return 0;
}

编译。带上-O2选项,得到的汇编代码:


0000000000400510 <main>:
400510: 48 83 ec 08 sub $0x8,%rsp
400514: 48 8b 7f 08 mov 0x8(%rdi),%rdi
400518: 31 c0 xor %eax,%eax
40051a: e8 f1 fe ff ff callq 400410 <atoi@plt>
40051f: 83 f8 02 cmp $0x2,%eax
400522: 75 18 jne 40053c <main+0x2c> /* likely在这里表示a非常有可能是2, 所以将运行a++和printf调用放在一起, 免去了jmp带来的影响 */
400524: be 03 00 00 00 mov $0x3,%esi
400529: bf 48 06 40 00 mov $0x400648,%edi
40052e: 31 c0 xor %eax,%eax
400530: e8 bb fe ff ff callq 4003f0 <printf@plt>
400535: 31 c0 xor %eax,%eax
400537: 48 83 c4 08 add $0x8,%rsp
40053b: c3 retq
40053c: 8d 70 ff lea -0x1(%rax),%esi
40053f: eb e8 jmp 400529 <main+0x19> /* jump到调用printf代码处, 导致cpu flush掉流水线上的内容. */
400541: 90 nop
适用场景
gcc手冊表示这两条指令应该在程序猿对分支走向相当确定的情况下使用。只是大多数程序猿还是会预測失败,所以建议经过大量profiling来确定可能性。

在linux内核代码中likely和unlikely常常被用在错误代码处理的情况, 由于发生错误的情况往往是少数的。

最新文章

  1. Linux.NET学习手记(8)
  2. GroupData群数据库的还原与优化
  3. Git 命令清单
  4. 转:C/C++程序员简历模板
  5. jquery的工具方法isFunction/isArray/isWindow/isNumeric/isPlainObject/isEmptyObject
  6. linux设备驱动概述,王明学learn
  7. C++-new操作符
  8. SCREAM:Error suppression ignored for
  9. Linq查询Count、Sum、Min、Max、Average
  10. JS与OC交互--简单使用
  11. Android 2014年1月22日
  12. mysql三张表关联查询
  13. 老李分享:《Linux Shell脚本攻略》 要点(二)
  14. 团队作业8——第二次项目冲刺(Beta版本)5.24
  15. 第一行代码阅读笔记---AndroidMainfest.xml分析
  16. UIActionSheet,UIAlertView技术分享
  17. STL的容器算法迭代器的设计理念
  18. OpenCV 初体验
  19. 别人的Linux私房菜(19)认识与分析日志文件
  20. mysql索引简单分析

热门文章

  1. 在linux查看内存的大小
  2. 关于类和对象的进一步讨论之析构函数 C++
  3. 努比亚 N2(Nubia NX575J) 解锁BootLoader 并进入临时recovery ROOT
  4. hibernate_09_关联映射_多对一
  5. PHP实现几秒前、几分钟前、几小时前、几天前
  6. python排序sorted与sort比较 (转)
  7. 【转载】CentOS 安装rz和sz命令 lrzsz
  8. appium的截图
  9. WPF通过鼠标滑轮缩放显示图片
  10. Git 基础教程 之 添加、提交