__builtin_expect(!!(x),1)

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

 

这两个宏的主要作用,就是告诉编译器:某一个分支发生的概率很高,或者说很低,基本不可能发生。编译器就根据这个提示信息,就会去做一些分值预测的编译优化。在这两个宏定义有一个细节,就是对宏的参数 x 做两次取非操作,这是为了将参数 x 转换为布尔类型,然后与 1 和 0 作比较,告诉编译器 x 为真或为假的可能性很高。

 

 

__builtin_expect 这个函数的主要用途就是编译器的分支预测优化。现代 CPU 内部,都有 cache 这个缓存器件。CPU 的运行速度很高,而外部 RAM 的速度相对来说就低了不少,所以当 CPU 从内存 RAM 读写数据时就会有一定的性能瓶颈。为了提高程序执行效率,CPU 都会通过 cache 这个 CPU 内部缓冲区来缓存一定的指令或数据。CPU 读写内存 RAM 中的数据时,会先到 cache 里面去看看能不能找到。找到的话就直接进行读写;找不到的话,cache 会重新缓存一部分内存数据进来。CPU 读写 cache 的速度远远大于内存 RAM,所以通过这种方式,可以提高系统的性能。

那 cache 如何缓存内存数据呢?简单来说,就是依据空间相近原则。比如 CPU 正在执行一条指令,那么下一个指令周期,CPU 就会大概率执行当前指令的下一条指令。如果此时 cache 将下面几条指令都缓存到 cache 里面,下一个指令周期 CPU 就可以直接到 cache 里取指、翻译、执行,从而使运算效率大大提高。

但有时候也会出现意外。比如程序在执行过程中遇到函数调用、if 分支、goto 跳转等程序结构,会跳到其它地址执行,那么缓存到 cache 中的指令就不是 CPU 要获取的指令。此时,我们就说 cache 没有命中,cache 会重新缓存正确的指令代码给 CPU 读取,这就是 cache 工作的基本流程。

有了这个理论基础,我们在编写程序时,遇到 if/switch 这种选择分支的程序结构,可以将大概率发生的分支写在前面,这样程序运行时,因为大概率发生,所以大部分时间就不需要跳转,程序就相当于一个顺序结构,从而提高 cache 的命中率。内核中已经实现一些相关的宏,如 likely 和 unlikely,用来提醒程序员优化程序。
 

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值