3.1 流水线的基本概念
3.1.1 什么是流水线技术
流水线技术概念 ⭐
-
把一个重复的过程分解为若干个子过程,每个子过程由专门的功能部件来实现。
-
把多个处理过程在 时间上错开,依次通过各功能段,这样,每个子过程就可以与其它的子过程并行进行。
以上就是计算机中的流水线技术
名词解释
-
流水线的级或段:流水线中的每个子过程及其功能部件
段与段相互连接形成流水线 -
流水线的深度:流水线的段数
-
指令流水线:
-
把流水线技术应用于指令的解释执行过程,就形成了指令流水线。
-
如果将指令分解为分析和执行两个子过程,并让这两个子过程分别用独立的分析部件和执行部件来实现:理想情况下,指令速度提高一倍
-
四段指令流水线:
-
-
浮点加法流水线
- 把流水线技术应用于运算的执行过程,就形成了运算操作流水线,也称为部件级流水线。
- 把浮点加法的全过程分解为求阶差、对阶、尾数、相加、规格化四个子过程。理想情况:速度提高3倍
-
时空图
-
时-空图从时间和空间两个方面描述了流水线的工作过程。
-
时-空图中,横坐标代表时间,纵坐标代表流水线的各个段。
-
例如:浮点加法流水线的时空图
- 通过时间:第一个任务从进入流水线到流出结果所需的时间。
- 排空时间:最后一个任务从进入流水线到流出结果所需的时间。
-
流水线技术特点
- 流水线把一个处理过程分解为若干个子过程(段),每个子过程由一个专门的功能部件来实现。
- 流水线中各段的时间应尽可能相等,否则将引起流水线堵塞、断流。
- 时间最长的段将成为流水线的瓶颈。
- 流水线每一个段的后面都要有一个缓冲寄存器(锁存器),称为流水寄存器。
- 作用:在相邻的两段之间传送数据,以保证提供后面要用到的信息,并把各段的处理工作相互隔离。
- 流水技术适合于大量重复的时序过程,只有在输入端不断地提供任务,才能充分发挥流水线的效率。
- 流水线需要有通过时间和排空时间 ⭐
- 通过时间:第一个任务从进入流水线到流出结果所需的时间。
- 排空时间:最后一个任务从进入流水线到流出结果所需的时间。
3.1.2 流水线的分类
部件级、处理机级及系统级流水线
(按照流水技术用于计算机系统的等级不同)
- 部件级流水线(运算操作流水线):把处理机中的部件分段,再把这些分段相互连接起来,使得各种类型的运算操作能够按流水方式进行。
- 处理机级流水线(指令流水线):把指令的执行过程按照流水方式处理。把一条指令的执行过程分解为若干个子过程,每个子过程在独立的功能部件中执行。
- 系统级流水线(宏流水线):把多台处理机串行连接起来,对同一数据流进行处理,每个处理机完成整个任务中的一部分
单功能流水线与多功能流水线
(按照流水线所完成的功能来分类)
- 单功能流水线:只能完成一种固定功能的流水线。
- 多功能流水线:流水线的各段可以进行不同的连接,以实现不同的功能。
- 例:ASC处理机的多功能流水线
- 具有8个功能段,按不同链接,可以实现浮点加减法和定点乘法运算
-
- 例:ASC处理机的多功能流水线
静态流水线与动态流水线
(按照同一时间内各段之间的连接方式对多功能流水线作
进一步的分类)
- 静态流水线:在同一时间内,多功能流水线中的各段只能按同一种功能的连接方式工作。
- 对于静态流水线来说,只有当输入的是一串相同的运算任务时,流水的效率才能得到充分的发挥
- 动态流水线:在同一时间内,多功能流水线中的各段可以按照不同的方式连接,同时执行多种功能。
- 优点 :灵活,能够提高流水线各段的使用率,从而提高处理速度。
- 缺点:控制复杂。
- 对比:
线性流水线与非线性流水线
(按照流水线中是否有反馈回路来进行分类)
- 线性流水线:流水线的各段串行连接,没有反馈回路。数据通过流水线中的各段时,每一个段最多只流过一次。
- 非线性流水线:流水线中除了有串行的连接外,还有反馈回路。
- 非线性流水线的调度问题
- 确定什么时候向流水线引进新的任务,才能使该任务不会与先前进入流水线的任务发生冲突——争用流水段。
-
- 非线性流水线的调度问题
顺序流水线与乱序流水线
(根据任务流入和流出的顺序是否相同来进行分类)
- 顺序流水线:流水线输出端任务流出的顺序与输入端任务流入的顺序完全相同。每一个任务在流水线的各段中是一个跟着一个顺序流动的。
-乱序流水线:流水线输出端任务流出的顺序与输入端任务流入的顺序可以不同,允许后进入流水线的任务先完成(从输出端流出)。也称为无序流水线、错序流水线、异步流水线
标量处理机与向量流水处理机
把指令执行部件中采用了流水线的处理机称为流水线处理机。
- 标量处理机:处理机不具有向量数据表示和向量指令,仅对标量数据进行流水处理。
- 向量流水处理机:具有向量数据表示和向量指令的流水线处理机,简称向量机。
- 向量数据表示和流水技术的结合。
3.2 流水线的性能指标
3.2.1 吞吐率(TP:ThroughPut) ⭐
在单位时间内流水线所完成的任务数量或输出结果的数量。
T P = n T k TP = \frac{n}{T_k} TP=Tkn
n n n: 流水线中的任务数量
T k T_k Tk:处理完成n个任务所用的时间
各段时间均相等的流水线
(假设一条k段线性流水线)
完成第一个任务所需要的时间:
k
∗
Δ
t
k*\Delta{t}
k∗Δt
完成第二个任务到第n个任务结束所需要的时间:
(
n
−
1
)
∗
Δ
t
(n-1)*\Delta{t}
(n−1)∗Δt
流水线完成n个连续任务所需要的总时间为:
T k = k ∗ Δ t + ( n − 1 ) ∗ Δ t = ( k + n − 1 ) ∗ Δ t T_k = k * \Delta{t} + (n-1)*\Delta{t} = (k+n-1)*\Delta{t} Tk=k∗Δt+(n−1)∗Δt=(k+n−1)∗Δt
流水线的实际吞吐率
T P = n ( k + n − 1 ) Δ t T P=\frac{n}{(k+n-1) \Delta t} TP=(k+n−1)Δtn
最大吞吐率 ⭐
T P max = lim n → ∞ n ( k + n − 1 ) Δ t = 1 Δ t T P_{\max }=\lim _{n \rightarrow \infty} \frac{n}{(k+n-1) \Delta t}=\frac{1}{\Delta t} TPmax=n→∞lim(k+n−1)Δtn=Δt1
最大吞吐率与实际吞吐率的关系
T P = n k + n − 1 T P max T P=\frac{n}{k+n-1} T P_{\max } TP=k+n−1nTPmax
流水线的实际吞吐率小于最大吞吐率, 它除了与每个段的时间有关外, 还与流水线的段数 k以及输入到流水线中的任务数 $\mathrm{n} $等有关。
只有当
n
>
k
n>k
n>k 时, 才有 $T P \approx \mathrm{TP}_{\max } $ 。
各段时间完全不相等的流水线
一条4段的流水线,S1,S3,S4各段的时间:Δt,S2的时间:3Δt
流水线中这种时间最长的段称为流水线的瓶颈段。
完成第一个任务所需要的时间:Δt+3Δt+Δt+Δt = 6Δt
完成第二个任务到第n个任务结束所需要的时间:(n-1)3Δt
各段时间不等的流水线的实际吞吐率为:
( Δ t i \Delta\mathrm{t}_{\mathrm{i}} Δti为第 i 段的时间, 共有 $ \mathrm{k} $个段 )
T P = n ∑ i = 1 k Δ t i + ( n − 1 ) max ( Δ t 1 , Δ t 2 , ⋯ , Δ t k ) T P=\frac{n}{\sum_{i=1}^{k} \Delta t_{i}+(n-1) \max \left(\Delta t_{1}, \Delta t_{2}, \cdots, \Delta t_{k}\right)} TP=∑i=1kΔti+(n−1)max(Δt1,Δt2,⋯,Δtk)n
流水线的最大吞吐率为:
T P max = 1 max ( Δ t 1 , Δ t 2 , ⋯ Δ t k ) T P_{\max }=\frac{1}{\max \left(\Delta t_{1}, \Delta t_{2}, \cdots \Delta t_{k}\right)} TPmax=max(Δt1,Δt2,⋯Δtk)1
取决于瓶颈段的时间
解决流水线瓶颈问题的常用方法
-
细分瓶颈段
-
-
重复设置瓶颈段
- 重复设置的段并行工作,时间上依次错开处理任务。
- 缺点:控制逻辑比较复杂,所需的硬件增加了。
3.2.2 流水线的加速比 ⭐
加速比:完成同样一批任务,不使用流水线所用的时间与使用流水线所用的时间之比。
假设:不使用流水线(即顺序执行)所用的时 间为 $\mathrm{T}{\mathrm{s}} $ ,使用流水线后所用的时间为 $\mathrm{T}{\mathrm{k}} $ ,则该 流水线的加速比为:
S = T s T k S=\frac{T_{s}}{T_{k}} S=TkTs
流水线各段时间相等:
一条k段流水线完成n个连续任务
所需要的时间为:
T k = ( k + n − 1 ) Δ t \mathrm{T}_{\mathrm{k}} = (\mathrm{k}+\mathrm{n}-1) \Delta \mathrm{t} Tk=(k+n−1)Δt
顺序执行n个任务
所需要的时间: $ T_{s} = n k \Delta t $
流水线的实际加速比为:
S = n k k + n − 1 S = \frac{n k}{k+n-1} S=k+n−1nk
最大加速比:
S max = n k k + n − 1 = k S_{\max } = \frac{nk}{k+n-1} = k Smax=k+n−1nk=k
当 n > > k 时 , S ≈ k 当n>>k时,S≈k 当n>>k时,S≈k
流水线的各段时间不完全相等时
一条 k 段流水线完成 n 个连续任务的实际加速比为:
S = n ∑ i = 1 k Δ t i ∑ i = 1 k Δ t i + ( n − 1 ) max ( Δ t 1 , Δ t 2 , ⋯ , Δ t k ) S=\frac{n \sum_{i=1}^{k} \Delta t_{i}}{\sum_{i=1}^{k} \Delta t_{i}+(n-1) \max \left(\Delta t_{1}, \Delta t_{2}, \cdots, \Delta t_{k}\right)} S=∑i=1kΔti+(n−1)max(Δt1,Δt2,⋯,Δtk)n∑i=1kΔti
3.2.3 流水线的效率 ⭐
流水线的效率:流水线中的设备实际使用时间与整个运行时间的比值,即流水线设备的利用率。
由于流水线有通过时间和排空时间,所以在连续完成n个任务的时间内,各段并不是满负荷地工作。
各段时间相等
-
各段的效率 e i e_i ei相同
e 1 = e 2 = ⋯ = e k = n Δ t T k = n k + n − 1 e_{1}=e_{2}=\cdots=e_{k}=\frac{n \Delta t}{T_{k}}=\frac{n}{k+n-1} e1=e2=⋯=ek=TknΔt=k+n−1n -
整条流水线的效率为:
E = e 1 + e 2 + ⋯ + e k k = k e 1 k = k n Δ t k T k E=\frac{e_{1+} e_{2}+\cdots+e_{k}}{k}=\frac{k e_{1}}{k}=\frac{k n \Delta t}{k T_{k}} E=ke1+e2+⋯+ek=kke1=kTkknΔt
可以写成:
E = n k + n − 1 E=\frac{n}{k+n-1} E=k+n−1n
-
最高效率为:
E max = lim n → ∞ n k + n − 1 = 1 E_{\max }=\lim _{n \rightarrow \infty} \frac{n}{k+n-1}=1 Emax=n→∞limk+n−1n=1
当 n > > k 时 , E ≈ 1 当 n>>k 时, \mathrm{E} \approx 1 当n>>k时,E≈1
-
当流水线各段时间相等时,流水线的效率与吞吐率成正比。
- E = T P ⋅ Δ t E = TP · \Delta{t} E=TP⋅Δt
- E = n k + n − 1 T P = n ( k + n − 1 ) Δ t \quad E=\frac{n}{k+n-1} \quad T P=\frac{n}{(k+n-1) \Delta t} E=k+n−1nTP=(k+n−1)Δtn
-
流水线的效率是流水线的实际加速比 S 与它的最大加速 比 k 的比值。
-
E = S k S = n k k + n − 1 E=\frac{S}{k} \quad S=\frac{n k}{k+n-1} E=kSS=k+n−1nk
-
当 E = 1 \mathrm{E}=1 E=1 时, S = k \mathrm{S}=\mathrm{k} S=k , 实际加速比达到最大。
-
-
从时空图上看,效率就是n个任务占用的时空面积和k个段总的时空面积之比。
- E = n 个 任 务 实 际 占 用 的 时 空 去 k 个 段 中 的 时 空 区 E = \frac{n个任务实际占用的时空去}{k个段中的时空区} E=k个段中的时空区n个任务实际占用的时空去
-
各段时间不相等时
E = n ⋅ ∑ i = 1 k Δ t i k [ ∑ i = 1 k Δ t i + ( n − 1 ) ⋅ max ( Δ t 1 , Δ t 2 , ⋯ , Δ t k ) ] E=\frac{n \cdot \sum_{i=1}^{k} \Delta t_{i}}{k\left[\sum_{i=1}^{k} \Delta t_{i}+(n-1) \cdot \max \left(\Delta t_{1}, \Delta t_{2}, \cdots, \Delta t_{k}\right)\right]} E=k[∑i=1kΔti+(n−1)⋅max(Δt1,Δt2,⋯,Δtk)]n⋅∑i=1kΔti
3.2.5 流水线设计中的若干问题
瓶颈问题 ⭐
- 理想情况下,流水线在工作时,其中的任务是同步地每一个时钟周期往前流动一段。
- 当流水线各段不均匀时,机器的时钟周期取决于瓶颈段的延迟时间。
- 在设计流水线时,要尽可能使各段时间相等。
流水线的额外开销 ⭐
流水寄存器延迟 时钟偏移开销
-
流水寄存器需要建立时间和传输延迟
-
建立时间:在触发写操作的时钟信号到达之前,寄存器输入必须保持稳定的时间。
-
传输延迟:时钟信号到达后到寄存器输出可用的时间。
-
-
时钟偏移开销
流水线中,时钟到达各流水寄存器的最大差值时间。(时钟到达各流水寄存器的时间不是完全相同) -
注:
- 流水线并不能减少(而且一般是增加)单条指令的执行时间,但却能提高吞吐率。
- 增加流水线的深度(段数)可以提高流水线的性能。
- 流水线的深度受限于流水线的额外开销。
- 当时钟周期小到与额外开销相同时,流水已没意义。因为这时在每一个时钟周期中已没有时间来做有用的工作。
冲突问题—流水线设计中要解决的重要问题之一 ⭐
-
运算操作的数据准备
-
指令操作的相互关联
3.3 非线性流水线的调度
在非线性流水线中,存在反馈回路,当一个任务在流水线中流过时,可能要多次经过某些段
流水线调度要解决的问题:
应按什么样的时间间隔向流水线输入新任务,才能既不发生功能段使用冲突,又能使流水线有较高的吞吐率和效率?
3.3.1 单功能非线性流水线的最优调度
非线性流水线的启动距离:向一条非线性流水线的输入端连续输入两个任务之间的时间间隔称为非线性流水线的启动距离
禁用启动距离:会引起非线性流水线功能段使用冲突的启动距离则称为禁用启动距离
启动距离和禁用启动距离一般都用时钟周期数来表示,是一个正整数。
预约表:
戴文森提出使用预约表来对流水线的任务进行优化调整和控制。
横向(向右):时间(一般用时钟周期表示)
纵向(向下):流水线的段
如果在第n个时钟周期使用第k段,则在第k行和第n列的交叉处的格子里有一个√。
如果在第k行和第n列的交叉处的格子里有一个√,则表示在第n个时钟周期要使用第k段。
根据预约表求得最佳调度方案的方法 ⭐
-
根据预约表写出禁止表F
-
禁止表:一个由禁用启动距离构成的集合
-
具体方法: 对于预约表的每一行的任何一对✔,用它们所在的列号相减(大的减小的),列出各种可能的差值,然后删除相同的,剩下的就是禁止表的元素
-
在该图中为:
- 第一行的差值只有一个:8;
- 第二行的差值有3个:1,5,6;
- 第3行只有一个√,没有差值;
- 第4和第5行的差值都只有一个:1;
- 其禁止表是:F= { 1,5,6,8 }
-
-
根据禁止表F写出初始冲突向量 C 0 C_0 C0
进行从一个集合到一个二进制位串的变换- 冲突向量:一个N位的二进制位串
- 设
C
0
C_0
C0 =
(
c
N
,
c
N
−
1
,
⋅
⋅
⋅
,
c
2
,
c
1
)
(c_N,c_{N-1},···,c_2,c_1)
(cN,cN−1,⋅⋅⋅,c2,c1),则当
i
i
i在禁止表中时,
c
i
=
1
c_i = 1
ci=1否则为0,即为:
- c i = 0 c_i=0 ci=0:允许间隔i个时钟周期后送入后续任务
- c i = 1 c_i=1 ci=1:不允许间隔i个时钟周期后送入后续任务
- 对于上面的例子:F = { 1,5,6,8 },所以 C 0 = ( 10110001 ) C_0 = (10110001) C0=(10110001)
-
根据初始冲突向量 C 0 C_0 C0画出状态转换图
- 当第一个任务流入流水线后,初始冲突向量C0决定了下一个任务需间隔多少个时钟周期才可以流入。
- 在第二个任务流入后,新的冲突向量为:假设第二个任务是在与第一个任务间隔j个时钟周期流入,这时,由于第一个任务已经在流水线中前进了j个时钟周期,其相应的禁止表中各元素的值都应该减去j,并丢弃小于等于0的值。-----也就是:对冲突向量来说,就是逻辑右移j位(左边补0)。 在冲突向量上,就是对它们的冲突向量进行“或”运算
- 更一般的情况
- 对于所有允许的时间间隔都按上述步骤求出其新的冲突向量,并且把新的冲突向量作为当前冲突向量,反复使用上述步骤,直到不再产生新的冲突向量为止。
- 具体方法:从初始冲突向量C0出发,反复应用上述步骤,可以求得所有的冲突向量以及产生这些向量所对应的时间间隔。由此可以画出用冲突向量表示的流水线状态转移图。
- 有向弧:表示状态转移的方向
- 弧上的数字:表示引入后续任务(从而产生新的冲突向量)所用的时间间隔(时钟周期数)
- 对于上面的例子有:
-
-
-
对于其他新向量,也照此处理。
-
- 对于 9 + 9^+ 9+的解释为:对于每个状态来说,只要等待9个时钟周期,那么它的码就变为000000000,这时与初始状态进行或运算,那么得到的自然也就是初始状态
-
-
根据状态转换图写出最优调度方案
- 根据流水线状态图,由初始状态出发,任何一个闭合回路即为一种调度方案。
- 列出所有可能的调度方案,计算出每种方案的平均时间间隔,从中找出其最小者即为最优调度方案。
-
- 所以,最短的就是(3+4)/2 = 3.5
- 方案(3,4)是一种不等时间间隔的调度方案,与等间隔的调度方案相比,在控制上要复杂得多。为了简化控制,也可以采用等间隔时间的调度方案,但吞吐率和效率往往会下降不少。
3.4 流水线的相关与冲突
3.4.1 一条经典的5段流水线
以RISC流水线为例
一条指令的执行过程分为以下5个周期 ⭐
- 取指周期(IF:Instruction Fetch)
- 以程序计数器PC中的内容作为地址,从存储器中取出指令并放入指令寄存器IR
- 同时PC值加4(假设每条指令占4个字节),指向顺序的下一条指令
- 指令译码/读寄存器周期(ID:Instruction Decode)
- 将IR中的指令拆分成操作码和操作数,并将操作数放入寄存器
- 对指令进行译码,并用指令寄存器中的寄存器地址去访问通用寄存器组,读出所需的操作数。
- 执行/有效地址计算周期(EX:Execute)
- load和store指令:ALU把指令中所指定的寄存器的内容与偏移量相加,形成访存有效地址。
- 寄存器-寄存器ALU指令:ALU按照操作码指定的操作对从通用寄存器组中读出的数据进行运算。
- 寄存器-立即数ALU指令:ALU按照操作码指定的操作对从通用寄存器组中读出的操作数和指令中给出的立即数进行运算。
- 分支指令:ALU把指令中给出的偏移量与PC值相加,形成转移目标的地址。同时,对在前一个周期读出的操作数进行判断,确定分支是否成功。
- 存储器访问/分支完成周期(MEM:Memory Access)
- 该周期处理的指令只有load、store和分支指令。其它类型的指令在此周期不做任何操作。
- load和store指令
- load指令:用上一个周期计算出的有效地址从存储器中读出相应的数据
- store指令:把指定的数据写入这个有效地址所指出的存储器单元。
- 分支指令:分支“成功”,就把转移目标地址送入PC。分支指令执行完成。
- 写回周期(WB:WriteBack)
- ALU运算指令和load指令在这个周期把结果数据写入通用寄存器组。
- ALU运算指令:结果数据来自ALU。
- load指令:结果数据来自存储器。
- ALU运算指令和load指令在这个周期把结果数据写入通用寄存器组。
流水线实现
-
每一个周期作为一个流水段,在各段之间加上锁存器
-
采用流水线方式实现时,应该注意的问题
- 要保证不会在同一时钟周期要求同一个功能段做两件不同的工作。
- 避免IF段的访存(取指令)与MEM段的访存(读/写数据)发生冲突。
- 可以采用分离的指令存储器和数据存储器;一般采用分离的指令Cache和数据Cache。
- ID段和WB段都要访问同一寄存器文件
- 解决方法:把写操作安排在时钟周期的前半拍完成,把读操作安排在后半拍完成。
- 考虑PC的问题
- 流水线为了能够每个时钟周期启动一条新的指令,就必须在每个时钟周期进行PC值的加4操作,并保留新的PC值。这种操作必须在IF段完成,以便为取下一条指令做好准备。----->设置专门的加法器
- 但分支指令也可能改变PC的值,而且是在MEM段进行,这会导致冲突。
5段流水线的两种描述方式
-
第一种:
-
第二种:
3.4.2 相关与流水线冲突
相关 ⭐
相关:两条指令之间存在某种依赖关系。
如果两条指令相关,则它们就有可能不能在流水线中重叠执行或者只能部分重叠执行。
相关的3种类型:
- 数据相关
- 名相关
- 控制相关
数据相关
对于两条指令i(在前)和j(在后),如果下述条件之一成立,则称指令j与指令i数据相关。
- 指令j使用指令i产生的结果
- 指令j与指令k数据相关,而指令k又与指令i数据相关(数据相关具有传递性)
- 数据相关反映了数据的流动关系,即如何从其产生者流动到其消费者。
例如:
当数据的流动是经过寄存器时,相关的检测比较直观和容易。
当数据的流动是经过存储器时,检测比较复杂。
- 相同形式的地址其有效地址未必相同(10(R5))
- 形式不同的地址其有效地址却可能相同
名相关
名:指令所访问的寄存器或存储器单元的名称
如果两条指令使用相同的名,但是它们之间并没有数据流动,则称这两条指令存在名相关。
指令j与指令i之间的名相关有两种:
- 反相关:如果指令j写的名与指令i读的名相同,则称指令i和j发生了反相关。
指令j写的名=指令i读的名 - 输出相关:如果指令j和指令i写相同的名,则称指令i和j发生了输出相关。
指令j写的名=指令i写的名
名相关的两条指令之间并没有数据的传送。
如果一条指令中的名改变了,并不影响另外一条指令的执行。.
换名技术:通过改变指令中操作数的名来消除名相关。
对于寄存器操作数进行换名称为寄存器换名
寄存器换名既可以用编译器静态实现,也可以用硬件动态完成.
这里面存在数据相关也存在名相关
控制相关
控制相关是指由分支指令引起的相关。
为了保证程序应有的执行顺序,必须严格按控制相关确定的顺序执行。
- 控制相关带来了以下两个限制:
- 与一条分支指令控制相关的指令不能被移到该分支之前。否则这些指令就不受该分支控制了。
- 对于上述的例子,then部分中的指令不能移到if语句之前。
- 如果一条指令与某分支指令不存在控制相关,就不能把该指令移到该分支之后。
- 对于上述的例子,不能把S移到if语句的then部分中
- 与一条分支指令控制相关的指令不能被移到该分支之前。否则这些指令就不受该分支控制了。
冲突 ⭐
流水线冲突是指对于具体的流水线来说,由于相关的存在,使得指令流中的下一条指令不能在指定的时钟周期执行。
流水线冲突有3种类型:
结构冲突
因硬件资源满足不了指令重叠执行的要求而发生的冲突。
- 在流水线处理机中,为了能够使各种组合的指令都能顺利地重叠执行,需要对功能部件进行流水或重复设置资源。
- 如果某种指令组合因为资源冲突而不能正常执行,则称该处理机有结构冲突。
- 常见的导致结构冲突的原因
- 功能部件不是完全流水
- 资源份数不够
- 结构冲突举例:访存冲突
-
- 有些流水线处理机只有一个存储器,将数据和指令放在一起,访存指令会导致访存冲突。
- 解决方法:
- 解决办法Ⅰ:插入暂停周期(“流水线气泡”或“气泡”)
-
- 解决方法Ⅱ:设置相互独立的指令存储器和数据存储器或设置相互独立的指令Cache和数据Cache。
- 解决办法Ⅰ:插入暂停周期(“流水线气泡”或“气泡”)
-
- 有时流水线设计者允许结构冲突的存在(减少成本)
- 如果把流水线中的所有功能单元完全流水化,或者重复设置足够份数,那么所花费的成本将相当高。
数据冲突
当指令在流水线中重叠执行时,因需要用到前面指令的执行结果而发生的冲突。
- 当相关的指令靠得足够近时,它们在流水线中的重叠执行或者重新排序会改变指令读/写操作数的顺序,使之不同于它们串行执行时的顺序,则发生了数据冲突。
-
- 数据冲突三种分类:
- 写后读冲突(RAM)
- 在i写入之前,j先去读。j 读出的内容是错误的。
- 这是最常见的一种数据冲突,它对应于真数据相关。
- 写后写冲突(WAW)
- 在i写入之前,j先写入。最后写入的内容是i,这个结果是错误的。
- 这种冲突对应于输出相关
- 写后写冲突仅发生在这样的流水线中:
- 流水线中不只一个段可以进行写操作;
- 指令被重新排序了。
- 前面介绍的5段流水线不会发生写后写冲突。因为只有在WB段才会写回寄存器,所以不会发生
- 读后写冲突(WAR)
- 在i读之前,j先写。i读出的内容是错误的!
- 由反相关引起。
- 这种冲突仅发生在这样的情况下
- 有些指令的写结果操作提前了,而且有些指令的读操作滞后了;
- 指令被重新排序了。
- 写后读冲突(RAM)
- 定向技术:减少写后读数据冲突引起的停顿:(旁路/短路)
- 在计算结果尚未出来之前,后面等待使用该结果的指令并不一定立即需要该计算结果,如果能够将该计算结果从其产生的地方直接送到其它指令需要它的地方,那么就可以避免停顿。
-
- 实现原理:
- EX段和MEM段之间的流水寄存器中保存的ALU运算结果总是回送到ALU的入口。
- 当定向硬件检测到前一个ALU运算结果写入的寄存器就是当前ALU操作的源寄存器时,那么控制逻辑就选择定向的数据作为ALU的输入,而不采用从通用寄存器组读出的数据。
- 结果数据不仅可以从某一功能部件的输出定向到其自身的输入,而且还可以定向到其它功能部件的输入。
- 需要停顿的数据冲突:
-
- 因为load指令需要在访存阶段才能够拿到这个数据,而下一条指令在执行阶段就要用到,此时无法传递过去,必须要停顿
-
- 解决措施:
- 增加流水线互锁机制,插入“暂停”。作用:检测发现数据冲突,并使流水线停顿,直至冲突消失。
-
- 指令调度/流水线调度
- 依靠编译器解决数据冲突
- 让编译器重新组织指令顺序来消除冲突,这种技术称为指令调度或流水线调度。
-
- 到考试的时候一定要在草纸上画一下这个图:
-
控制冲突
流水线遇到分支指令和其它会改变PC值的指令所引起的冲突。
- 执行分支指令的结果有两种:
- 分支成功:PC值改变为分支转移的目标地址
- 不成功或失败:PC值保持正常递增,指向顺序的下一条指令
- 处理分支指令最简单的方法:
- 冻结/排空流水线
-
- 由分支指令引起的延迟成为分支延迟
- 减少分支延迟的措施:
- 在流水线中尽早判断出分支转移是否成功
- 尽早计算出分支目标地址
假设分支指令是在ID段的末尾进行执行的,所带来的分支延迟为一个时钟周期,则有:
- 3种 通过软件(编译器) 来减少分支延迟的方法
- 共同点:
- 对分支的处理方法在程序的执行过程中始终是不变的,是静态的
- 要么总是预测分支成功,要么总是预测分支失败
- 预测分支失败
- 允许分支指令后的指令继续在流水线中流动,就好象什么都没发生似的;
- 若确定分支失败,将分支指令看作是一条普通指令,流水线正常流动;
- 若确定分支成功,流水线就把在分支指令之后取出的所有指令转化为空操作,并按分支目地重新取指令执行。
- 要保证:分支结果出来之前不能改变处理机的状态,以便一旦猜错时,处理机能够回退到原先的状态。
-
- 预测分支成功
- 假设分支转移成功,并从分支目标地址处取指令执行。
- 起作用的前题:先知道分支目标地址,后知道分支是否成功。
- 注:此方法在之前的5段流水线中没有任何好处
- 延迟分支
- 主要思想:从逻辑上“延长”分支指令的执行时间。把延迟分支看成是由原来的分支指令和若干个延迟槽构成,不管分支是否成功,都要按顺序执行延迟槽中的指令。
-
- 分支延迟槽中的指令“掩盖”了流水线原来必需插入的暂停周期。
- 分支延迟指令的调度
- 任务:在延迟槽中放入有用的指令由编译器完成。能否带来好处取决于编译器能否把有用的指令调度到延迟槽中。
- 三种调度方法:
- 从前调度
- 从目标处调度
- 从失败处调度
-
-
- 分支延迟受到两个方面的限制:
- 可以被放入延迟槽中的指令要满足一定的条件;
- 编译器预测分支转移方向的能力。
- 分支取消机制
- 分支指令隐含了预测的分支执行方向,当分支的实际执行方向和事先所预测的一样时,执行分支延迟槽中的指令,否则就将分支延迟槽中的指令转化成一个空操作。
-
-
- 共同点:
3.5 流水线的实现
不做重点,不讲