Skip to content

流水线冒险与解决方案

考情分析

流水线冒险是408考研综合题的核心考点,常见题型:分析指令序列中存在的相关类型、计算需要插入几个气泡、画出时空图。数据冒险尤其是 RAW 相关最为常考。

三类冒险概述

冒险类型根本原因常见解决方法
结构冒险硬件资源冲突增加硬件、资源复制
数据冒险指令间数据依赖转发、阻塞
控制冒险分支/跳转改变PC延迟分支、分支预测

结构冒险(Structural Hazard)

定义:两条指令在同一时钟周期争用同一硬件资源。

典型场景:

  • lw 指令在 MEM 阶段访问数据存储器,而后续指令的 IF 阶段也需要访问存储器
    • 解决:指令存储器和数据存储器分开(哈佛结构),或分时复用(插入气泡)
  • 寄存器堆在 WB 阶段写、ID 阶段读同时发生
    • 解决:寄存器堆支持前半周期写、后半周期读(写优先),或转发

数据冒险(Data Hazard)

定义:后续指令需要用到前面指令尚未产生的结果。

三种数据相关类型

类型全称定义示例
RAW(写后读)Read After Write指令 j 读取指令 i 将要写入的寄存器I1: ADD R1,R2,R3 → I2: SUB R4,R1,R5
WAR(读后写)Write After Read指令 j 写某寄存器,而指令 i 还需要读它的旧值I1: ADD R3,R1,R2 → I2: SUB R1,R4,R5
WAW(写后写)Write After Write指令 j 和指令 i 写同一寄存器,程序语义要求 j 的结果是最终值I1: ADD R1,R2,R3 → I2: SUB R1,R4,R5

顺序流水线中只有 RAW 是实际问题——因为读操作(ID阶段)总在写操作(WB阶段)之前,后面指令的 ID 可能比前面指令的 WB 更早执行。

乱序(非按序)流水线中三种相关都可能出现:

  • WAR:若 I2 因乱序先完成写回,I1 就会读到错误的新值(本该读旧值)
  • WAW:若 I1 因乱序后完成写回,R1 的最终值变成 I1 的结果而非 I2 的(违反程序语义)

WAR 和 WAW 也被称为"名相关"(name dependence),因为它们的本质不是数据流依赖,而是两条指令恰好使用了同一个寄存器名。可以通过寄存器重命名技术消除——将逻辑寄存器映射到不同的物理寄存器,使得两条指令实际操作不同的存储位置。

RAW 示例

I1: ADD R1, R2, R3    # R1 = R2 + R3,EX阶段结束(第3周期)才有结果
I2: SUB R4, R1, R5    # 需要读 R1(ID阶段在第3周期,但R1还没写回)

若不处理,I2 在 ID 阶段读到的 R1 是旧值,结果错误。

解决方案一:阻塞(Stall / 插入气泡)

在 I2 的 ID 阶段之前插入"气泡"(NOP),等 I1 的结果写回后再让 I2 继续。

I1:  IF  ID  EX  MEM  WB
I2:  IF  ** ** ID   EX  MEM  WB   (* 表示气泡)
  • 对 RAW 相关,通常需要插入 2 个气泡(若无转发)
  • 优点:实现简单;缺点:性能损失大

解决方案二:数据转发(Forwarding / Bypassing)

将 ALU 运算结果直接从 EX/MEM 阶段的流水线寄存器旁路(bypass)给下一条指令的 EX 阶段,不等写回寄存器堆。

I1:  IF  ID  EX →MEM  WB
I2:  IF  ID  EX ↑    (EX阶段从旁路获取I1的EX输出)

大部分 RAW 相关可通过转发解决,不需要插入气泡。

例外:lw-use 相关(load-use hazard)

I1: lw  R1, 0(R2)     # R1的值在MEM阶段结束后才有
I2: ADD R3, R1, R4    # I2的EX阶段需要R1

lw 的数据在 MEM 阶段才得到,而 I2 的 EX 阶段在 MEM 之前,转发来不及。此时必须插入 1 个气泡

I1:  IF  ID  EX  MEM →WB
I2:  IF  ID  ** EX ↑  MEM  WB   (* 表示1个气泡)

控制冒险(Control Hazard)

定义:遇到分支或跳转指令时,流水线不知道下一条指令从哪里取,已经取入流水线的后续指令可能是错误的。

问题示意

BEQ R1, R2, target   # IF  ID  EX ...(EX阶段才确定是否跳转)
I2:                  # 已经开始 IF(可能取错)
I3:                  # 已经开始 IF(可能取错)

解决方案一:延迟分支(Delayed Branch)

将分支指令之后的一条或多条指令定义为"延迟槽",这些指令无论分支是否发生都会执行。编译器负责将有用指令填入延迟槽(或填 NOP)。

解决方案二:分支预测

静态预测

  • 总是预测分支不发生(Always-Not-Taken):适合前向分支(if 条件跳转,通常不跳转)
  • 总是预测分支发生(Always-Taken):适合后向分支(循环回边,通常跳转)
  • 基于跳转方向预测(向后跳转预测发生,向前跳转预测不发生)——综合了以上两者

动态预测

  • 1位预测器:记录上次分支是否发生,本次按上次结果预测
  • 2位预测器(饱和计数器):状态机有4个状态(强发生/弱发生/弱不发生/强不发生),需要连续预测错误两次才改变预测方向
2位预测器状态机:
强发生(11) ←→ 弱发生(10) ←→ 弱不发生(01) ←→ 强不发生(00)
  ↑发生        发生↑↓不发生    发生↑↓不发生       ↓不发生

预测错误时:将已取入流水线的错误指令清除(flush),性能损失约等于分支延迟槽的数量。

交互可视化

加载可视化中...
加载可视化中...

例题

例1:以下指令序列在五段式流水线中,假设无旁路机制,SUB需要暂停几个周期?

ADD R1, R2, R3
SUB R4, R1, R5

解:ADD 在 T5(WB) 写回 R1,SUB 原本在 T3(ID) 读 R1。ID 必须等 WB 完成后才能读到正确值(若寄存器堆支持同周期前写后读,则 SUB 的 ID 可在 T5 执行)。原本 SUB 的 ID 在 T3,推迟到 T5,暂停 2个周期

例2:以下指令序列,有旁路机制时是否需要暂停?

LW  R1, 0(R2)
AND R3, R1, R4

解:LW 的 MEM 阶段结束时(T4末)数据才可用,AND 的 EX 阶段开始时(T4初)就需要 R1。时序上差一个周期,旁路无法解决。仍需暂停 1个周期,之后从 MEM/WB 寄存器旁路取得数据。

例3:某程序分支指令占 20%,采用2位预测器准确率 90%,预测错误代价 2 个周期。求因分支导致的额外 CPI。

解:额外 CPI = 0.20×(10.90)×2=0.20×0.10×2=0.04

若基础 CPI = 1,则实际 CPI = 1.04。

易混淆知识点

1. RAW/WAR/WAW 什么时候需要处理?

按序流水线只需处理 RAW(因为 ID 在 WB 之前,后面指令可能提前读)。WAR 和 WAW 在按序流水线中不会出现问题——因为指令严格按程序顺序经过各阶段,写操作的先后顺序天然正确。只有在乱序执行的处理器中,WAR 和 WAW 才会成为真正的问题。

2. 转发能解决所有 RAW 吗?

不能。lw-use 相关(load 后面紧跟使用该数据的指令)必须插入 1 个气泡,因为 lw 在 MEM 阶段末尾才拿到数据,而下一条指令的 EX 阶段在同一周期开始,时序上来不及。

3. 分支预测错误的代价到底是几个周期?

取决于分支结果在哪个阶段确定。若在 EX 阶段确定(标准五段),已取入 2 条错误指令,代价 = 2 周期。若硬件将分支判断提前到 ID 阶段,代价降为 1 周期。

考点清单

  • 顺序流水线中实际需要处理的只有 RAW 和控制冒险
  • 乱序流水线中 RAW/WAR/WAW 都可能出现,WAR 和 WAW 可通过寄存器重命名消除
  • lw-use 相关是数据冒险中唯一转发也无法完全消除的,必须插入1个气泡
  • 一般 RAW 相关(ALU指令间)可以通过转发解决,不需要气泡
  • 2位预测器优于1位:如循环体最后一次迭代预测错误,但不会影响下次循环开始的预测
  • 结构冒险通过分离指令存储器和数据存储器解决(这就是为什么流水线CPU使用哈佛结构)

真题练习

相关真题(8题)

2024Q19选择题2分

流水线数据冒险的处理方式辨析

2024Q43综合题13分

指令格式、数据通路与流水线综合题

2023Q19选择题2分

流水线中转发与阻塞的综合判断

2019Q18选择题2分

流水线中数据冒险的判断

2016Q19选择题2分

无转发机制下流水线数据冒险的判断

2014Q16选择题2分

指令Cache与数据Cache分离的原因

2014Q44综合题12分

循环程序的指令序列与流水线执行分析综合题

2010Q19选择题2分

流水线阻塞的原因与转发技术