现代处理器设计-超标量处理器基础
讲解现代处理器设计,比较老的书
处理器设计
先介绍了处理器发展史。
指令级处理器设计的关键是指令集体系结构(ISA),定义了指令级处理器必须要实现的功能,软件开发者和编译器的参考,也是处理器设计者的规范。
体系结构->逻辑实现->物理实现
体系结构就是 ISA,处理器的功能性行为,处理器上执行的软件全部都要根据 ISA 进行编码,将程序发展和硬件发展独立并成为处理器设计规范。
逻辑实现,微结构,ISA 的具体逻辑实现,包括流水线设计、cache 存储器等。
物理实现是设计的具体物理表现形式,对于微处理器而言,具体的物理表现形式通常是单芯片或多芯片的封装。一个逻辑实现可以对应多种物理实现。
动态-静态接口(DSI,Dynamic-Static Interface)
ISA中有内在的接口定义,用于区别哪些是在编译时静态完成,哪些是在运行时动态完成,这个接口就是DSI。
将 ISA 作为软件与硬件之间的约定所产生的直接结果。在编译时由软件和编译器静态完成的任务和优化被认为是在 DSI 之上的,运行时由硬件动态完成的任务以及优化则被认为是在 DSI 之下的。
理想化的情况是,体系结构或者 ISA 应该只包含表达功能或者软件算法语义所必需的特征,而不管那些用于优化程序性能的所有特征应该归入实现还是归入微体系结构领域。
现代处理器中微结构在微处理器性能中居于支配地位。
性能公式
公式中右侧的三项为:
- 指令数,特定程序需要执行的动态指令数目
- CPI,平均执行一条指令花费的周期数
- 机器的时钟周期时间,时钟频率的倒数
减少公式中三项可以提高处理器性能
- 减少指令数
RISC ISA 上程序数目可能是 CISC ISA 上的两倍,虽然指令数量多但是执行部件简单,时钟周期短
编译器可以展开循环但是静态代码增加会影响 Cache 命中率,函数调用消除同理。 - 减少 CPI
采用 RISC 的一个关键动机就是减少了指令复杂性,从而减少每条指令的周期数目。
如果使用深度流水线能避免增加时钟周期但预测错误的 CPI 增加。 - 时钟周期时间
信号传播延迟决定时钟频率。
指令级并行
采用流水线处理器多条指令重叠可以将 CPI 降低到接近 1,标量流水线处理器的限制就是每个周期内最多只能发射一条指令。
IPC 大于 1 的处理器成为超标量处理器。
平均 IPC 反映了处理器达到的平均指令吞吐率,它是衡量微体系结构效率的一个关键参数。
并行效率
N 个处理器的总利用率
N 变大时机器在向量上花费时间越来越少,进而效率接近于 0,所有时间用于标量计算。
处理器数目增加时,并行处理器效率下降非常快。
流水线处理器性能
执行过程分为三个阶段,首先是流水线填充阶段, 在这个阶段,开始的 N 条指令进入流水线。第二个阶段是完全流水阶段,流水线完全充满,代表流水线的稳定阶段。这里有一个前提,即假设流水过程中没有中断,这代表了理想的执行过程。第三个阶段是流水线排空阶段,在这一阶段没有新的指令进入流水线. 流水线继续处理停留在流水线中的指令。
实际流水线的执行图与理想情况不同,必须考虑停顿周期,实际的流水线性能会由一小部分的停顿周期大幅下降。
超标量方案
设计超标量处理器的一个主要动机就是开发可以获得一定(相对于向量来说较低)级别的并行度的通用处理器。目的是确保大部分的程序都能获得一定程度的指令级并行,以减轻顺序执行时瓶颈所产生的影响。当然,高度向量化的程序将会通过并行而持续获得较好的加速比。
指令级并行的极限
Flynn 瓶颈:大多数程序的 ILP 小于 2.
Fisher 的乐观估计:许多程序中几乎拥有无限的 ILP。
指令级并行的机器
标量流水线处理器作为基准处理器,通用四级流水线,分别是:
- IF
- DE
- EX
- WB
讨论 ILP 处理器的性能或加速比时,将使用这个基准处理器作为参考。相对于不能将多条指令的处理重叠起来的串行非流水处理器,流水线处理器可以获得一定的加速比,这种形式的加速比限制在标量处理器领域内的比较上,其重点是相对于(标量的)非流水线处理器,在(标量的)流水线处理器中可以获得吞吐率的提高。
超流水处理器
相对基准处理器有更高的流水度。
处理器时钟周期比基准处理器短,一个基准时钟周期里有多个次基准周期。
超流水处理器的流水度已经超过了简单指令的操作延迟所决定的流水度。实际上超流水处理器将执行段进一步分成多个流水段。一个“流水化程度不够”的处理器不能以指令的执行速度来发射指令。从另一个方面来说,超流水处理器发射指令的速度比执行的速度还要快。
R4000 相比 4 段基准流水线获得潜在加速比为 2.
超标量处理器
发射并行,与标量流水线处理器相比每个周期内可以同时发射指令数更多。
超长指令字处理器
与超标量处理器类似,主要区别在于 DSI 位置,不需要赋值 IF 和 DE 段来同时对 n 条指令同时取指和译码。
质量发射的决策在编译时进行,编译器决定哪 n 条指令被同时发射到执行段,并将这 n 条指令作为一个超长指令字存放在程序存储器中。
小结
任何 ISA 的不足都可以通过微体系结构技术来克服,并且随着可移植字节码和 JIT 编译出现,ISA 的含义以及动态静态界面的位置将变得更加模糊。
流水线处理器
主要有两种流水线:算数流水线和指令流水线。书中重点是指令流水线。
将系统分割成很多段,适当增加缓冲,吞吐率大大提高。
流水线段数的局限性,有两个因素限制了时钟频率,一个是组合逻辑的最长和最短传输延迟之差,另一个是为正确建立时钟信号所需要的额外延迟。
算数流水线实例:一个浮点乘法器
非流水的浮点乘法器
总共需要175个芯片,时钟周期400ns,频率2.5MHz。
流水的浮点乘法器
流水化后考虑缓存中间结果用的寄存器后,时钟周期最小为172ns,频率达到5.8MHz。
唯一需要增加的硬件是边沿触发寄存器,用于缓存流水线级之间的结果,在175个芯片的基础上增加了82片。
硬件复杂度增加了45%但是性能提高了130%。
理想流水线假设
- 一致的运算分量:要完成的整个运算量可以均匀地分程延迟一致的若干分量
运算量分开时不考虑无效时间的引入,缓冲的引入以及时钟没有带来额外的延迟
要保持流水线均衡减少内部碎片 - 重复的运算:输入数据有大量相同的,重复的运算
外部碎片 - 独立的运算:所有相同的重复运算之间没有相关性
运算不相关
流水线处理器设计
- 一致的运算分量=>保持流水段均衡
- 重复的运算=>统一指令类型
- 独立的运算=>尽量减少流水线停顿
深流水线处理器
流水线的深度存在下线,对于深流水线环节流水线相关的开销更大。
对于一次错误预测的分支前端流水线中所有的指令都要被清掉,减少分支开销的第一个方法是,减少前端水线的段数。第二个方法是将前端流水线的一部分移至后端。
小结
流水线处理器性能的主要障碍是指令相关引起的流水线停顿。
超标量结构
标量流水局限性
- 标量流水线最大的吞吐率不会超过每周期一条指令。
- 将不同类型的指令放在一条流水线中处理,效率低下。
- 为了保证流水线的步调一致而插入的停顿使流水线产生很多气泡
从标量流水线到超标量流水线
消除了标量流水线的限制,属于并行流水线。
并行流水线
两种实现可以堪称机器的时间并行和空间并行。
并行流水线是二者的结合。
实现并行流水线需要增加大量的硬件资源,指令缓冲区之间采用 S×S 的交叉楷固安互联,电路开销达到 O(s^2)量级,此外寄存器堆的读写端口也要增加为 s 倍,指令 cache 和数据 cache 同理。
多配置流水线
不同类型的指令执行所需硬件资源不同,标量流水线中所有指令延迟相等都等于流水线长度,带来了不必要的停顿。
每条流水线只执行一种指令,因此可以根据其特点进行专门优化。比配置 s 条相同的标量流水线高效地多。
动态流水线
段间缓冲是必须的。标量处理器采用单记录缓冲。
并行流水线相邻段间则使用多记录缓冲。
图(b)中的多记录缓冲只有一个统一的读端口和统一的写端口,各条记录之间没有互联。
超标量流水线同标量流水线区别是超标量使用复杂的多记录缓冲存放正在执行的指令,并行流水线中为了最大程度地减少不必要指令停顿,后续指令必须能够绕过停顿的前导指令。
按照程序原始顺序载入译码的指令,然后按不同的顺序分派到各个功能部件,输入顺序输出乱序。
指令乱序流入,但是要保证程序原始顺序,指令的提交也必须是顺序的。
超标量流水线综述
以 TEM 流水线为模板来讨论,仅表示逻辑上的流水线,在物理上的实现不是一一对应的。
六级流水线指的是取指(Fetch)、译码(Decode)、分派(Dispatch)、执行(Execution)、完成(Complete)和提交(Retire)。执行段包括多个不同类型的流水话功能部件,而且各个功能部件完成的延迟各不相同。
取指
超标量是并行流水线,每周期可以从指令 cache 中取出多条指令,流水线宽度为 s 就可以从指令 cache 中取出 s 条指令。
取指吞吐率主要有两个障碍:读取的 s 条指令没有对齐,和指令 cache 的物理组织有关;控制流改变了取指集中的指令。
对齐问题解决有两种方案:
- 编译器静态技术
编译器了解指令 cache 的组织结构,将指令合理地放置在存储器中。 - 执行时硬件协助解决
即使指令组跨越了阵列边界,对齐硬件也能保证一个周期内取出 s 条指令
指令译码
指令译码堆从 cache 中取出但没有分派到功能部件的指令进行译码,包括指令的识别、指令类型确定以及指令间相关性检测。
译码复杂度受两个因素影响:ISA 和并行流水线宽度。
RISC 流水线译码操作非常简单,CISC 译码操作非常复杂,一般需要多级流水段实现。
CISC 指令长度不确定导致了译码周期的不定,一条指令的长度确定了以后才能进行下一条指令的译码,因此多条指令并行译码不易实现。最坏情况下,由于下一条指令可能在所取指令序列的任意一个字节开始,因此需要设置大量的译码器同时译码这些可能的指令。
还有另一个难点是译码器必须将指令转换成内部更低一级的操作,才可以被硬件直接执行。
这些内部操作和 RISC 指令相似可以看作一串微指令。
预译码技术,将指令译码的部分工作转移到指令 cache 中进行,当 cache 失效并需要从存储器调入一个 cahce 块时,内存与 cache 之间增加一个硬件将 cache 块中的硬件进行预译码。
主要有两种影响
- 是由于在存储器到指令 cache 的通路上增加了预译码操作而增加了指令 cache 的失效开销,不过当 cache 失效率很小时影响不大。
- 指令 cache 的大小由于存储预译码标识位而增大。
因此,是否使用预译码技术需要对指令 cache 的容量和预译码的程度之间采取一种折中方案。
预译码技术不单单可以用在 CISC 并行流水线中来消除 CISC 指令译码时的时间瓶颈,它还可以用来改善 RISC 并行流水线的性能。对 RISC 指令在载人指令 cache 前进行预译码,译码信息可用来确定分支指令的分支方向以及对当前指令组中不相关的指令进行预先分组。
指令分派
指令在超标量流水线中必须经过分派才能执行。
标量流水线中所有类型的指令均在同一条流水线中执行因此不存在分派阶段。超标量属于多配置流水线,执行段使用了很多不同类型的执行部件,不同类型的指令要在不同类型的流水线执行。指令的类型在译码段一旦确定, 指令就必须被发射到相应的部件执行。
在指令译码与执行之间,还需要对指令进行临时的缓冲,因为在执行之前所有指令都必须保证操作数是可用的。在译码阶段从寄存器文件中读取操作数,但是在超标量流水线中,由于前导指令还没有完成对寄存器的更新,所以当前指令的某些操作数可能没有准备好。这种情况下,最简单的解决方法就是停止译码段的继续执行,直到所有操作数就绪,但是这种方法对译码段的吞吐率的影响很大,因此是不可取的。更好的解决方法是,不能立即执行的指令把已经就绪的操作数读出并放入一个单独的缓冲中,并在此等待仍没有就绪的操作数。临时缓冲称为保留站。
保留站有两种实现方式
- 分派段前端使用一个统一的缓冲,则称为集中保留站
- 在分派段后端使用多个缓冲,称为分布保留站
“分派”是指译码后指令同相应类型的功能部件之间的“连接”;而“发射”是指指令在功能部件中执行的初始化。
两个事件不是同时的但是不可分。
指令执行
指令执行段是超标址流水线的核心,当前超标量设计的趋势是向着大规模并行和多条流水线的方向发展。
目前的超标量处理器一般都有多个整数部件,甚全多个浮点部件,这是两种最基本的部件类型,部件复杂但是效率很高。每周期可以执行多条指令,(a)图显示了TI SuperSPARC的整数执行部件,采用了级联的ALU部件。3个ALU操作跨越2级流水线,每周期可以处理两个整数操作,两操作不相关的话ALU2和ALU0可以同时执行,如果存在相关则第二条指令在ALUC执行。这样一种功能部件可以在更多的时钟周期内实现双发射。
IBM RS/6000 中的浮点部件是使用一个两级流水的MAF(Multiply-Add-Fused)乘-加部件来实现的。使浮点指令的吞吐率达到每周期两条指令。
整数部件除了执行整数ALU之外,还用来计算存储器地址、处理分支以及load/store指令。
一些设计中出现了单独的分支部件以及load/store部件。分支部件主要是修改PC,load/store则是直接和数据cache相连。其他一些专用部件诸如图像处理部件也相继出现。
对于许多信号处理和多媒体应用,常见数据类型是字节,多数情况下4个字节打包在一个32位字中处理的,因此需要设置专门的32位功能部件来提高吞吐率。
一般处理器都只有一个load/store部件,但在某些限制条件满足的情况下,每周期可以处理两条load/store指令。现然load/store部件的配置太少,原因是设计能够同时被多个load/store部件访问的数据cache很困难。多端口数据cache的电路设计十分复杂,而且会导致访存速度严重降低。
执行段资源的并行性由空间并行性和时间并行性共同决定的,设置多个功能部件是一种空间并行性的体现方式,同样的并行程度可以通过功能部件流水化实行按,这是时间并行性的一种体现方式。例如:cache不能实现双端口的话可以将cache分为两级流水,也可以同时处理两条load/store。
为了避免结构相关,功能部件的数量往往大于并行流水线的宽度。
指令完成和提交
指令完成意味着指令执行结束并修改了机器状态,指令结束是指指令离开功能部件并进入完成缓冲。接下来离开缓冲整条指令完成。
书中,“完成”是指更新机器状态,而“提交”是指更新存储器状态。对于不更新存储器的指令,完成的同时也就提交了指令。因此,在分布保留站中,指令经过了以下阶段:
- 取指
- 译码
- 分派
- 发射
- 执行
- 结束
- 完成
- 提交
其中发射和结束分别指指令开始执行和指令结束执行。某些超标量处理器提供商在使用这些术语时存在着细微的不同,“发射”和“分派”、“完成”和“提交”经常混用,有时“完成”用来表示执行结束,而“提交”表示更新机器状态并且没有固定的标准。
中断和异常经常会打断程序的执行。动态流水线的超标量处理器由于指令存在乱序执行,所以必须能够正确地对中断和异常进行处理。
异步发生并且必须挂起交给操作系统处理中断,异常通常由程序自身指令的执行而引起。
动态流水线中,指令将顺序取指并译码,但是以乱序的方式执行,也就是进入保留站时是顺序的离开保留站时是乱序的,结束时也相应是乱序。但是为了支持精确异常指令完成时也是顺序的,即堆机器状态的更新是顺序的,因此并行流水线完成段需要设置一个再定序缓冲。
指令完成段用再定序缓冲来处理精确中断。发生异常时,当前指令在再定序缓冲中标识出异常指令。完成段按顺序检查每条指令是否可以完成,当发现一条带标记的指令时,则不允许其完成,但所有之前的指令都可以完成,同时,应标记该条指令为检查点并保存机器状态。机器状态包括所有体系结构寄存器以及程序指针。流水线中的其他指令即使已经执行结束,也必须使之失效。异常处理完毕后,需要恢复检查点的机器状态并取出发生异常的那条指令,从而使程序重新开始执行。
小结
上图给出了一个当前超标量流水线的基本结构,前端是顺序执行,执行段是乱序执行,但后端是顺序提交。前端和后端流水段每周期都能处理多条指令。由于等待操作数就绪,指令可能在保留站中停留多个时钟周期,一旦操作数就绪,指令就从保留站发射到相应部件加以执行。执行结束后,指令进入再定序缓冲(完成缓冲),然后按照程序原始顺序完成并提交。再定序缓冲一般是按照指令原始顺序组织的循环队列。
本章主要介绍的是超标量流水线的组织结构以及各个流水段相关的问题。到此为止,我们已经讨论了超标量流水线的静态结构,在第4章中将讨论超标量流水线的动态行为。本章从一个较高的层次阐述了超标量流水线的组织结构并省略了实现上的细节,主要是为从标量流水线到超标量流水线实现一种过渡。
超标量技术
超标量流水线涉及的最终目标是得到最大的指令吞吐率。
重点是超标量流水线的同台行为,以及针对某些特殊指令的处理技术。
三条流通路:
- 指令流:分支指令处理
- 寄存器数据流:ALU指令处理
- load/store 指令处理器:load/store 指令处理
指令流
一般用在超标量流水线的前端,即取指段和译码段。
前端的吞吐率就是整条流水线吞吐率的上线。
控制流语义可以用控制流图(CFG)表示,CFG中基本块以及其中的指令必须顺序地保存在存储器中,因此偏序关系的基本块必须在存储器中以全序方式存储。在将CFG中映射为连续的存储位置时,必须加入无条件分支指令.
流水线机器只有在流水模式(sreming moe)下才能达到最大的吞吐率。
分支对流水的影响
处理条件分支的延时将导致取指段有3个周期的停顿,对应分支指令的译码、分派、执行三个流水段。
分支预测技术,减少分支开销.
分支目标地址的推测可以通过设置分支目标缓冲BTB ( Branch Target Buffer )来实现。
保存前几次分支执行的目标地址,是一个较小的cache存储器并在取指时使用PC访问.
记录分支地址和分支目标地址,如果跳转的话后续使用新的pc值位置的地址.
寄存器数据流技术
指ALU指令在寄存器执行部件中的有效执行。
寄存器复用和假数据相关
因为寄存器硬件资源有限,寄存器分配工具需要将无线的寄存器符号资源映射到有限的、固定的体系结构寄存器上。
定义和最后一次时钟之间称作活跃区间,区间内最后一次使用完毕后就可以被赋值。
处理假数据相关的一种更有效的方法是为同一体系结构寄存器中的多个定义动态分配不同的名字,称为寄存器重命名(register rename)。寄存器重命名需要硬件的支持并可以执行时撤销寄存器重用,恢复所有当前指令的值与寄存器之间的一一对应关系。
数据相关和数据流极限
两条指令间的写后读成为数据真相关。
关键路径是存在相关指令的最长延时和,所有的寄存器数据流技术就是为了笔记数据流极限。
Tomasulo算法
动态执行内核
Tomasulo算法的实现,使指令在执行时接近数据流极限,包含分派(寄存器重命名 保留站 再定序缓冲)、执行、完成三部分。
- 本文作者: Zheng Yuchen
- 本文链接: https://zycccccc.top/2022/01/07/读书笔记/现代处理器设计/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!