关于分支预测的基本概念和详细算法可以参考我之前写的知乎回答,基本概念不再阐述了~~

https://www.zhihu.com/question/486239354/answer/2410692045

说几个常见的能够提升CPU分支预测效率的方法。

将最常见的条件比较单独从switch中移出

分支预测除了需要预测方向,还需要预测分支的目标地址。目标地址BTA(Branch Target Address)分为两种:

  • 直接跳转(PC-relative, direct) : offset以立即数形式固定在指令中,所以目标地址也是固定的。
  • 间接跳转(absolute, indirect):目标地址来自通用寄存器,而寄存器的值不固定。

对于直接跳转,使用BTB可以很好的进行预测。但是对于间接跳转,目标地址不固定,更难预测。switch-case的指令实现(类似jmpq *$rax,$rax是case对应label地址)、C++虚函数调用就属于间接跳转。间接跳转如果还用直接跳转的BTB预测,准确率只有50%左右。

很多CPU针对间接跳转都有单独的预测器,比如的Intel的论文The Intel Pentium M Processor: Microarchitecture and Performance中介绍额Indirect Branch Predictor:通过额外引入context-information——Global Branch History来提高间接跳转的目标地址预测准确率。

switch-case的优点是将诸多if/else(conditional branch)转换为统一的unconditioal branch,但缺点就是目标地址难以预测。如果某个case的命中率特别高,就可以将其从switch中单独提出来,这样该分支的预测方向 && 目标地址都很好预测。

比如java dubbo代码里的一个例子::

超过99.9%情况state取值都是ChannelState.RECEIVED ,将其单独提出来。官网博客有一个benchmark,性能有很大的改观。

将使用【控制】的条件转移转换为使用【数据】的条件转移

CMOV指令就是典型的例子。CPU无需进行分支预测,但是会计算一个条件的两种结果,然后通过检查条件码,要么更新目的寄存器,要么保持不变。

比如

v = test-expr ? then-expr : else-expr

会转换为下列伪代码:

v = then-expr;
ve = else-expr;
t = test-expr;
if(!t) v=ve;

编译器会倾向于将使用三元运算符且两种结果的计算量不大的表达式转换为CMOV条件数据转移。例如facebook folly中的例子,注意看注释:

当分支的结果完全由外部输入决定,local branch history和global branch history都毫无规律时,效果会更好。下面这个是《Computer Systems A Programmer's Perspective 》5.11.2小节的例子,第二个版本性能是第一个三倍:

/* Rearrange two vectors so that for each i, b[i] >= a[i] */
void minmax1(long a[], long b[], long n) {
long i;
for (i = 0; i < n; i++) {
if (a[i] > b[i]) {
long t = a[i];
a[i] = b[i];
b[i] = t;
}
}
} /* Rearrange two vectors so that for each i, b[i] >= a[i] */
void minmax2(long a[], long b[], long n) {
long i;
for (i = 0; i < n; i++) {
long min = a[i] < b[i] ? a[i] : b[i];
long max = a[i] < b[i] ? b[i] : a[i];
a[i] = min;
b[i] = max;
}
}

使用算数逻辑代替分支

比如ARM优化手册里提到,可以将范围比较转换为无条件计算,编译器有时候也会自动做这个转换:

// origin version
int insideRange1(int v, int min, int max) {
return v >= min && v < max;
} // optimized version
int insideRange2(int v, int min, int max) {
return (unsigned) (v - min) < (max - min);
}

韦易笑大佬针对这个做过更详细的优化和测试,反正我是看晕了:

引用文章内的测试数据:

Avoiding Branches里有更多的例子,不过用之前还是做测试更靠谱。

使用template移除分支

2018年Stephen Yang的博士论文NanoLog: A Nanosecond Scale Logging System介绍了一款C++日志库Nanolog,将日志调用开销的中位数降为了个位数纳秒级别。作者在文章NANOLOG: A NANOSECOND SCALE LOGGING SYSTEM中提到了Nanolog的关键技术和优化,第三条就是将printf在运行时的大量分支逻辑利用C++ template优化成编译期的运算。

likely/unlikely

这个很多人已经介绍过了,C++20已经将其标准化,支持将更可能执行的代码放在hot path上,对icache更友好。例如facebook folly中的例子:

FOLLY_LIKELY是一个包装:

更进一步,有些ISA的分支指令有一个bit,支持programmer去指定分支是否taken。现代CPU使用的TAGE分支预测器,部分实现会使用该bit去初始化predictor(是初始化,不是一直使用programmer指定的跳转结果)。TAGE预测器可以参考下我开头放的回答:https://www.zhihu.com/question/486239354/answer/2410692045

(完)

朋友们可以关注下我的公众号,获得最及时的更新:

如何在代码层面提供CPU分支预测效率的更多相关文章

  1. CPU 分支预测

    去年在安宁庄的时候, 有个同事阐述了一个观点:php中的if else  在执行时考虑到效率的原因,不会按我们的代码的顺序一条一条去试,而是随机找出一个分支,执行,如果不对,再随机找到一个分支 当时由 ...

  2. 从一段 Dubbo 源码到 CPU 分支预测的一次探险之旅

    每个时代,都不会亏待会学习的人. 大家好,我是 yes. 这次本来是打算写一篇 RocketMQ 相关文章的,但是被插队了,我也是没想到的. 说来也是巧最近在看 Dubbo 源码,然后发现了一处很奇怪 ...

  3. CPU分支预测器

    两篇结合就ok啦 1.https://www.jianshu.com/p/be389eeba589 2.https://blog.csdn.net/edonlii/article/details/87 ...

  4. 现代中央处理器(CPU)是怎样进行分支预测的?

    人们一直追求CPU分支预测的准确率,论文Simultaneous Subordinate Microthreading (SSMT)中给了一组数据,如果分支预测的准确率是100%,大多数应用的IPC会 ...

  5. 【操作系统之十二】分支预测、CPU亲和性(affinity)

    一.分支预测 当包含流水线技术的处理器处理分支指令时就会遇到一个问题,根据判定条件的真/假的不同,有可能会产生转跳,而这会打断流水线中指令的处理,因为处理器无法确定该指令的下一条指令,直到分支执行完毕 ...

  6. 【CPU微架构设计】利用Verilog设计基于饱和计数器和BTB的分支预测器

    在基于流水线(pipeline)的微处理器中,分支预测单元(Branch Predictor Unit)是一个重要的功能部件,它负责收集和分析分支/跳转指令的执行结果,当处理后续分支/跳转指令时,BP ...

  7. GCC的分支预测优化__builtin_expect

    智能指针笔记 GCC的原子操作函数 将流水线引入cpu,可以提高cpu的效率.更简单的说,让cpu可以预先取出下一条指令,可以提供cpu的效率.如下图所示: 取指令 执行指令 输出结果 取指令 执行 ...

  8. __builtin_expect — 分支预测优化

    1.引言 在很多源码如Linux内核.Glib等,我们都能看到likely()和unlikely()这两个宏,通常这两个宏定义是下面这样的形式. #define likely(x) __builtin ...

  9. 通过从代码层面分析Linux内核启动来探知操作系统的启动过程

    通过从代码层面分析Linux内核启动来探知操作系统的启动过程 前言说明 本篇为网易云课堂Linux内核分析课程的第三周作业,我将围绕Linux 3.18的内核中的start_kernel到init进程 ...

随机推荐

  1. 企业应用架构研究系列二:MSF&Scrum 项目管理

    从业软件项目这么多年,在企业应用开发项目中,项目能否成功,是否能按照项目计划有效的推进,是有很强的一套项目管理理论.最早的时候,接触的项目管理的方法论就是微软的MSF(Microsoft Soluti ...

  2. 选择Key-Value Store

    [IT168 专稿]在之前的文章中,给大家介绍了<Redis快速入门:Key-Value存储系统简介>,今天进一步给大家介绍为什么选择Key-Value Store.Key-Value S ...

  3. python 列表,字典,元组,字符串,QuerySet之间的相互转换

    1. 列表转换成字典list1 = ['key1','key2','key3']list2 = ['value1','value2'] dict1 = zip(list1,list2) # dict( ...

  4. 学习heartbeat-05 实现web服务高可用

    一.环境介绍 说明:所有案例在虚拟机(VMware)上完成 操作系统:centos 6.5 64bit 高可用软件:heartbeat 3.0.4 Web应用服务器:apache httpd 2.2. ...

  5. 汽车中的V流程开发

    各步骤的简介各步骤的简介 (1)Control Design and offline Simulation:算法模型构建和离线仿真(基于模型的设计).算法工程师用Matlab模型实现算法:并实施离线仿 ...

  6. 03. Pandas数据结构

    03. Pandas数据结构 Series DataFrame 从DataFrame中查询出Series 1. Series Series是一种类似于一维数组的对象,它由一组数据(不同数据类型)以及一 ...

  7. 媒体查询@media的使用

    媒体查询 参考:https://developer.mozilla.org...一个媒体查询由一个可选的媒体类型和零个或多个使用媒体功能的限制了样式表范围的表达式组成,例如宽度.高度和颜色.媒体查询, ...

  8. ionic的checkbox分析

    之前分析了一个原生的checkbox,趁热打铁分析ionic的自带checkbox. html <label class="checkbox"> <input t ...

  9. 如何用vue打造一个移动端音乐播放器

    写在前面 没错,这就是慕课网上的那个vue音乐播放器,后台是某音乐播放器的线上接口扒取,虽然这类项目写的人很多,但不得不说这还是个少有的适合vue提升的好项目,做这个项目除了想写一个比较大并且功能复杂 ...

  10. window10解决需要管理员删除文件的权限问题

    1.快捷键:"win+R",输入:gpedit.msc  回车 2.依次点击:计算机配置-windows配置-安全设置-本地策略-安全选项 3.将两个管理员批准模式和管理员状态三者 ...