Appearance
408 > ### 计算机组成原理 > #### CO-05-06 流水线冒险(数据冒险/控制冒险/结构冒险)
一、定位信息
| 项目 | 内容 |
|---|---|
| 所属章节 | 第5章 中央处理器 |
| 知识单元编号 | CO-05-06 |
| 主题 | 流水线冒险(数据冒险/控制冒险/结构冒险) |
| 考纲要求 | 掌握流水线冒险的类型、产生原因及解决方法 |
| 历年考查频率 | 高频(选择题必考+综合题高频) |
| 预计分值 | 4-8分(选择)/ 10-15分(综合) |
二、知识点讲解
1. 流水线冒险概述
流水线冒险(Hazard)是指在流水线执行过程中,由于指令之间的各种依赖关系或资源冲突,导致流水线无法在下一个时钟周期继续正常执行的情况。冒险会导致流水线停顿(Stall)或气泡(Bubble),降低流水线效率。
冒险分为三大类:
| 冒险类型 | 定义 | 根本原因 |
|---|---|---|
| 结构冒险 | 多条指令同时竞争同一硬件资源 | 硬件资源不足 |
| 数据冒险 | 后续指令需要用到前面指令尚未产生的数据 | 指令间的数据依赖 |
| 控制冒险 | 分支指令改变了程序执行的顺序 | 分支结果不确定 |
2. 结构冒险(Structural Hazard)
定义:当多条指令在同一时钟周期内需要使用同一硬件资源时,就产生了结构冒险。
典型场景:
- 指令存储器和数据存储器共用一个端口:IF阶段取指令和MEM阶段访存数据可能同时需要访问存储器。如果只有一个存储器端口,就会产生结构冒险。
- 寄存器组的读写端口不足:如果寄存器组只有一个读端口,而某些指令需要同时读两个寄存器,就会产生结构冒险。
解决方案:
- 资源复制(资源冗余):将冲突的硬件资源复制一份。例如,采用分离的指令Cache和数据Cache(哈佛结构),使取指和访存可以同时进行。
- 资源分时复用:在不同时钟周期使用同一资源。例如,某些周期暂停取指,让MEM阶段先完成访存。
- 增加端口:为寄存器组增加更多的读写端口。
3. 数据冒险(Data Hazard)
数据冒险是最常见的冒险类型,由指令之间的数据依赖关系引起。
数据冒险的三种类型:
(1)写后读冒险(RAW, Read After Write)
- 最常见的数据冒险
- 后面的指令需要读取前面指令还未写回的寄存器值
- 示例:如果ADD指令还在EX阶段,R1的新值尚未写回寄存器组,SUB指令在ID阶段读到的R1就是旧值。
ADD R1, R2, R3 ; R1 ← R2 + R3 SUB R4, R1, R5 ; R4 ← R1 - R5(需要用到R1的新值)
(2)写后写冒险(WAW, Write After Write)
- 两条指令都要写同一个寄存器,必须保证写入顺序正确
- 在顺序流水线中一般不会出现(因为写操作的顺序是确定的)
- 在乱序执行的流水线中可能出现
(3)读后写冒险(WAR, Write After Read)
- 后面的指令要写入的寄存器,前面的指令还在读
- 在顺序流水线中不会出现(因为读在ID阶段完成,写在WB阶段完成,顺序正确)
- 在乱序执行的流水线中可能出现
数据冒险的解决方案:
方案一:插入气泡(停顿/阻塞)
- 检测到数据冒险后,暂停后续指令的执行,等待数据准备好
- 通过旁路检测单元检测冒险,产生停顿信号(Stall Signal)
- 优点:简单可靠;缺点:降低性能
方案二:数据旁路/转发(Forwarding/Bypassing)
- 不等待数据写回寄存器组,而是通过专用通路将ALU的运算结果直接转发给后续指令的ALU输入端
- EX/MEM → EX转发:将EX阶段的运算结果直接转发给下一条指令的EX输入
- MEM/WB → EX转发:将MEM阶段的结果转发给后续指令的EX输入
- 旁路可以解决大部分RAW冒险,但不能解决所有情况
方案三:编译器调度(指令重排)
- 编译器在不改变程序语义的前提下,重新安排指令顺序,将产生数据的指令和使用数据的指令隔开足够远
- 优点:不需要额外硬件;缺点:依赖编译器能力
需要停顿的情况: 即使有旁路机制,Load-Use冒险仍然需要停顿。例如:
LW R1, 0(R2) ; 从内存加载到R1
ADD R3, R1, R4 ; 使用R1的值LW指令在MEM阶段结束后数据才可用,但ADD指令在EX阶段就需要R1的值。即使有旁路,也必须停顿1个周期(Load-Use Penalty)。
4. 控制冒险(Control Hazard)
定义:当遇到分支指令(条件跳转、无条件跳转等)时,流水线不知道下一条应该取哪条指令,直到分支指令执行完毕才能确定,这就产生了控制冒险。
产生原因:在5级流水线中,分支指令的目标地址和是否跳转的信息通常在EX阶段(甚至MEM阶段)才能确定,但取指阶段需要立即知道下一条指令的地址。
解决方案:
方案一:停顿(Stall)
- 遇到分支指令时,暂停流水线,等待分支结果确定后再继续取指
- 简单但浪费严重,分支指令后可能需要停顿2-3个周期
方案二:预测分支不跳转(Predict Not Taken)
- 假设分支不跳转,继续顺序取下一条指令
- 如果预测正确,没有性能损失
- 如果预测错误,需要清空(Flush)已进入流水线的错误指令,重新从正确地址取指
方案三:预测分支跳转(Predict Taken)
- 假设分支总是跳转到目标地址
- 需要提前计算分支目标地址
方案四:延迟分支(Delayed Branch)
- 分支指令之后的那条指令总是被执行(称为延迟槽/delay slot),无论分支是否跳转
- 编译器在延迟槽中填入有用的指令(无用时填NOP)
- 适用于RISC架构
方案五:动态分支预测
- 使用**分支历史表(BHT)**记录分支指令的历史行为
- 根据历史记录预测本次分支是否跳转
- 预测策略:1位预测器、2位预测器等
分支预测准确率对性能的影响:
- 假设分支指令占20%,预测准确率90%,误预测惩罚为2个周期
- 平均每条指令因分支预测错误增加的周期数 = 20% × 10% × 2 = 0.04个周期
- 如果预测准确率只有50%,则 = 20% × 50% × 2 = 0.2个周期,影响显著增大
5. 三种冒险的对比总结
| 对比维度 | 结构冒险 | 数据冒险 | 控制冒险 |
|---|---|---|---|
| 根本原因 | 硬件资源冲突 | 数据依赖关系 | 分支改变执行流 |
| 发生条件 | 资源不足 | RAW/WAR/WAW | 遇到分支指令 |
| 检测方式 | 资源使用表 | 寄存器号比较 | 指令类型判断 |
| 解决方法 | 资源复制/增加端口 | 旁路/停顿/编译器调度 | 预测/停顿/延迟分支 |
| 影响程度 | 现代处理器中较少见 | 最常见 | 影响显著 |
| 典型解决硬件 | 分离Cache | 转发通路/MUX | 分支预测器 |
三、记忆辅助
"结数控"三兄弟:结构冒险(争资源)、数据冒险(等数据)、控制冒险(猜方向)。记住三种冒险的根本原因。
RAW最常见:"先写后读"(RAW)是三种数据冒险中最常见的,也是408考试的重点。WAR和WAW在顺序流水线中一般不出现。
Load-Use必须停顿:即使有旁路机制,Load指令后紧跟使用该数据的指令,仍需停顿1个周期。这是因为Load的数据在MEM阶段才从内存读出,而下条指令在EX阶段就需要它。
分支预测口诀:"不跳继续取,跳转清气泡。"预测不跳转就继续顺序取指;预测错误就清空流水线中的错误指令(产生气泡)。
旁路不能解决所有数据冒险:旁路(Forwarding)能解决大部分RAW冒险,但Load-Use冒险必须停顿。记忆:"旁路万能?Load说不。"
四、例题精解
例题1
题目:考虑以下指令序列在5级流水线(IF/ID/EX/MEM/WB)上的执行,假设没有数据旁路机制。
(1) ADD R1, R2, R3
(2) SUB R4, R1, R5
(3) AND R6, R1, R7指令(2)需要等待指令(1)的执行结果,至少需要插入几个气泡?
四步解题:
第一步:审题——没有旁路机制,数据必须写回寄存器组后才能被后续指令读取。
第二步:分析指令间依赖:
- 指令(1) ADD的结果R1在WB阶段结束时才写入寄存器组
- 指令(2) SUB在ID阶段需要读取R1的值
- 指令(3) AND在ID阶段也需要读取R1的值
第三步:计算气泡数:
- 指令(1)在第5个周期(WB)结束时写入R1
- 指令(2)最早在第3个周期(ID)需要读R1
- 时间差 = 5 - 3 = 2个周期,所以需要插入2个气泡
- 对于指令(3):指令(1)在T5写入R1,指令(3)最早在T4(ID阶段)需要R1,也需要等1个周期。但因为指令(2)已经停顿了2个周期,指令(3)的实际ID阶段会被推迟,所以如果指令(2)停顿了,指令(3)自然也满足了时序要求。
第四步:答案——至少需要插入 2个气泡。
注:如果有旁路机制,指令(2)可以直接使用指令(1)在EX/MEM寄存器中的结果,不需要气泡。
例题2
题目:在5级流水线中,假设分支指令在EX阶段确定分支结果,采用"预测不跳转"策略。当分支实际发生跳转时,需要清空几条指令?
四步解题:
第一步:审题——分支指令在EX阶段确定结果,预测不跳转意味着继续顺序取指。
第二步:分析流水线状态:
- 周期T:分支指令在IF阶段
- 周期T+1:分支指令在ID阶段,同时下一条指令(顺序的)进入IF阶段
- 周期T+2:分支指令在EX阶段(此时才知道是否跳转),顺序的第2条指令进入IF阶段,顺序的第1条指令进入ID阶段
第三步:确定需要清空的指令: 当分支指令在T+2周期的EX阶段确定需要跳转时:
- 顺序的第1条指令已经进入了ID阶段(需要清空)
- 顺序的第2条指令已经进入了IF阶段(需要清空)
- 共2条指令需要清空
第四步:答案——需要清空 2条指令(产生2个气泡的惩罚)。
注:如果分支在MEM阶段才确定,则需要清空3条指令。
例题3
题目:考虑以下指令序列,分析是否存在数据冒险,若有,指出类型和解决方案。
(1) LW R1, 0(R2)
(2) ADD R3, R1, R4
(3) SW R3, 0(R5)四步解题:
第一步:审题——逐对检查指令间是否存在数据依赖。
第二步:分析各指令间的依赖:
- (1)→(2):指令(1)将内存数据加载到R1,指令(2)使用R1作为源操作数。这是RAW数据冒险。且(1)是Load指令,(2)紧随其后使用R1,构成Load-Use冒险。
- (2)→(3):指令(2)将结果写入R3,指令(3)使用R3作为源操作数(存入内存)。这也是RAW数据冒险。
第三步:确定解决方案:
- (1)→(2)的Load-Use冒险:即使有旁路机制,也需要停顿1个周期。Load的数据在MEM阶段才从内存读出,通过MEM/WB旁路可以转发给ADD的EX阶段,但ADD的EX阶段比Load的MEM阶段早1个周期,所以必须停顿1个周期。
- (2)→(3)的RAW冒险:可以通过EX/MEM旁路解决,将ADD在EX阶段的运算结果直接转发给SW的EX阶段(用于计算地址)和MEM阶段(用于存数据),不需要停顿。
第四步:答案:
- (1)→(2)存在Load-Use数据冒险(RAW类型),需停顿1个周期
- (2)→(3)存在RAW数据冒险,可通过旁路机制解决,无需停顿
五、考情分析
| 维度 | 说明 |
|---|---|
| 考查题型 | 选择题(冒险类型判断)+ 综合题(分析冒险/计算停顿周期/画流水线时空图) |
| 考查重点 | RAW冒险的识别与解决、旁路机制的工作原理、Load-Use冒险、分支预测 |
| 命题趋势 | 近年综合题常给出一段指令序列,要求分析冒险并画出流水线时空图 |
| 分值预估 | 选择题2-4分,综合题10-15分 |
| 复习建议 | 重点掌握数据冒险的三种类型和旁路机制,能够画出带停顿的流水线时空图 |
六、易错点
Load-Use冒险即使有旁路也需停顿:这是最常见的易错点。旁路不能解决所有数据冒险,Load-Use冒险必须停顿至少1个周期,因为Load数据在MEM阶段才可用,而下条指令在EX阶段就需要。
旁路的方向是向后的:旁路是将前面指令的结果转发给后面指令的输入端,不能反向使用。旁路通路通常是从EX/MEM寄存器或MEM/WB寄存器转发到EX阶段的ALU输入端。
WAR和WAW在顺序流水线中不出现:顺序执行的5级流水线中,读操作在ID阶段,写操作在WB阶段,不会出现WAR和WAW。只有在乱序执行的流水线中才需要考虑这两种冒险。
分支预测错误的惩罚周期数取决于分支结果确定的阶段:如果分支在EX阶段确定,惩罚为2个周期;如果在MEM阶段确定,惩罚为3个周期。做题时要根据题目给定的条件计算。
结构冒险在现代处理器中较少见:由于现代处理器普遍采用分离的指令Cache和数据Cache、多端口寄存器组等设计,结构冒险已经很少出现。但408考试中仍然会考查其概念和解决方法。
清空(Flush)≠ 停顿(Stall):停顿是让后续指令等待,保持已进入流水线的指令不变;清空是丢弃已进入流水线的错误指令,用NOP替换。分支预测错误时使用清空,数据冒险时使用停顿。
七、来源标注
| 来源 | 说明 |
|---|---|
| 主要教材 | 唐朔飞《计算机组成原理》第3版,第5章5.7节 |
| 辅助教材 | 袁春风《计算机组成与系统结构》第3版 |
| 考纲依据 | 全国硕士研究生招生考试计算机学科专业基础综合考试大纲(408) |
| 补充参考 | Patterson & Hennessy《计算机组成与设计》第4章 |