计算机体系结构-体系结构基础与流水线原理

news2024/11/25 4:37:02

计算机体系结构:体系结构基础与流水线原理

​ 计算机体系结构:量化设计与分析一书以RISC-V为例介绍计算机体系结构。本文为第一部分,介绍体系结构的基本知识和流水线原理。笔记内容为原书的第一章,附录A、B、C。

第一章 量化设计与分析基础

​ 第一章主要介绍关于体系结构的基础知识,最为重要的是关于体系结构的相关定义(指令集体系结构)的内容(1.3节),主要位于附录A;其他内容(1.1-1.2&1…4-1.8节)包括计算机的分类,技术趋势,成本趋势,功耗等,只需要有大概的认知和了解;最后的1.9节介绍了计算机设计的量化原理,给出了三个设计计算机时的指导原则。其中相对不重要的部分省略了。

1.3 体系结构的定义

​ 狭义的计算机体系结构仅包括指令集设计,但体系结构要解决的问题已经远超出指令集设计的范围了,因此,本书介绍的体系结构包括:指令集体系结构,微体系结构(存储器,内部处理器等组成),硬件实现

​ 其中的指令集体系结构,在附录A中详细介绍。

1.4技术趋势

​ 过去的计算机设计技术随着集成电路逻辑技术,半导体技术,磁盘技术等的快速发展而迅猛提高。然而现在随着摩尔定律的失效,技术提升的速度已经放缓了。仅关注性能方面的趋势,最大的特点是:带宽的改进远大于延迟的改进,经验表明带宽的增长速度至少是延迟改进速度的平方。

在这里插入图片描述

1.9计算机设计的量化原理

  • 充分利用并行:指令并行,线程并行,数据并行,电路并行,任务并行等。
  • 局部性原理:时间局部性/空间局部性原理
  • 重点关注常见情形:从常见情形提高计算机的工作效率

​ 1.9还介绍了一个重要的定律,用于计算改进计算机的一部分而获得的性能增益,即Amdahl定律。Amdahl定义了加速比:
加速比 = 原执行时间 采用改进后的执行时间 加速比 = \frac{原执行时间}{采用改进后的执行时间} 加速比=采用改进后的执行时间原执行时间
​ 假设改进的比例称为升级比例,改进的部分的升级加速比已知,则整体的执行时间为:
新执行时间 = 原执行时间 × [ ( 1 − 升级比例 ) + 升级比例 升级加速比 ] 新执行时间 = 原执行时间 \times [(1-升级比例)+\frac{升级比例}{升级加速比}] 新执行时间=原执行时间×[(1升级比例)+升级加速比升级比例]
​ 从而可计算总加速比为:
总加速比 = 原执行时间 新执行时间 = 1 ( 1 − 升级比例 ) + 升级比例 升级加速比 总加速比 = \frac{原执行时间}{新执行时间}=\frac{1}{(1-升级比例)+\frac{升级比例}{升级加速比}} 总加速比=新执行时间原执行时间=(1升级比例)+升级加速比升级比例1
​ 除此外还介绍了一些衡量性能的指标,例如CPI(每条指令时钟周期数),时钟频率,响应时间,带宽/延迟等:

  • 响应时间 = 任务开始到任务完成的时间 = CPU TIME + WAITING TIME,用CPU性能衡量CPU执行时间
  • C P U 时间 = 程序的 C P U 时钟周期数 × 时钟周期时间 = C P I × 指令数 × 时钟周期时间 CPU时间 = 程序的CPU时钟周期数\times时钟周期时间 = CPI\times指令数\times时钟周期时间 CPU时间=程序的CPU时钟周期数×时钟周期时间=CPI×指令数×时钟周期时间

附录A 指令集基本原理

1.指令集体系结构的分类

指令集体系结构的区别在于处理器中内部存储类型的不同。共有三种体系结构:栈体系结构,累加器体系结构,通用寄存器体系结构。其中,栈和累加器式的体系结构都使用隐式的操作数,而通用寄存器使用显式的操作数,或者为寄存器,或者为存储器位置。

在这里插入图片描述

​ 通用寄存器体系结构又可以分为两类,一类可使用任意指令来访问存储器,称为寄存器-存储器体系结构,另一类只能用载入和存储指令来访问存储器,称为载入-存储体系结构。第三类将所有操作数保存在存储器中,还没有出现在今天的计算机中,称为存储器-存储器体系结构。寄存器-存储器体系结构可以使用较少的指令,但指令的实现较为复杂;而载入-存储体系结构需要使用更多的指令,实现较为简单。

​ 现有的计算机都使用通用寄存器体系结构,因为寄存器比存储器更快,且对于编译器来说,使用寄存器效率更高,这是因为寄存器可用于保存变量,可以降低存储器通信流量,加快程序速度。

*2.存储器寻址

解释存储器地址

​ 通常在指令集中都是字节寻址的,存储器地址访问到的是一个字节,指令集提供对字节,半字,和字的访问方式,大多数计算机还提供对双字的访问。

​ 一个大于一个字节的数据在存储器中的存放方式有两种,分别为:

  • 小端法:低位在低地址
  • 大端法:高位在低地址

​ 现代计算机通常支持双端,可以配置为任意一种顺序。

​ 在许多计算机中,对于大于一个字节的存储器寻址都必须是对齐的。因为存储器通常与一个字或双字的倍数对齐,读写更快,如果使用非对齐寻址则会增加硬件的复杂性,并且非对齐寻址可能需要多个对齐的存储器引用。

寻址方式

​ 常用的寻址方式包括寄存器间接寻址,立即数寻址,偏移量寻址等。

​ 一种体系结构至少支持以上提到的三种寻址方式,并且根据统计数据,偏移量寻址方式中的地址大小至少为12-16位,立即数寻址中立即数字段的大小至少为8-16位,就能满足大多数情况下的使用需求。

在这里插入图片描述

*3.操作数的类型与大小

​ 操作数的常见类型包括字符,半字,字,单精度浮点和双精度浮点。整数通常用二进制补码表示,字符通常使用ASCII码表示,浮点数都采用IEEE标准。

*4.指令集操作

​ 基本所有的指令集体系结构都至少支持以下几种操作:

  • 算数与逻辑:数的运算与逻辑运算
  • 数据传送:载入-存储(move指令)
  • 控制:分支,跳转,过程调用与返回,陷阱
  • 系统:操作系统调用

5.控制流指令

​ 关于改变控制流的指令,可以分为四类:

  • 条件分支(有条件的跳转)
  • 跳转
  • 过程调用
  • 过程返回

​ 根据统计,在计算机中条件分支出现的频率是最高的。

控制流寻址

​ 控制流寻址常见的一种方式是采用PC相对寻址,还有寄存器间接跳转动态寻址。分支常用PC相对寻址来指定目标,从下图可以看出,分支位移量至少为8位就可以满足大多数情况。

在这里插入图片描述

​ 寄存器间接跳转寻址通常出现于以下四种情况:

  • case/switch
  • 虚拟函数或虚拟方法
  • 高级函数或函数指针
  • 动态共享库

条件分支选项

​ 条件分支的实现技术主要有以下三种:

  • 条件代码(80x86):测试ALU运算设定的特殊位
  • 条件寄存器(MIPS):使用寄存器保存比较结果,实现简单
  • 比较与分支

过程调用选项

​ 在过程调用和返回时,需要进行一些状态保存,至少包括返回地址和ebp,esp等指针的保存,而保存寄存器则分为两种:由调用者进行保存;由被调用者保存。大多数实际系统都采用这两种机制的组合方式,根据一些确定的基本规则,将一些寄存器由调用者保存,而另一些则由被调用者保存。

6.指令集编码

​ 指令的编码要说明指令的操作和操作数,此外,还必须能够得到操作数的寻址方式。对于简单的载入-存储计算机,寻址方式可以编码到操作码之中,而对于有多种寻址方式的计算机,通常为每个操作数添加一个地址标识符说明寻址方式。对指令集进行编码时,架构师必须平衡以下几个方面:

  • 允许尽可能多的寄存器和寻址方式
  • 寄存器字段和寻址方式字段的大小对平均指令大小存在影响
  • 编码后的指令长度应易于以流水线方式处理

​ 以下是三种常见的指令集编码方式:

在这里插入图片描述

​ 变长编码适用于寻址方式和操作较多时,定长编码适用于寻址方式与操作数较少的情况,但牺牲了平均代码规模。两种编码方式之间的权衡是代码规模与处理器译码的难易程度(性能)。第三种选择就是提供多种指令长度,缩小代码尺寸,这对于嵌入式应用程序来说很重要。一些RISC指令集版本同时提供16位和32位的指令,从而压缩代码规模。

7.编译器(-)

​ 机器执行的指令都是由编译器生成的,因此在设计和实现指令集时,需要考虑编译器技术,尽可能降低编译器生成良好代码的难度。目前编译器的结构大致如下:

在这里插入图片描述

​ 编译器的首要目标是正确性,其次是编译后的代码速度,这取决于对代码的优化程度。现代编译器的优化可以分类为:

  • 高级优化:直接对源代码进行
  • 本地优化:对基本块内的代码进行优化
  • 全局优化:将本地优化扩展到分支范围之外,并引入对循环的优化
  • 寄存器分配:图着色算法
  • 处理器相关的优化

​ 不同优化的相对使用频率:

在这里插入图片描述

​ 在设计指令集架构时,通过以下特性为编译器编写人员提供帮助:

  • 提供正交性:操作,数据类型和寻址方式应当是正交的。(两个方面应该互不影响)
  • 提供原型而非解决方案
  • 简化候选项之间的平衡
  • 提供一些指令,将编译时的已知量绑定为常量

​ 综上,设计一个新的指令集体系结构总是希望满足以下三点:

  • 至少有16个通用寄存器,以简化寄存器分配
  • 保证正交性,全部寻址方式适用于所有传送数据的指令
  • 注重简单性

8.RISC V

​ RISC V的设计如下:

  • 寄存器组:32个通用寄存器(GPR),一组浮点寄存器
  • 数据类型:字节,半字,字,双字,浮点
  • 寻址方式:立即数寻址,偏移寻址,寄存器间接寻址
  • 指令格式:32位指令,7位主操作码
  • 操作:载入与存储,ALU运算,分支与跳转,浮点数运算
  • 控制流指令:通过跳转指令和分支指令处理控制流转移,分支条件由指令指定

​ 指令格式分为以下几种:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZT8zsXbq-1681740208430)(计算机体系结构-体系结构基础与流水线原理/image-20230415231042887.png)]

​ R型是寄存器-寄存器指令,主要是运算类的指令;I型是立即数指令,包括涉及立即数的运算和Load指令;S型指令(以及SB型)通常为存储指令和分支指令,而U型指令(以及UJ型)用于实现跳转。指令中包含了源寄存器(rs),目的寄存器(rd),这些字段在译码和写回时使用,读取或写入指定的寄存器。

附录B 存储器层次结构

术语表:

在这里插入图片描述

1.概述

评价缓存性能

​ 评价缓存性能的一种方法是扩展第一章给出的处理器执行公式:

CPU执行时间 = (CPU时钟周期数+存储器停顿周期数) x 时钟周期时间

​ 其中CPU周期数为IC(指令数) x CPI

​ 存储器停顿周期取决于缺失数和每次缺失的代价:

存储器停顿周期 = 缺失数 x 缺失代价 = IC(指令数) x 存储器访问 / 指令 x 缺失率 x 缺失代价

​ 其中的存储器访问/指令表示单条指令的存储器访问次数,对于操作不访问存储器的指令,只有取指令本身访问一次存储器。如果直接使用缺失数测量缺失率,通常使用每千条指令缺失数。

​ 缺失率与硬件速度无关,易于测量,但可能产生误导,更好的度量存储器层次结构性能的标准是存储器平均访问时间

存储器平均访问时间 = 命中时间 + 缺失率 x 缺失代价

缓存

​ 对于存储器层次结构的第一级:缓存,考虑以下四个问题:

  • 缓存组织方式:共有以下三种,但其他两种也可以算作组相联
    • 直接映射:一个块只能放在一个确定的位置(相当于m个组相联)
    • 全相联:一个块可放在缓存的任意位置(若可放m个块,相当于m路组相联)
    • 组相联:一个块可放在缓存中划分出的组里的任意位置
  • 找到块中的缓存:物理地址可以划分为以下形式,标志位用于匹配判断是否为要找的块,索引字段指出了组,块偏移从块中选择数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UmtS3gGx-1681740208431)(计算机体系结构/image-20230318095933490.png)]

  • 缓存缺失读入块时的替换策略:通常有三种策略
    • 随机
    • LRU
    • FIFO
  • 读写策略

​ 重点考虑读写策略。所有指令访问都是读取,大多数指令不会写入数据,针对读取操作的优化是:一旦得到了块地址,就开始读取块,如果命中,就立即交给处理器,否则只需忽略读取值,按照读取缺失处理。而对于写则不能这样优化,必须核对标志位是否相同,因此写入通常比读取慢。写入的策略有两种选项:

  • 直写:信息被写入缓存和低一级存储器
  • 写回:信息仅被写入缓存,块被替换时才写入主存储器

​ 为了减少写回块的频率,通常采用一个脏位记录块是否被修改,如果块没有被修改,则不需要写回存储器。

​ 对于写入缺失,也有两种策略:

  • 写入分派:发生写入缺失时将块写入缓存,随后执行写入命中
  • 无写入分派:仅修改低一级存储器中的块

Opteran微处理器中数据缓存的组织方式

在这里插入图片描述

​ Opteran采用两路组相联策略,LRU替换策略,写回策略,有一个牺牲块缓冲区,被替换且修改过的块会发送给该缓冲区,写入低一级的存储器。

2.6种基本的缓存优化

​ 根据存储器平均访问时间的公式,可以将缓存优化的方式分为3类:

  • 降低缺失率:采用较大的块,大的缓存,较高的相联度
  • 降低缺失代价:多级缓存
  • 缩短在缓存中命中的时间:索引缓存时避免地址转换

​ 所有的缺失可以分为三类:

  • 冷不命中:第一次访问一个块时一定是缺失的
  • 容量不命中:缓存无法容纳当前需要用到的所有块
  • 冒险不命中:如果采用组相联或直接映射,则会发生冒险缺失,冒险缺失会随相联度的增大而减小

​ 其中的冒险不命中是最容易避免的,只需要采用全相联布置,但硬件实现成本高,可能会降低处理器时间频率;针对容量不命中,可采用的方法只有增大缓存;冷不命中可以通过增大块的大小来减少,但可能增加其他的缺失。许多降低缺失率的技术也会增加命中时间或缺失代价,因此必须综合考虑提高整体系统的速度的目标,优化缓存。下面介绍6种基本的缓存优化方法。

  • 增大块大小以降低缺失率:较大的块会降低冷不命中,并且充分利用了空间局部性,但是太大的块会增加缺失代价,增加其他两种缺失。块大小的选择有赖于低级存储器的带宽和延迟,对于高带宽的高延迟存储器,采用大块很少增加缺失代价,鼓励采用大块,若低级处理器是低延迟低带宽的,则鼓励采用小块
  • 增大缓存以降低缺失率:可降低容量缺失,缺点是可能延长命中时间,增加成本和功耗
  • 提高相联度以降低缺失率:经验规律是采用八路组相联和全相联是一样有效的。但是提高相联度会提高缺失代价
  • 采用多级缓存降低缺失代价:使用多级缓存可以加快缓存的速度,同时扩大缓存的容量。为了有效衡量多级缓存的缺失情况,使用局部缺失率(当前缓存级别的缺失率)和全局缺失率(整体缓存的缺失率)。第一级缓存的速度影响处理器的时钟频率,第二级缓存的速度仅影响一级缓存的缺失代价。二级缓存的缺失率更高,,因此重心偏向减少缺失,采用更高相联度和更大的块
  • 读取缺失的优先级高于写入缺失:对写后读问题,如果写入尚未完成,还在写入缓冲区,可以让读取缺失先检查写入缓冲区的内容
  • 索引缓存时避免地址转换:多数系统在缓存中使用物理地址,缩短命中时间,避免使用虚拟地址时的地址保护检查和进程标识等问题

3.虚拟存储器

​ 每个进程都有自己的地址空间,为了让同时运行的进程共享物理地址空间,计算机系统都采用虚拟存储器机制,让程序本身不需要考虑空间的具体分配,由操作系统及硬件负责具体空间的分配和虚拟地址到物理地址的转换。

​ 虚拟存储器的划分由两种机制:段机制和页机制,常见这两种方式的混合使用,或是多页面大小的分页机制的使用。

存储器层次结构的四个问题

  • 块在主存的位置:由于存储器缺失会导致访问磁盘,因此需要尽可能降低缺失率,块可以放在主存中的任何位置,即组织方式为全相联
  • 找到块的位置:分页方式通过页表找到虚拟地址对应的物理地址,地址被分为页号和偏移量,从页表查找映射;分段方式类似,使用段号和偏移获得物理地址。为了加快地址转换,计算机使用一个专门的地址转换缓存(TLB)
  • 存储器缺失时替换哪个块:操作系统常采用LRU算法,替换最近最少使用的块
  • 写入策略:由于写入磁盘代价很高,因此总是采用写回策略

快速地址转换

​ 分页表本身很大,有时候还会采用多级页表,这导致存储器访问甚至需要两次访存才能进行地址转换,因此计算机系统采用硬件缓存TLB(旁路地址转换缓冲)缓存地址转换。操作系统改变页表,必须使相应的TLB失效。

选择页大小

​ 页大小是常见的体系结构参数,页表的大小和页大小成反比,增大页可以节省存储器,并且分页较大时,可以允许缓存命中较大缓存,并且大的分页还可以使TLB高效映射更多存储器。采用较小的页则可以减少空间碎片,加快进程启动时间。

附录C 流水线基本原理

1.RISC V流水线

​ 流水线是一种将多条指令重叠执行的实现技术。一条指令需要多个操作,流水线技术利用了操作之间的并行性。流水线可以缩短每条指令的执行时间,可以记作CPI的下降或时钟周期的下降。如果开始时一条指令需要多个时钟周期,则看作是CPI的下降,否则可以看作是时钟周期的下降。

​ 附录介绍RISC-V体系结构下的流水线实现原理。RISC体系结构已在附录A中有所介绍。

RISC-V指令集的简单实现

​ RISC指令集中的每条指令都可以在最多五个时钟周期内实现,这五个周期如下:

  • 取址周期IF:提取当前指令,更新程序计数器
  • 指令译码/寄存器提取周期ID:对指令进行译码,并读取指定的寄存器值,并进行相等测试,判断是否为分支
  • 执行周期EX:ALU对上一周期准备的操作数进行操作,根据指令类型执行:
    • 存储器引用:基址寄存器+偏移量形成有效地址
    • 寄存器-寄存器ALU指令
    • 寄存器-立即数ALU指令
  • 存储器访问MEM:使用上一周期计算的有效地址,载入指令则从存储器中读取数据,存储指令则向存储器写入寄存器组第二个寄存器读取的数据
  • 写回周期WB:将结果写入寄存器组

​ 下图是MIPS的CPU结构,较RISC-V简单,可对照以上五个阶段,理解数据的流动过程。

在这里插入图片描述

RISC-V的流水线

​ 在每个时钟周期开始执行一条新的指令,就可以实现流水线化,为了保证每个周期都能正确执行,需要解决流水线化带来的一些问题。本节首先确保在一个周期,不会同时对相同数据源执行两个不同操作

​ 下图是一个RISC数据路径的流水线表示:

在这里插入图片描述

​ 主要的功能单元在不同周期使用,因此不会引入太多冒险,以下三点避免了可能的冒险:

  • 使用分离的指令缓存和数据缓存。在取址和存储器访问之间可能发生冒险,为了消除这种冒险,采用分离的缓存;访存可能是读也可能是写,无法确定,并且访存时间较长,不能像寄存器那样按照读写在半个周期分别处理
  • 在ID和WB两个阶段都使用了寄存器组,ID是读取,WB是写入,因此每个时钟周期要完成多个读取和一次写入。为了处理这个问题,在时钟周期的前半部分写寄存器,在后半部分读寄存器(利用上升沿-下降沿将指令周期划分前后)
  • 为了确保指令在流水线中不会相互干扰,在流水级之间引入流水线寄存器。在时钟周期的末尾,将一个流水级得到的结果存储到寄存器当中,用作下一级的输入

流水化的基本性能问题

​ 流水化提高了指令吞吐量,但不会缩短单条指令的执行时间,由于流水线控制会产生开销,通常还会稍微延长每条指令的执行时间。流水线开销包括流水线寄存器延迟(建立时间)和时钟偏差(两个寄存器之间的延迟),时钟的速度不可能快于最慢的流水级,因此时钟周期被限定了下限。

2.流水线冒险

​ 冒险阻止了指令流在下一个周期的执行,共有以下三类冒险:

  • 结构冒险:资源冲突
  • 数据冒险:相邻指令之间存在相关性
  • 控制冒险:分支指令及其他改变程序计数器的指令实现流水化时可能导致控制冲突

​ 冒险会使流水线停顿,为了避免冒险,经常要求一些指令延迟时,其他一些指令可以继续执行。附录中讨论的流水线,一条指令被停顿后,所有之后发射的指令也被停顿。

结构冒险

​ 结构冒险是由于资源冲突,不允许某些指令重叠。例如写入存储器的同时从存储器取址。当遇到这种指令序列时,流水线会使其中一个指令停顿一个周期,这个周期被称为流水线气泡。结构冒险是可以避免的,例如访存的数据冒险,可以将缓存分为独立的指令缓存和数据缓存,也可以用一组缓冲区来保存指令。是否要避免结构冒险,要考虑单元的成本,对于罕见的结构冒险,不值得花代价避免其出现。

数据冒险

​ 数据冒险是由数据的读写访问顺序产生的,重叠指令的执行改变了原有的读写顺序。下图的指令就是一个数据冒险,第五个周期ADD指令才写回,但SUB指令在第三个周期就要访问寄存器了。

在这里插入图片描述

​ or指令及之后的指令就不会导致冒险了,因为or读寄存器在第五周期的后半部分,而写入是在第五周期的前半部分。

​ 典型的数据冒险是由以下三种相关产生的:

  • 读后写WAR
  • 写后读RAW
  • 写后写WAW

​ 可以利用转发技术减少上述的数据冒险,这一技术也称为数据前推(Forwardig)。转发技术的关键是要把数据转移到需要的地方,对于上例,如果add计算后的结果转移到sub指令计算的位置,就可以避免出现停顿。工作方式如下:

  • 来自EX/MEM和MEM/WB的流水线寄存器的ALU结果总是被反馈给ALU的输入
  • 如果转发硬件检测到了前一个ALU操作已经对当前ALU操作的源寄存器进行了写入,则控制逻辑选择转发结果作为ALU输入,而不是从寄存器堆中读取值

在这里插入图片描述

​ 上述方式可以减少数据冒险停顿,但有些数据冒险是无法通过转发处理的。考虑以下指令:

在这里插入图片描述

​ 对于这段程序,ld指令第四周期才读出sub指令需要的值,而sub指令第二周期就要读取这个值了,这个冒险是无法避免的。这个时候就需要增加一种称为流水线互锁的执行方式,检测冒险,并在冒险结束之前使流水线停顿。

控制冒险

​ 处理分支的最简单办法是,如果译码检测到了分支指令,就在下一个周期重新对下一条指令进行取址,这会产生一个周期的停顿。假设分支指令在ID计算分支地址并判断分支条件。如果分支没有被选中,这一个停顿周期就是不必要的,因此,下面讨论一些应对这一问题的技术。

在这里插入图片描述

​ 降低分支代价有四种编译时机制,由软件利用硬件机制和分支特点降低分支代价。

  • 冻结或冲刷流水线:保留或删除分支之后的指令,直到知道分支目标,这是上表选择的方式,代价是固定的
  • 预测未选中机制:将所有分支看作未选中分支,如果分支被选中,就将提取的指令转为空操作
  • 预测选中分支:将所有分支看作选中分支,对于五级流水线来说没有好处,因为计算分支地址最快也要ID完成,但对于具有隐形设定条件代码或其他分支机制的处理器,可能是有效的
  • 延迟分支:无论分支是否被选中,都执行分支指令的下一条指令

​ 延迟分支在早期RISC中应用广泛,在分支和分支目标之间的分支延迟时隙执行一条指令,这条指令由编译器进行调度。显然如果没有冒险,把一条分支指令之前的一定会执行的指令移动到分支指令之后是最合适的,不过这可能无法实现。这个技术也被称为延迟槽。现在的RISC-V使用动态分支预测,已经不再使用延迟分支了。

​ 当流水线越来越深,分支的代价增加时,上述简单机制就不够了,需要更好的分支预测机制。这些机制分为两类:依赖编译时信息的静态分支预测机制,根据程序特性对分支动态预测的机制。

  • 静态分支预测:利用先前运行过程收集的数据,预测选中或未选中。整数程序的错误预测率较高,此类分支频率很高,是静态分支预测的主要限制
  • 动态分支预测:最简单的方式是使用分支预测缓冲区,根据分支指令的低位进行索引,这个缓冲区包含一个位,表明该分支是否被选中,如果预测不正确,则将该位翻转。如果一个分支连续两次的结果不相同且与之前的分支情况不同,则两次都会预测错误,第一次因为预测位为0,第二次因为预测位为1,为了弥补这一弱点,经常使用2位预测机制,经测量,每项两位的分支预测缓冲区预测准确度超过82%,算是相当准确了。

在这里插入图片描述

2位的动态分支预测

3.流水化的实现

3.1 流水线的基本实现

​ 流水线化的方式已经在C.1中介绍过了。这里细致的说明每个周期指令完成的实际操作。

取址周期

​ IR <- Mem[PC]

​ NPC <- PC+4

​ 其中IR存储取出的指令,NPC是下一条指令的地址。PC并不止这一种取值,还可能是分支值。

指令译码/寄存器提取周期

​ A <- Regs[rt]

​ B <- Regs[rt]

​ Imm <- 扩展后的立即数

执行周期

​ 这一周期有几种可能的操作:

  • 存储器引用:计算引用的地址值
  • ALU运算:进行寄存器与寄存器值或立即数值的计算
  • 分支目标计算及条件判断(分支实际上不需要等到执行周期完成,后面会说明)

访存周期

​ 这一周期完成了存储器引用:

​ LMD(载入存储器数据) <- MEM[ALUoutput] / MEM[ALUoutput] <- B

​ 同时在这个周期把上个周期计算出的分支目标地址写入PC。(和上面的分支计算一样,这一操作没有必要等到这个周期)

写回周期

​ 写回周期根据指令类型,写入寄存器组:

  • R型指令:Regs[rd] <- ALUoutput
  • I型运算指令:Regs[rt] <- ALUoutput
  • I型访存指令:Regs[rt] <- LMD

​ 通过将执行划分为五个周期,最终的流水线如下图:

在这里插入图片描述

3.2实现流水线的控制

​ 将一条指令从译码ID移入执行EX的过程通常为指令发射,已经执行这一步骤的指令称为已发射。对于整数的情况,所有的数据冒险都可以在ID阶段进行检查,如果存在数据冒险,就停顿当前指令。停顿的方式是IF/ID保持值而不更新,ID/EX输出空操作,这样流水线的IF和ID阶段停顿,后面的阶段继续运行,从而处理了数据冒险问题。以下是可能的数据冒险:

在这里插入图片描述

3.3处理流水线分支

​ 对于零检测分支,分支条件判断和目标地址计算工作在译码ID阶段就可以完成了,不需要等到执行,因此ID阶段可以判断分支条件,这样如果有分支,只浪费了分支之后IF的一条指令,相当于停顿一个周期,这条IF的指令还可以作为延迟槽,使用指令重排序将一条无论是否跳转都要执行的指令到这里,避免浪费。对于更深的流水线设计,分支延迟可能更大。MIPS采用了这样的设计。然而,如果在ID阶段就完成分支计算,会导致一些数据冒险产生更多停顿,因此RISC-V设计在EX阶段完成分支判断,这样如果没有分支预测,会浪费两条指令,相当于产生两个停顿

​ RISC-V使用动态分支预测,不使用延迟槽,因为分支延迟并不总是可行,并且分支判断在EX阶段完成,在ID阶段根据预测的结果进行跳转,EX阶段进行验证。

在这里插入图片描述

​ 对于RISC-V来说,假设采用动态分支预测,流水线是这样的(对于jal这样的指令,分支地址可以在ID计算),假设总是预测正确

预测选中

CLK1CLK2CLK3CLK4CLK5CLK6CLK7
pipline i1IF(PC+4)ID(分支预测,分支地址计算)EX(计算分支条件)MEMWB
pipline i2IF(根据预测结果更新PC=PC+8/branch target)IDflushflushflush
pipline i3IF(PC=PC+4)ID(branch target)EXMEMWB

预测不选中

CLK1CLK2CLK3CLK4CLK5CLK6CLK7
pipline i1IF(PC+4)ID(分支预测,分支地址计算)EX(计算分支条件)MEMWB
pipline i2IF(根据预测结果更新PC=PC+8/branch target)IDEXMEMWB
pipline i3IF(PC=PC+4)ID(PC)EXMEMWB

​ 如果没有分支预测,或者说默认未选中,那么流水线将是这样的:

CLK1CLK2CLK3CLK4CLK5CLK6CLK7CLK8
pipline i1IF(PC+4)ID(分支地址计算)EX(计算分支条件)MEMWB
pipline i2IF(PC = PC+4)ID(PC)flushflushflush
pipline i3IF(根据分支条件,PC=PC+4/branch target )flushflushflushflush
pipline i4IF(PC=PC+4)ID(branch target)EXMEMWB

​ 分支预测正确时减少了指令的浪费和停顿。

3.4流水线加速比

​ 在理想情况下,流水线中没有停顿,一个流水线的时钟周期完成一条指令,假设流水线深度为d,没有流水线化的d个时钟周期可以完成一条指令,建立流水线后,可以完成d条指令,因此理想流水线加速比为d。考虑停顿,流水线加速比为:
S p e e d u p = d 1 + s t a l l s Speedup = \frac{d}{1+stalls} Speedup=1+stallsd
​ 其中的停顿时间来自各种冒险,如果知道每个冒险发生的频率和代价,就可以计算出流水线加速比。

4.流水线中的异常

​ 不同CPU会用不同的词描述改变指令正常执行顺序的情景,包括中断、错误、异常等词。在本书中,用异常来包含所有这些情况。异常的情况非常多,仅从流水线的角度来说,有以下这几种异常:

流水级异常
IF指令提取发生页错误、非对齐存储器访问、违反存储器保护规则
ID未定义或非法操作码
EX算数异常
MEM数据提取时发生页错误、非对齐存储器访问、违反存储器保护规则
WB

​ 在实际的流水线当中,错误很可能不按指令执行顺序发生。如果发生异常时,流水线可以停止,使紧急错误指令之前的指令可以完成,使其之后的指令可是从头重新启动,就说该流水线拥有精确异常。处理异常较为复杂,书中介绍了停止和恢复执行的方式,此处略过。

7.交叉问题

7.1RISC指令集和流水线

​ RISC这样的简单指令集有一个好处,对代码的调度是简单的。因为RISC完成一个完整的操作需要更多指令,增加了调度的灵活性。因此几乎所有复杂指令集的流水线都将复杂指令转换为类似RISC的简单操作,然后进行调度和流水化。

7.2动态调度流水线

​ 之前介绍的数据前推解决流水线中的一些冒险,但是总是存在一些不可避免的冒险,使流水线停顿。停顿时,不会提取或发射新指令,为了弥补这些性能损失,编译器可以采用调度指令来避免冒险,这种方法为静态调度。几种早期处理器使用了另外一种动态调度技术,为了更好的理解后续采用的更加复杂的机制,有必要介绍动态调度机制

​ 之前介绍的流水线,指令时按序执行的,如果两条指令之间存在冒险,即使后面的指令是不相关的,也会停顿下来。

将一条指令从译码ID移入执行EX的过程通常为指令发射,已经执行这一步骤的指令称为已发射。为使一条指令在操作数可用时就可以开始执行,而不受先前停顿的指令的影响,发射过程必须分为两部分:检查冒险,等待数据冒险结束。按序对指令进行译码和发射,但乱序执行。ID流水线将被划分为两级:

  • 发射:指令译码,检查结构冲突
  • 读取操作数:等到没有数据冒险,随后读取操作数

​ 为了能让多条指令处于执行状态中,要改变功能单元设计,改变单元数,操作延迟和功能单元流水化。

采用记分牌的动态调度机制

​ 动态调度流水线中,指令按序发射,乱序执行,实现方式是使用记分牌。记分牌全面负责指令发射与执行,包括所有冒险检测任务。乱序执行会导致原来顺序执行流水线中不存在的WAR和WAW冒险出现,这些冒险都由记分牌来检测和处理。为了保证多个指令同时执行,处理器拥有多个功能单元(存储器引用单元,整数运算单元,浮点运算单元等)。每条指令都会进入记分牌,有一条记录,记分牌会判断什么时候能读取操作数并执行,还会控制指令什么时候能写回目标寄存器。

​ 现在先不考虑存储器访问,只考虑运算指令,指令在流水线中完成有四个步骤:

  • 发射:如果指令的一个功能单元空闲,没有其他活动指令以同一寄存器为目标寄存器,则向功能单元发射指令。如果存在WAW冒险或结构冒险,则指令发射停顿。
  • 读取操作数:记分牌监视源操作数的可用性,如果先前发射的指令都不写入源操作数,则该源操作数可用,这一步解决了RAW冒险。
  • 执行:功能单元收到操作数后开始执行,结果就绪后,通知记分牌已经完成了执行。
  • 写结果:记分牌知道了功能单元完成执行,则检查WAR冒险,并在必要时停止正在完成的指令。

​ 接下来以一个指令序列为例,给出记分牌中所有记录的信息:

LD F6,34R2
LD F2,45(R3)
MULD F0,F2,F4
SUBD F8,F6,F2
DIVD F10,F0,F6
ADDD F6,F8,F2

在这里插入图片描述

​ 记分牌有三个部分:

  • 指令状态:指出该指令处于四个步骤中的哪一步
  • 功能单元状态:指出功能单元的状态,Fj和Fk为源寄存器编号,Fi为目标寄存器,Qj,Qk为生成源寄存器的功能单元,Rj和Rk表示操作数是否已准备就绪
  • 寄存器结果状态:指出哪个功能单元将写入哪个寄存器,写入完成后字段为空

​ 有了上述信息,记分牌就可以控制指令的执行过程,一个指令的执行,要先检查需要使用的结构单元是否处于空闲,如果空闲,则可以发射,并准备读取操作数。读取操作数之前要检查RAW冒险,确保操作数就绪,得到操作数后可以开始执行。执行结束后,根据寄存器结果状态以及其他信息,检查WAR冒险和WAW冒险,无冒险时完成写入。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/426047.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

练习Tomcat

文章目录1. 简述静态网页和动态网页的区别。2. 简述 Webl.0 和 Web2.0 的区别。3. 安装tomcat8&#xff0c;配置服务启动脚本&#xff0c;部署jpress应用。1. 简述静态网页和动态网页的区别。 静态网页&#xff1a; &#xff08;1&#xff09;静态网页不能简单地理解成静止不…

SCADE Display(OpenGL)软件设计文档生成工具的设计考虑

SCADE Display&#xff08;OpenGL&#xff09;软件设计文档生成工具的设计考虑 2018年6月 1 引言 本文档描述在SCADE Display软件设计文档生成工具&#xff08;以下简称为SDYSDDGEN&#xff09;的设计过程中考虑到的一些问题及其解决方案。 2 目标 SDYSDDGEN的目标设定为&…

面向对象程序设计 C++总结笔记(1)

面向对象程序设计 学习方法 理解基本原理掌握程序设计方法加强动手实践 课程目标 理解面向对象程序设计的基本原理&#xff0c;掌握面向对象技术的基本概念和封装性、继承性和多态性&#xff0c;能够具有面向对象程序设计思想。掌握C语言面向对象的基本特性和C语言基础知识&…

就在20号!袋鼠云春季生长大会邀您共观数智生机,我们云上见

如今&#xff0c;数字经济正逐步走向深化应用、规范发展、普惠共享的新阶段&#xff0c;数字经济与实体经济深度融合、基础软件国产化替代成为数字时代主潮流。 「 2023 袋鼠云春季生长大会」乘风而起&#xff0c;带您走近大数据基础软件——数栈&#xff0c;低代码数字孪生世界…

Hadoop之Yarn篇

目录 ​编辑 Yarn的工作机制&#xff1a; 全流程作业&#xff1a; Yarn的调度器与调度算法&#xff1a; FIFO调度器&#xff08;先进先出&#xff09;&#xff1a; 容量调度器&#xff08;Capacity Scheduler&#xff09;&#xff1a; 容量调度器资源分配算法&#xff1…

【面试题】对 JSON.stringify()与JSON.parse() 理解

大厂面试题分享 面试题库 前后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 web前端面试题库 VS java后端面试题库大全 重新学习这两个API的起因 在本周五有线上的项目&#xff0c;16:30开始验证线上环境。 开始…

【数据挖掘与商务智能决策】第十一章 AdaBoost与GBDT模型

11.1 AdaBoost模型简单代码实现 1.AdaBoost分类模型演示 from sklearn.ensemble import AdaBoostClassifier X [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]] y [0, 0, 0, 1, 1]model AdaBoostClassifier(random_state123) model.fit(X, y)print(model.predict([[5, 5]]))[0…

使用 Urch 让 Ubuntu 原生远程控制功能稳定可靠

有些时候&#xff0c;使用远程控制能够简化不少运维和操作的事情。 本篇文章分享如何通过开源工具 “Urch&#xff08;Ubuntu Remote Control Helper&#xff09;” 让 Ubuntu 原生的远程控制&#xff08;远程桌面&#xff09;功能稳定可靠。 方案已经经过 Ubuntu 22.04 LTS …

JVM之低延迟垃圾收集器

目录 低延迟垃圾收集器 概要 各款收集器的并发情况 Shenandoah收集器 Shenandoah相比G1的改进之处 链接矩阵 定义 优点 Shenandoah收集器的工作过程 Brooks Pointer 转发指针技术 转发指针的优缺点 Shenandoah 性能测试 Shenandoah 总结 ZGC 收集器 ZGC的Region的…

编译原理第一章

编译原理笔记 文章目录编译原理笔记day1什么是编译&#xff1f;编译器的结构词法分析概述词法分析的主要任务语法分析概述主要目的主要任务具体实例语义分析概述主要目的主要任务中间代码生成和编译器后端常用的中间表示形式目标代码生成器代码优化器day1 什么是编译&#xff…

Mysql 学习(一)基础知识(待更新)

文章目录服务端处理客户端请求启动项系统变量启动项和系统变量的区别常见的字符集字符集比较规则服务端处理客户端请求 客户端进程向服务器进程发送一段文本&#xff08;MySQL语句&#xff09;&#xff0c;服务器进程处理后再向客户端进程发送一段文本&#xff08;处理结果&am…

Idea使用样式主题

目的 花里胡哨的idea显示主题 安装插件 在preferences>plugins中搜索“Material Theme”安装两个中的一个 重启>设置>选择主题 对比度&#xff08;多选&#xff09; Contrast Mode:对比度模式&#xff0c;目录结构&#xff0c;选项卡等非文本选择前后的颜色对比度。…

Docker部署RabbitMQ(单机,集群,仲裁队列)

RabbitMQ部署指南 1.单机部署 我们在Centos7虚拟机中使用Docker来安装。 1.1.下载镜像 方式一&#xff1a;在线拉取 docker pull rabbitmq:3-management方式二&#xff1a;从本地加载 在课前资料已经提供了镜像包&#xff1a; 上传到虚拟机中后&#xff0c;使用命令加载镜…

【论文阅读】(20230410-20230416)论文阅读简单记录和汇总

&#xff08;20230410-20230416&#xff09;论文阅读简单记录和汇总 2023/04/09&#xff1a;很久没有动笔写东西了&#xff0c;这两周就要被抓着汇报了&#xff0c;痛苦啊呜呜呜呜呜 目录 (CVPR 2023): Temporal Interpolation Is All You Need for Dynamic Neural Radiance …

RPC 漫谈:序列化问题

RPC 漫谈&#xff1a;序列化问题 何为序列 对于计算机而言&#xff0c;一切数据皆为二进制序列。但编程人员为了以人类可读可控的形式处理这些二进制数据&#xff0c;于是发明了数据类型和结构的概念&#xff0c;数据类型用以标注一段二进制数据的解析方式&#xff0c;数据结…

echarts formatter如何自定义百分比小数位置,比如取整数。{b} {d}%

echarts formatter如何自定义百分比小数位置&#xff0c;比如取整数。{b} {d}% 一、现状 我有一个 pie 的图表&#xff0c;option 中的 formatter 是这样的&#xff1a; label: {show: true,position: outside,fontSize: 12,formatter: {b} {d}% },图表数据是这样的 二、需…

获取本地电脑连接的所有WIFI密码(适合Windows 11/10/8/7)

背景 如果你的心入职同事问你公司WIFI密码是多少&#xff0c;恰好这时你也忘记密码&#xff0c;用次方法可以实现得到WIFI密码。 如果你忘记现在在WIFI密码&#xff0c;也可以用此方法获取。 实现 1. 使用管理员权限打开 cmd.exe 2. 获取本机所有连接的 WIFI 用户配置 ne…

如何交叉编译程序:以freetype为例

【记录所学】 本博客为学习Linux开发时的笔记。主要记录如何交叉编译程序。 内容会首先介绍程序运行的一些基础知识&#xff0c;其次介绍常见错误的解决方法&#xff0c;然后介绍交叉编译程序的万能命令&#xff0c;最后以一个实际例子介绍如何交叉编译程序。 简要说明&#…

使用篇丨链路追踪(Tracing)很简单:链路实时分析、监控与告警

作者&#xff1a;涯海 前文回顾&#xff1a; 基础篇&#xff5c;链路追踪&#xff08;Tracing&#xff09;其实很简单 使用篇&#xff5c;链路追踪&#xff08;Tracing&#xff09;其实很简单&#xff1a;请求轨迹回溯与多维链路筛选 在前面文章里面&#xff0c;我们介绍了…

快排非递归 归并排序

递归深度太深会栈溢出 程序是对的&#xff0c;但是递归个10000层就是栈溢出 int fun(int n) {if (n < 1){return n;}return fun(n - 1) n; }所以需要非递归来搞快排和归并&#xff0c;在效率方面没什么影响&#xff0c;只是解决递归深度太深的栈溢出问题 有的能直接改&am…