体系结构学习-2-现代处理器最常用的分支预测
现代处理器最常用的解决控制冒险的方法就是分支预测法(Branch Prediction).
在2018年年初Intel承认的"Meltdown"漏洞就和"分支预测"紧密相关。
Meltdown漏洞相关报道
上述报道中对Meltdown漏洞生动的诠释:
赵晓峰打比方说:“我拿着假的录取通知书去拿宿舍钥匙,我虽然会被发现是假冒的,但是在这一过程中,我会发现相应学号对应的相应宿舍。这样,我就能推测出不同专业的学生住在哪了。”
分支预测需要解决的三个核心问题:
(1)是否为跳转指令
(2)是否会跳转
(3)跳转目标地址
MIPS的Branch指令类型:
指令类型 | 指令示例 | 跳转可能性 | 跳转目标地址 |
---|---|---|---|
条件跳转 | beq | 不确定 | 要执行后才能确定 |
无条件跳转 | j | 一定 | 立即数,译码阶段可以计算 |
调用 | jal | 一定 | 立即数,译码阶段可以计算 |
返回 | jr | 一定 | 由call存储的$ra内部值决定 |
间接跳转 | jr | 一定 | 由依赖的寄存器内部值决定 |
jal 和 j 指令可以在译码阶段确定跳转地址,有利于分支预测,其他的需要寄存器访问和指令执行后才能得到跳转信息。
-如果不做分支预测,那么流水线的下一条指令需要stall相应周期,等待跳转信息确定才能继续执行。
-如果分支预测错误,那么流水线需要flush(冲刷)取错的指令,也会浪费时钟周期和计算资源。
分支预测流程
Created with Raphaël 2.2.0Predicte next PCKeep running Prediction is correct?Keep runningFlush pipeline and fetch correct instryesno分支预测错误进行冲刷流水线时,并不会影响用户可见的程序运行(可以这样理解:被冲刷的指令一定是在Branch指令被取入到Branch指令被执行完成这段时间进入CPU的,那么它们都是没有被执行完成后写回的,所以冲刷相当于插入了多个nop一样——只考虑简单的单核情况来理解),但是冲刷可能影响cache等这一些用户不可见的状态,就像之前提到的Meltdown漏洞。
如果按照simple branch(npc = pc +4)方式预测,之前计算了Acc(准确率)=0.86,那么EX阶段得到执行结果,flush需要冲刷掉IF(取址),ID(译码)段的指令,损失两个时钟周期。
理想情况下流水线 CPI = 1,此时估算 CPI=1+0.14∗2=1.28 CPI = 1 + 0.14*2 = 1.28 CPI=1+0.14∗2=1.28
以标准流水线1为基准:
预测正确没有周期损失:0 * 0.86 = 0
预测错误损失两个周期:2 * 0.14 = 0.28
所以分支预测错误发现的越早,那么冲刷的指令也会更少,那么损失的周期就更少(或者降低预测错误率)。我们如果能在ID(译码)阶段就能确定是否跳转,并且计算跳转地址,便能提前发现错误,损失时钟周期降低到1,CPI = 1 + 0.14 * 1 = 1.14
缺点: 实际上这是在ID阶段增加了计算硬件资源和计算复杂性:如ID后加入的比较器是在流水线关键路径上的,会增加时延;地址计算器需要额外加法器。另外还有可能存在数据冒险,比如类似JR,BEQ指令,可能需要转发才能得到比较的原操作数
寻找更好的解决方案
由上文可知降低周期损失的方法主要有尽早发现错误和降低预测错误率两种方法。
那如果我们能在IF阶段就能确定跳转,那么损失周期是不是就能够进一步降低?但是这个时候如何判断呢?会不会由有数据依赖关系呢?如何解决预测的三个问题呢?
Branch Target Buffer(BTB)——基础思想:如果知道了某条PC对应的instr是一条branch而且这条PC会被反复执行,那么在IF阶段就可以按照之前该指令的跳转情况预测本次跳转信息,相当于我们可以建立如下的映射关系:
f(CurrentPC)=>BranchPredictionInfo f( Current \quad PC ) => Branch\quad Prediction \quad Infof(CurrentPC)=>BranchPredictionInfo
BTB工作流程:
- 若此时IF阶段取到了当前PC= 0xbfc0ccb8
(即下图展示的MIPS指令:bnez,表示如果$a1寄存器的值不为0,那么就跳转到目标地址target)
bfc0ccb8: 14a0fffd bnez a1,target
- 根据取得的PC搜索BTB( BTB的数据结构如下,可以联想TLB,Cache来理解:index位对应PC的后四位来在BTB表中作为索引查找并检查Tag位,找到后发现其valid位为1即之前这一条PC执行过跳转指令,于是查看记录的"Target PC——上次跳转目标地址","state——是否会跳转"来进行分支预测)
Index | Valid | Tag | Target PC(last execute) | BP state |
---|---|---|---|---|
… | … | … | … | … |
b8 | 1 | 14a0ff | target(0xbfc0aa88) | 11 |
… | … | … | … | … |
cd | 0 | bfc023 | 0xbfc00380 | 00 |
… | … | … | … | … |
(此BTB的state为2位,state位数也能为1位,但是2位state运行效果不一定比1位的更好,要考虑实际执行的指令和state位的控制方法等因素)
BTB中最关键的便是state位,因为state位决定了是否跳转。
那么如何控制state位与跳转与否的关系呢?——静态分支预测 or 动态分支预测
淡定路过的我 原创文章 19获赞 1访问量 697 关注 私信- 开源处理器Rocket的分支预测机制研究与性能评估(二)
- SpringMVC学习(四)——处理器Handler的各种常用实现
- 【Java深入学习系列】之CPU的分支预测(Branch Prediction)模型
- Python3.4学习笔记之常用操作符,条件分支和循环用法示例
- 体系结构学习-3-基本分支预测方法
- 理解处理器的“分支预测逻辑”,优化程序性能
- 【Java深入学习系列】之CPU的分支预测(Branch Prediction)模型
- 【Java深入学习系列】之CPU的分支预测(Branch Prediction)模型
- Spring框架学习(5)SpringMVC常用注解-基于注解的处理器
- 学习笔记——分支预测入门
- 体系结构复习2——指令级并行(分支预测和VLIW)
- 第四章处理器体系结构 学习报告
- python3.4学习笔记(十) 常用操作符,条件分支和循环实例
- Git常用指令集合 (分支管理)
- 入门学习Linux常用必会60个命令实例详解 Linux必学的60个命令
- Struts2学习篇(三) struts.xml常用配置解析
- java虚拟机学习之java体系结构
- 学习jQuery必须知道的几种常用方法
- python之seaborn画图库学习绘制常用的图
- python基础学习(四):条件和分支