分支预测算法

目录

前言

参考

介绍

静态分支预测:

动态分支预测:

1bit预测器:

2位饱和计数器:

BHT预测:

两级分支预测器:(PHT)

分支目标缓冲器:(BTB)

基于全局历史的分支预测器:

GHR预测器:

Gshare分支预测器:

混合预测:

感知机预测:

TAGE分支预测器:

返回地址堆栈(RAS):

总结:


前言

本篇文章只适合初步入门学习,更细致的学习需要参考更多的论文,其涉及的代码我并没有深入的研究,所以文章适合理论学习,项目可参考其他开源处理器核,如OpenHw的CVA6或者PULP的官网。图是用visio画的,一些图借用了知乎专栏,侵权删。

难免由疏忽之处还请大佬指正。

参考

开源RISC-V处理器架构分析与验证 ,知乎,超标量处理器,以及网上资料整理。

介绍

取指模块取到分支指令的时候,我们不希望等到执行单元解析出指令后再进行跳转,那会造成流水线停顿。

因此我们引入分支预测,再译码阶段就知道它的是否执行肯定会事半功倍,这样减少了冲刷流水线操作(flush)。

所以,进行分支预测的阶段通常是再译码阶段就要执行,预测分支指令,我们需要预测两个东西。

  1. 指令是否跳转?
  2. 指令跳转地址?

分支预测分为静态预测和动态预测:

静态分支预测:

静态预测很好理解,总是默认跳转或者默认不跳转,这种预测方式在硬件上实现简单,但是预测度很低,对于简单的处理器(流水线较少)而言,使用静态分支预测是最划算的方式,即使分支预测失败惩罚也不严重。

如果跳转出现跳转,不跳转,跳转,不跳转,等这样如此的循环,那么预测将会是全错的,所以静态分支预测不适合现代处理器。

动态分支预测:

动态分支预测主要是基于历史预测,根据前面的跳转指令的结果来预测下一次跳转指令是否要跳转,以及跳转地址。

由于每次的结果都是更新的,我们称它为动态分支预测。现代处理器基本使用动态分支预测,所以下面介绍常见的动态分支预测算法:

1bit预测器:

1bit预测器主要根据上一次的结果来做这一次的分支预测,因为只能根据上一次的结果(1bit) 所以这种方法直接不适用,故而诞生了2位饱和计数器。(其实只是为了引入2bit计数器)

2位饱和计数器:

2位饱和计数器是现代分支预测算法的基础,所以着重讲述2位饱和计数器的算法。

2位饱和计数器有4个状态,分别是:强跳转,弱跳转,强不跳转,弱不跳转。

如图所示:

强跳转:计数器饱和,分支预测本次会跳转

弱跳转:计数器不饱和,分支预测本次会跳转

弱不跳转:计数器不饱和,分支预测本次不跳转

强不跳转:计数器饱和,分支预测本次不跳转

饱和计数器初始状态是强不跳转(00),当出现连续三次不跳转才会处于强不跳转状态,反之也是如此。

所以该算法的核心是:在跳转和不跳转之间引入四个状态来细分预测状态,提高预测精度。

由两位饱和计数器衍生出的结构组成结构有很多,比如:

BHT预测:

分支历史表(branch history table) 简写为BHT,配合PC值的低n位索引,所以BHT需要有2^n  个表项才能够PC值索引。

BHT里面存储的是多条分支指令的历史执行结果,使用一个位向量或者一系列位来记录每个分支指令的历史,其中的每一个表项对应一条分支指令的历史执行结果(跳转或不跳转)。

对于每个分支指令,BHT中的对应位或者几位都会随时更新以反映最新的历史执行结果,这个更新来源于分支指令的执行结果反馈。

由于PC值的最低位没有任何意义,所以舍弃不要了。

如图所示:

可以看出BHT预测的是分支指令跳转或者不跳转,而不是预测地址。

两级分支预测器:(PHT)

两级分支预测器是基于局部历史的,所以我们也叫它:基于局部历史的分支预测器(其实上面的BHT也是局部历史)。

局部历史预测器很明显,只能基于以前局部的分支指令结果来做预测,因此局部历史记录多少限制了预测的准确性。

如图所示:

两级分支预测器由分支历史寄存器(branch history register,简称BHR) 和模式历史表(pattern history table ,简称PHT)组成。

PHT是一个记录分支历史跳转信息的表格,每个表项都可以用2位饱和计数器实现,里面存储着BHR每种数值对应的两位饱和计数器的值。

BHR是一个寄存器(准确的说是移位寄存器),里面记录了一条分支指令在过去的历史状态,即该指令前几次的执行结果(跳转还是不跳转)。

里面有n个bit ,每个bit 的数值为0 就是没有跳转,1就是代表跳转。

其结构如上图所示,可以看到它和BHT预测其实并没有多大的差别,无非就是把PC索引换成了BHR而已,然后再把BHT改个名。

分支目标缓冲器:(BTB)

分支目标缓冲器是由PC索引和分支目标缓冲器( branch target buffer ,简称BHB)实现的,其功能可以说是最为简单的。

如图所示:

BTB预测最大的问题在于多个分支指令共用一个表项的情况,这会造成分支干扰或者数据冒险,结构冒险等。

这是由于BTB内容是有限的,恰好有多条分支指令跳转的地址恰好相同,于是出现竞争冒险情况。

BTB预测的是地址,而不是跳转方向。

以上的的分支预测都是基于局部的分支历史来进行预测的,那么对应的就是基于全局历史进行预测的全局历史预测器。

基于全局历史的分支预测器:

除了记录自己这条指令的历史执行状况,还可以记录其他指令的历史情况来辅助判断,这种预测算法就叫做全局历史预测。

全局历史预测是局部历史的扩展,将局部历史扩展到全局,相应的我们需要一个GHR(global history branch)寄存器,用来记录所有分支指令的结果。

GHR预测器:

全局历史预测只是局部历史预测的扩展而已,相当于把BHR换成GHR而已,其内部存储的数据基本上是一样的,只是位宽更大。

如知乎图所示:

Gshare分支预测器:

两级分支预测器BHR在对PHT进行索引时,会存在严重的别名冲突(比如存在多个BHR或GHR组件的共用一个PHT时就会出现一个PHT里的值对应多个BHR的值或者GHR的值,这个时候就会出现别名冲突。)

所以我们需要引入一个更加精密的索引机制,哈希。

如图所示,通过预测分支的PC值与BHR的值先做一次哈希运算后,再把结果作为PHT的索引,其结果会更加准确。

然而这样也会发生别名冲突,所以缓解别名冲突的方法有:

  1. 增加BHR的长度,记录更多这条分支指令的历史状态
  2. 改进哈希函数
  3. 结合多种预测技术(全局历史,局部历史,两级预测器等)实现混合预测。

看到这里你需要理解的是:

        1. BHR记录的是某条特定分支指令的最近执行结果,通常是跳转,或者不跳转

        2. PHT记录的是该条分支指令执行结果映射到2位饱和计数器或着状态机表示的预测结果,也就是说,它里面存储的是预测状态(强跳转,弱跳转,弱不跳转,强不跳转)。

        3.可以认为BHR和PHT就是简单的针对同一条分支指令,但实际上它们可以支持多条分支指令,只需要增加更多的BHR 和PHT就好,没准还能实现并行预测。

混合预测:

使用BHT ,BHR,GHR,BTB等预测方式搭配起来实现混合预测,目的就在于提高精度。

借用知乎图来说就是:

可以看出混合预测就是将上述的预测器综合起来,不过这也没什么好说的。

感知机预测:

感知预测是现代分支预测器中的一种,主要是通过函数运算得到的,当跳转成线性变化时很有效,如果不是线性变化那么预测会变得很差。

感知预测是通过BHR或者GHR寄存器中的每一个bit 作为输入,然后通过加权求和得出结果,权重越大代表跳转概率越大,反之就是不跳转。

如知乎图所示:

需要注意的是,BHR 和GHR寄存器每一bit 输入不是按照原数据输入的,而是:

当前位为1(跳转) ,输入1 ;

当前位为0(不跳转),输入-1 ;

输出Y是一个点积,>0 预测为跳转, <0 预测为不跳转。

所以感知机预测通常只能预测是否要跳转,就是说:在当前BHR或GHR的值的输入基础上预测下一次是否要跳转,但是无法预测出跳转地址。

如果想要预测地址,需要更加复杂的模型,比如多层感知机或者神经网络,或者专门的地址预测器(分支目标缓冲器BTB,分支预测缓冲器BHB,两级分支预测器PHT,Gshare分支预测器等等)

此外感知机需要训练,类似于人工智能一样,更多信息还请参考其他书籍吧。

TAGE分支预测器:

TAGE 预测器主要应用于现代处理器中,其组成由基础预测器和多个TAGE(标签表)组成全局预测器。

使用同一分支指令的不同历史长度的GHR去索引PHT,从而得出每一段历史长度的跳转预测值,再把它们级联的输出,最后得出结果。

需要注意的是:

  1. tage预测器针对的同一分支指令的不同历史长度长度,也就是根据同一分支指令不同阶段下的跳转情况来预测的
  2. Tage 预测器输出的数据同样是是否跳转,而不是一个具体的跳转地址,这个前面的感知机的输出是类似的。
  3.  Tage 预测器输出是由命中的tag最长的那个TN表进行输出,不是由最后一个TN表才会输出。图中所示就不要理解为要在T4才会输出就行,如果命中了T3 ,而T4 没有命中,那么还是由T3输出。

配合上下文来看:

如图所示来看,T0是使用PC直接索引2位饱和计数器的表项;

T1 ~ TN都是使用PC和不同的全局分支历史长度进行哈希索引,索引的是表项中的tag。

内部解释:

  1. Pred: 3位符号饱和计数器,符号位代表是否要跳转,0代表不跳转,1代表跳转,这个其实就是在2位饱和计数器下多加了一位用于输出跳转信息罢了。
  2. Tag : 内部存储着分支指令过去的执行结果,这个PHT(模式历史表)或BHT(分支历史表)内部的信息差不多。
  3. U : 2位计数器,表示当前的tag 的有用程度,因为可能索引的时候一个也没索引到,没有索引到就没有命中。

返回地址堆栈(RAS):

对于函数调用和函数返回指令,虽然也可以使用BTB进行分支预测,但是这纯属于绕弯路多此一举,因为和函数有关的地址大多简单,使用堆栈处理更加高效快捷。

发生函数调用时,将函数调用的下一条指令的PC值压入堆栈,在函数返回时,直接从堆栈中弹出一个PC值作为返回地址的预测结果。

这才成对的函数调用返回下十分契合。

涉及入栈出栈的知识不做讲解,读者可以自行搜索。

总结:

指令

类型

是否预测

是否预测地址

分支预测组件

备注

Is_branch

条件跳转

Y

N

BHT 感知机,TAGE等

预测方向

Is_jump

无条件直接跳转

N

N

无需预测

Is_jalr

无条件间接跳转

N

Y

BTB

预测地址

Is_return

函数返回

N

Y

堆栈

出栈

Is_call

函数调用

N

N

堆栈

入栈

Y代表是 , N 代表否。

上述的分支预测中可以看出,很多预测组件只预测是否需要跳转,对地址预测我只简述了BTB组件。

你需要理解2比特饱和计数器,这是最基础的,是分支预测的关键,也是课题的基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江流月照

感谢客官打赏与支持。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值