流水线中的相关和冒险
并行需要解耦依赖,依赖又称相关性。当俩个事件存在相关性而同时执行就有可能产生冒险(Hazard)。程序上下指令间存在天然的依赖性,指令间的依赖性可用数据依赖图表示,而流水线同时执行多条指令必然要面对冒险的问题。
在数字电路中也有冲突冒险的概念,也表示对公共资源的冲突,此文的冒险则侧重于流水线并行中的冒险概念。
相关性
产生冒险一定相关,相关不一定产生冒险。分析相关的粒度到指令级,和流水线的粒度保持一致。
- 数据相关:数据流间的相关性。“输入A-指令A-输出A”,“输入B-指令B-输出B”,指令B的输入是指令A的输出,二者构成数据相关。依赖关系可以传递,数据相关关系可以构成相关链“指令A-指令B-指令C”…… 这是逻辑上的相关联系。数据相关指令必须按顺序执行。
- 名称相关:“伪相关”的一种,寄存器名称冲突但数据上不存在冲突,可通过在软件或硬件上实现寄存器重命名消除
- 控制相关:分支的相关冲突。
流水线粒度
以流水线单元为粒度分析冲突是冒险。
- 数据流
- 数据冒险
- 控制流
- 分支冒险
- 硬件资源
- 结构冒险
数据冒险
数据相关必须按照原本顺序执行,但按照顺序执行不一定代表不会发生冲突。由于流水线并行俩个顺序指令挨着很近发生重叠,仍有可能冲突。指令A先于指令B执行,根据发生冲突的不同位置划分如下:
指令 B \ 指令 A | 输入(R) | 输出(W) |
---|---|---|
输入(R) | - | RAW |
输出(W) | WAR | WAW |
比如 RAW 冒险,指令 A 先于指令 B 执行,按理说 B 应该能正确读取到 A 的输出,但是由于 pipeline ,B 读取输入时 A 还没有输出,造成了冒险。对于 RAW,分为俩种情况,B 读取时输入时 A 已经产生了输出数据,只是没有存储到寄存器里,此时可以引入额外的数据旁路解决(数据转发);若 B 读取时 A 还没产生输出,只能插入气泡停顿等待数据生成。
分支冒险
即下一条指令依赖上一条指令的分支结果,一般可以引入分支预测解决。
结构冒险
在 pipeline 不同阶段对某个相同硬件资源访问冲突。
比如经典的五级流水线 IF-ID-EX-MEM-WB,各级对硬件资源的访问需求如下
Stage | Requirements |
---|---|
IF | 缓存读指令 |
ID | 读寄存器 |
EX | 数据总线 |
MEM | 缓存读写 |
WB | 写寄存器 |
比如如果 Register File 使用 Signal Port 实现,那么 ID 和 WB 可能会发生冒险,如果存在多发射结构,则 EX 多个执行单元会竞争数据总线等等。