26考研——中央处理器_指令流水线_流水线的冒险与处理 流水线的性能指标 高级流水线技术(5)
408答疑
文章目录
- 六、指令流水线
- 流水线的冒险与处理
- 结构冒险
- 数据冒险
- 延迟执行相关指令
- 采用转发(旁路)技术
- load-use 数据冒险的处理
- 控制冒险
- 流水线的性能指标
- 流水线的吞吐率
- 流水线的加速比
- 高级流水线技术
- 超标量流水线技术
- 超长指令字技术
- 超流水线技术
- 八、参考资料
- 鲍鱼科技课件
- 26王道考研书
六、指令流水线
流水线的冒险与处理
- 在指令流水线中,可能遇到一些情况使得后续指令无法正确执行而引起流水线阻塞,这种现象称为流水线冒险。根据导致冒险的原因不同分为结构冒险、数据冒险和控制冒险 3 种。
- 不同类型指令在各流水段的操作是不同的,下表中列出了几类指令在各流水段中的操作。
指令 | 流水段 | ||||
---|---|---|---|---|---|
IF | ID | EX | MEM | WB | |
ALU | 取指 | 译码,读寄存器堆 | 执行 | — | 结果与回寄存器堆 |
取/存 | 取指 | 译码,读寄存器堆 | 计算访存有效地址 | 访存(读/写) | 将读出的数据写入寄存器堆/— |
转移 | 取指 | 译码,读寄存器堆 | 计算转移目的地址,设置条件码 | 若条件成立,将转移目的地址送 PC | — |
结构冒险
- 由不同指令在同一时刻争用同一功能部件而形成的冲突,也称资源冲突,即由硬件资源竞争造成的冲突。
- 例如,指令和数据通常都存放在同一存储器中,在第 4 个时钟周期,第 i i i 条 LOAD 指令进入 MEM 段时,第 i + 3 i+3 i+3 条指令的 IF 段也要访存取指令,此时会发生访存冲突,为此可在前一条指令访存时,暂停(一个时钟周期)取后一条指令的操作,如下表所示。当然,若第 i i i 条指令不是 LOAD 指令,则在 MEM 段不访存,也就不会发生访存冲突。
指令 | 流水段 | ||||
---|---|---|---|---|---|
IF | ID | EX | MEM | WB | |
取 | 取指 | 译码,读寄存器堆 | 计算访存有效地址 | 访存(读/写) | 将读出的数据写入寄存器堆 |
指令 | 时钟周期 | ||||||||
---|---|---|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
LOAD 指令 | IF | ID | EX | MEM | WB | ||||
指令 i + 1 | IF | ID | EX | MEM | WB | ||||
指令 i + 2 | IF | ID | EX | MEM | WB | ||||
指令 i + 3 | 停顿 | IF | ID | EX | MEM | WB | |||
指令 i + 4 | IF | ID | EX | MEM |
- 解决结构冲突有以下两种办法:
- 前一条指令访存时,使后一条相关指令(及其后续指令)暂停一个时钟周期。
- 设置多个独立的部件。
- 例如,对于寄存器访问冲突,可将寄存器的读口和写口独立开来;
- 对于访存冲突,单独设置数据存储器和指令存储器。在现代 Cache 机制中,L1 级 Cache 通常采用数据 Cache 和指令 Cache 分离的方式,从而也就避免了资源冲突的发生。
数据冒险
- 数据冒险也称数据相关。引起数据冒险的原因是,后面指令用到前面指令的结果时,前面指令的结果还没有产生。
- 在以非乱序执行的流水线中,所有数据冒险都是因为前面指令写结果之前,后面指令就需要读取而造成的,这种数据冒险称为写后读(Read After Write, RAW)冲突。
在按序执行的流水线中(统考中通常采用这种方式),只可能出现 RAW 冲突。
例如,考虑下列两条指令:
I1: add R1, R2, R3 # (R2) + (R3) → R1
I2: sub R4, R1, R5 # (R1) - (R5) → R4
- 在写后读(RAW)冲突中,指令 I2 的源操作数是指令 I1 的目的操作数。正常的读/写顺序是由指令 I1 先写入 R1,再由指令 I2 来读 R1。
- 在非流水线中,这种先写后读的顺序是自然维持的。
- 但在流水线中,由于重叠操作,读/写的先后顺序关系发生了变化,如下表所示。
指令 | 流水段 | ||||
---|---|---|---|---|---|
IF | ID | EX | MEM | WB | |
ALU | 取指 | 译码,读寄存器堆 | 执行 | — | 结果与回寄存器堆 |
- 可以采用以下几种办法解决 RAW 数据冲突。
延迟执行相关指令
- 把遇到数据相关的指令及其后续指令都暂停一至几个时钟周期,直到数据相关问题消失后再继续执行,可分为软件插入空操作 “nop” 指令和硬件阻塞(stall)两种方法。
- 如下表所示,在第 5 个时钟周期,add 指令才将运算结果写入 R1,但后继 sub 指令在第 3 个时钟周期就要从 R1 中读数,使先写后读的顺序改变为先读后写,发生了先写后读(RAW)的数据冲突。
- 若不采取措施,按上表的读/写顺序,则会导致结果出错。
- 为此,可以暂停 sub 指令 3 个时钟周期,直至前面 add 指令的结果生成,如下表所示。
指令 | 时钟周期 | ||||||||
---|---|---|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
add | IF | ID | EX | MEM | WB | ||||
sub | 阻塞 | 阻塞 | 阻塞 | IF | ID | EX | MEM | WB |
- 对于 I1 和 I2 的数据相关问题,还可以通过将寄存器的写口和读口分别控制在前、后半个时钟周期内操作,使前半周期写入 R1 的值在后半周期马上被读出,在一个周期内读/写寄存器不会产生冲突,这样 I1 的 WB 段和 I2 的 ID 段就可重叠执行,从而只需延迟 2 个时钟周期。
采用转发(旁路)技术
-
设置相关转发通路,不等前一条指令把计算结果写回寄存器,下一条指令也不再从寄存器读,而将数据通路中生成的中间数据直接转发到 ALU 的输入端。
-
如下表所示,指令 I1 在 EX 段结束时已得到 R1 的新值,被存放到 EX/MEM 流水段寄存器中,因此可以直接从该流水段寄存器中取出数据发送到 ALU 的输入端,这样,在指令 I2 执行时 ALU 中用的就是 R1 的新值。
-
增加转发通路后,相邻两条运算类指令之间、相隔一条的两个运算类指令之间的数据相关问题就都能解决了。
load-use 数据冒险的处理
- 若 load 指令与其后紧邻的运算类指令存在数据相关问题,则无法通过转发技术来解决,通常把这种情况称为 load-use 数据冒险。
- 对于下列两条指令,load 指令只有在 MEM 段结束时才能得到主存中的结果,然后送 MEM/WB 流水段寄存器,在 WB 段的前半周期才能存入 R2 的新值,但随后的 add 指令在 EX 阶段就要取 R2 的值,因此,得到的是旧值。
I2: load r2, 12(r1) # M[(r1)+12] → (r2)
I3: add r4, r3, r2 # (r3) + (r2) → (r4)
-
对于 load-use 数据冒险,最简单的做法是由编译器在 add 指令之前插入一条 nop 指令,这样在 add 指令的 EX 段就可以从 MEM/WB 流水段寄存器中取出 load 指令的最新结果,如下表所示。
-
当然,最好的办法是在程序编译时进行优化,通过调整指令顺序以避免出现 load-use 现象。
控制冒险
- 指令通常是顺序执行的,但当遇到改变指令执行顺序的情况,例如执行转移或返回指令、发生中断或异常时,会改变 PC 值,从而造成断流,也称控制冒险。
- 对于由转移指令引起的冲突,最简单的处理方法就是推迟后续指令的执行。
- 通常把因流水线阻塞带来的延迟时钟周期数称为延迟损失时间片 C。
- 在下列指令中,假设 R2 存放常数 N,R1 的初值为 1,bne 指令在 EX 段通过计算设置条件码,并在 MEM 段确定是否将 PC 值更新为转移目的地址,因此仅当 bne 指令执行到第 5 个时钟结束时才能将转移目标地址送 PC。
- 为此,在数据通路检测到分支指令后,可以在分支指令后插入 C(此处 C = 3)条 nop 指令,如下表所示。
I1: loop: add R1, R1, 1 # (R1) + 1 → R1
I2: bne R1, R2, loop # if (R1) != (R2) goto loop
指令 | 流水段 | ||||
---|---|---|---|---|---|
IF | ID | EX | MEM | WB | |
转移 | 取指 | 译码,读寄存器堆 | 计算转移目的地址,设置条件码 | 若条件成立,将转移目的地址送 PC | — |
指令 | 时钟周期 | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
add | IF | ID | EX | MEM | WB | |||||
bne | IF | ID | EX | MEM | WB | |||||
add | IF | ID | EX | MEM | WB |
- 有以下几种方法解决控制冲突:
- 对于由转移指令引起的冲突,可采用和解决数据冲突相同的软件插入 “nop” 指令和硬件阻塞(stall)的方法。比如,延迟损失多少时间片,就插入多少条 nop 指令。
- 对转移指令进行分支预测,尽早生成转移目标地址。分支预测分为简单(静态)预测和动态预测。若静态预测的条件总是不满足,则按序继续执行分支指令的后续指令。动态预测根据程序转移的历史情况,进行动态预测调整,有较高的预测准确率。
Cache 缺失的处理过程也会引起流水线阻塞。
流水线的性能指标
流水线的吞吐率
-
流水线的吞吐率是指在单位时间内流水线所完成的任务数量,或输出结果的数量。
- 流水线吞吐率(TP)的最基本公式为
T P = n T k TP = \frac{n}{T_k} TP=Tkn
- 式中, n n n 是任务数, T k T_k Tk 是处理完 n n n 个任务所用的总时间。
-
设 k k k 为流水线的段数, Δ t \Delta t Δt 为时钟周期。在输入流水线中的任务连续的理想情况下,一条 k k k 段流水线能在 k + n − 1 k + n - 1 k+n−1 个时钟周期内完成 n n n 个任务。得出流水线的吞吐率为
T P = n ( k + n − 1 ) Δ t TP = \frac{n}{(k + n - 1)\Delta t} TP=(k+n−1)Δtn
- 连续输入的任务数 n → ∞ n \to \infty n→∞ 时,得到最大吞吐率为 T P max = 1 Δ t TP_{\text{max}} = \frac{1}{\Delta t} TPmax=Δt1。
流水线的加速比
-
完成同样一批任务,不使用流水线与使用流水线所用的时间之比。
- 流水线加速比(S)的基本公式为
S = T 0 T k S = \frac{T_0}{T_k} S=TkT0
- 式中, T 0 T_0 T0 表示不使用流水线的总时间: T k T_k Tk 表示使用流水线的总时间。
-
一条 k k k 段流水线完成 n n n 个任务所需的时间为 T k = ( k + n − 1 ) Δ t T_k = (k + n - 1)\Delta t Tk=(k+n−1)Δt;顺序执行 n n n 个任务时,所需的总时间为 T 0 = k n Δ t T_0 = kn\Delta t T0=knΔt。
- 将 T 0 T_0 T0 和 T k T_k Tk 值代入上式,得出流水线的加速比为
S = k n Δ t ( k + n − 1 ) Δ t = k n k + n − 1 S = \frac{kn\Delta t}{(k + n - 1)\Delta t} = \frac{kn}{k + n - 1} S=(k+n−1)ΔtknΔt=k+n−1kn
- 连续输入的任务数 n → ∞ n \to \infty n→∞ 时,得最大加速比为 S max = k S_{\text{max}} = k Smax=k。
高级流水线技术
- 有两种增加指令级并行的策略:
- 多发射技术:通过采用多个内部功能部件,使流水线功能段能同时处理多条指令,处理机一次可以发射多条指令进入流水线执行。
- 超流水线技术:通过增加流水线级数来使更多的指令同时在流水线中重叠执行。
超标量流水线技术
也称动态多发射技术,每个时钟周期内可并发多条独立指令,以并行操作方式将两条或多条指令编译并执行,为此需配置多个功能部件,如下图所示。
- 在简单的超标量 CPU 中,指令是按顺序发射执行的。
- 为了更好地提高并行性能,多数超标量 CPU 都结合动态流水线调度技术,通过动态分支预测等手段,指令不按顺序执行,这种方式称为乱序执行。
超长指令字技术
也称静态多发射技术,由编译程序挖掘出指令间潜在的并行性,将多条能并行操作的指令组合成一条具有多个操作码字段的超长指令字(可达几百位),为此需要采用多个处理部件。
超流水线技术
- 流水线功能段划分得越多,时钟周期就越短,指令吞吐率也就越高,因此超流水线技术是通过提高流水线主频的方式来提升流水线性能的,如下图所示。
- 但是,流水线级数越多,用于流水寄存器的开销就越大,因此流水线级数是有限制的,并不是越多越好。
- 超标量流水线 CPU 在流水线充满后,每个时钟周期还是执行一条指令, C P I = 1 CPI = 1 CPI=1,但其主频更高;多发射流水线 CPU 每个时钟周期可以处理多条指令, C P I < 1 CPI < 1 CPI<1,但其成本更高、控制更复杂。
八、参考资料
鲍鱼科技课件
b站免费王道课后题讲解:
网课全程班: