本文主要是介绍Control-Flow Decoupling,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Control-Flow Decoupling
-
摘要
- 问题:论文在四个基准测试套件(spec2006,NU-MineBench3.0 BioBench,cBench-1.1)中发现,MPKI中的三分之一的指令是可分离分支。可分离分支是论文提出的一个概念,表示那些分支的控制相关区域很大(不适合if-conversion转换),并且这些分支的向后切片代码(backward slice)不依赖于其控制相关指令或者具有短暂的依赖关系
- 解决:论文提出了控制流解耦和(control flow decoupling)的方法消除可分离分支的错误预测
- 思想:将包含分支的循环分离为两个循环,第一个循环只包含分支的谓词计算,第二个循环包含分支和与该分支有控制相关的指令。第一个循环通过微结构上的队列将分支结果传递给第二个循环
- CFD的循环转换可以由于程序员或者编译器控制
- 结果:在类似Intel的sandy bridge core的微架构上,CFD可以提高43%的性能,能耗降低41%
-
介绍:
-
论文比较了一个完美的分支预测器和一个当时最新的分支预测器(ISL-TAGE)之间的性能和功耗对比
-
可分离分支的两个特点
- 这种分支的控制相关区域非常大,不适合使用if-conversion的方法进行转换
- 这种分支不依赖于本身的控制相关指令(由循环携带的数据相关带来的相关)(完全可分离分支),或者只依赖于它的控制相关指令的一个短的循环携带的相关(部分可分离分支)
-
对于完全可分离的分支,分支的谓词计算完全独立于该分支及其控制相关区域,因此可以先生成谓词向量,然后使用该向量驱动取值或者跳过控制相关的区域的连续动态实例
-
对于部分可分离分支:分支的断言计算依赖于一些分支的控制相关指令,即在计算断言的循环中需要将这些控制相关的分支和该分支本身拷贝一份。这种拷贝可以最终转换为if-conversion的形式,因此此时控制相关的指令已经非常的少,可以进行断言转换
-
-
控制流分类:四类
- Hammock(吊床):只有很小并且简单的控制相关区域,可以使用if-conversion进行转换。(可能会增加store指令的数量)
- Separable(分离的):具有很大并且复杂的控制相关区域,但是分支的后向切片(谓词计算)和分支指令以及其控制相关的指令可以完全分离或者部分分离
- inseparable(不可分离的):具有很大并且复杂的控制相关区域,但是分支的向后切片(谓词计算)包含了太多分支的控制相关指令。这种情况下,分离分支的谓词计算不会产生好处
- Not Analyzed(未分析的):对整体的分支错误预测之后很小的贡献的分支
-
控制流解耦和示例
- 图a是一个在循环中的完全可分离的分支。分支切片(branch slice)用于计算分支的谓词。分支根据谓词计算的结果决定是否执行之后的指令。当前示例中,分支的控制相关之后都不在其后向切片中(下一次的谓词计算切片),即在和分支相关的指令和分支之间不存在循环携带的数据相关性。(部分可分离分支则是一小部分的控制相关指令在分支切片中,即有一条从控制相关指令指向分支切片的后向边)
- 图b则是利用CFD转换之后的循环。此时循环变成两个循环,循环的判断条件相同。第一个循环只包括分支切片,并且将断言的计算结果压入BQ(branch queue),压入操作使用新的指令Push_BQ。第二个循环包括控制相关指令,使用另一个新的指令Branch_on_BQ,将断言结果从BQ中弹出,然后用于分支判断
- 对于部分可分离分支,转换之后的第一个循环中不仅包括分支切片和Push_BQ指令,还包括分支指令以及一些必须的控制相关指令。分支和控制相关指令将会利用条件move指令,转换为if-conversion的形式
-
CFD的ISA支持
- 分支队列BQ(branch queue)的体系结构说明
- BQ有一个特定的大小,并且对软件有一定的影响
- 每个BQ表项包含一个标志位,用于指示taken/not taken。同时表项中也会包含一些其它的体系结构状态,但是这些对软件不可见,ISA中也没有指定
- 使用一个长度寄存器指示当前BQ的占用情况,软件只能够看到这个寄存器的值
- ISA提供了将BQ状态(队列内容和长度寄存器)保存和恢复到内存的机制,从而保证BQ也可以在上下文切换时可用(论文推荐使用专用的寄存器完成这个任务)
- Push_BQ指令:有一个源寄存器号(也是通用寄存器),如果寄存器内容为非零,则将1压入队列,否则压入1
- Branch_on_BQ:一条新的分支指令,也通过PC相对偏移得到目标地址,但是没有显示的源寄存器要求。执行时该指令会从BQ中弹出谓词,确定是否跳转
- ISA要求软件必须遵守push和pop的使用规则:
- push必须在pop之前
- 连续的N次push之后,必须按照压栈的顺序,连续的进行N次pop
- N不能够超过BQ的大小
- 分支队列BQ(branch queue)的体系结构说明
-
CFD的软件支持
- ISA中为了支持CFD要求循环的次数不能够超过BQ的大小。如果超过会影响性能,因为BQ在溢出之后需要保存到内存中,因此会降低性能
- 解决:将原本的循环转换为两层嵌套循环,保证内层的循环次数不超过BQ的大小。然后再对内层循环进行CFD转换
-
CFD的硬件支持
- BQ使用循环缓冲区实现,每个BQ表项包括的微结构状态:push位,pop位和检查点id
- 提前push(early push)
- 当push指令被取值时,会在BQ的尾部分配一个表项,此时push位和pop位都被清零。并且push指令会记录分配在BQ中的表项位置(索引)
- 当push指令最终被执行时,检查pop位,如果仍旧为0,意味着pop操作尚未执行,此时将断言的结果写入BQ表项中,并且设置push位
- 当遇到pop指令时,检查当前对应的BQ中的表项的push位,如果为1,则使用表项的结果进行判断
- Late push(延后push):pop指令在push指令执行之前取值
- pop指令取值时,检查对应的BQ表项中的push位,发现仍旧为0,意味着表项中没有断言计算的结果
- 两种解决方法:暂停取值,直到push完成执行;使用分支预测器进行分支预测
- 论文使用第二种解决方案,称之为推测pop。当推测pop指令到达重命名阶段时,将使用检查点保存状态,并且会将预测的结果和检查点id写入对应的BQ表项,并且设置pop位。等待push操作完成之后判断是否需要进行恢复操作
- 论文发现,在经验中,延迟push非常少见,因为在软件中会使得pop和push之间很多间隔指令
- BQ长度(占用率):使用两个组件的和表示
- net_push_ctr:表示push和pop操作个数之差。当发生push指令提交时,该计数器增加,当pop指令提交时,计数器减少
- pending_push_ctr:在指令窗口中push指令的个数(已经取值但是尚未提交的push的个数)。当push被取值时,计数器增加,当push提交时,计数器减少
- 如果BQ长度等于BQ大小,并且取到了push指令,此时取值单元必须停止
- BQ的恢复(recovery)
- 为错误分支预测恢复的准备:每个分支检查点都增加了将BQ恢复到程序执行中的该检查点所需要的状态,即需要对BQ的头指针和尾指针进行快照
- 为异常恢复的准备:需要维护提交的BQ的头尾指针版本
- 当出现回滚时,BQ头尾指针将从引用的检查点或者提交的版本中恢复,并且清除恢复的头尾之间所有的pop位。pending_push_ctr需要根据尾指针的变化情况进行减少
这篇关于Control-Flow Decoupling的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!