首页/计算机组成原理/中央处理器/指令流水线 🔗 在 Obsidian 中打开
计算机组成原理 · 中央处理器

指令流水线

重要度 ⭐⭐⭐⭐⭐中央处理器数据冒险控制冒险结构冒险吞吐率CPU
速查
五级流水线 IF → ID → EX → MEM → WB;$n$ 条指令 $k$ 级流水共需 $(k+n-1)\Delta t$,加速比 $S=\dfrac{nk}{k+n-1}$。流水线不缩短单条指令延迟,只提高吞吐率

速查

项目
阶段取指 IF → 译码 ID → 执行 EX → 访存 MEM → 写回 WB
加速比$S = \dfrac{n \times k}{n+k-1}$,$n$ 为指令数,$k$ 为段数
吞吐率$TP = \dfrac{n}{T}$

核心概念

非流水线 vs 流水线

方式推进规则3 条指令(5 级)耗时
非流水线上一条全部完成后下一条才开始$3\times5 = 15$ 个周期
流水线每拍错开一级并行推进$5+3-1 = 7$ 个周期

经典五级流水线

阶段全称主要工作使用部件
IFInstruction Fetch按 PC 取指令,PC + 4指令存储器、PC、加法器
IDInstruction Decode译码,读寄存器堆,立即数扩展译码器、寄存器堆
EXExecuteALU 运算 / 计算有效地址 / 判分支ALU
MEMMemory Access访问数据存储器(仅 Load/Store)数据存储器
WBWrite Back结果写回寄存器堆寄存器堆写口
分段原则各段耗时应尽量均衡。流水线时钟周期由最慢的一段决定:$\Delta t = \max\{\Delta t_i\} + $ 锁存器延迟。木桶效应是流水线设计的第一约束。

流水线性能指标

吞吐率 TP(Throughput)

单位时间内流水线完成的指令数:

$$TP = \frac{n}{T_{\text{流}}} = \frac{n}{(k+n-1)\,\Delta t}$$

当 $n \to \infty$ 时,$TP \to \dfrac{1}{\Delta t}$,即最大吞吐率——每个时钟周期流出一条指令。

加速比 S(Speedup)

$$S = \frac{T_{\text{非流水线}}}{T_{\text{流水线}}} = \frac{n \times k \times \Delta t}{(k+n-1)\,\Delta t} = \frac{nk}{k+n-1}$$

当 $n \to \infty$ 时,$S \to k$,最大加速比等于流水线级数

效率 E(Efficiency)

时空图中"有效时空区"占"总时空区"的比例:

$$E = \frac{\text{有效时空区}}{\text{总时空区}} = \frac{S}{k} = \frac{n}{k+n-1}$$

当 $n \to \infty$ 时,$E \to 1$(100%)。

三者关系一句话$E = S / k$,且 $TP = E / \Delta t$。三个指标本质上都在描述同一件事:$(k-1)$ 个填充 / 排空周期被 $n$ 条指令摊薄的程度

计算例题

题目:5 级流水线,每级 100 ns,连续执行 100 条指令(无冒险),求非流水线时间、流水线时间、加速比、吞吐率、效率。

  • 非流水线时间:$100 \times 5 \times 100\,\text{ns} = 50000\,\text{ns}$
  • 流水线时间:$(5 + 100 - 1) \times 100\,\text{ns} = 10400\,\text{ns}$
  • 加速比:$S = 50000 / 10400 \approx \mathbf{4.81}$
  • 吞吐率:$TP = 100 / 10400\,\text{ns} \approx \mathbf{9.62 \times 10^6}$ 条 / 秒
  • 效率:$E = 4.81 / 5 \approx \mathbf{96.2\%}$
答题模板先写 $T_{\text{流}} = (k+n-1)\Delta t$ 这一步,其余三个指标全部由它推出;若题目给出各段不等长,则 $\Delta t$ 取最长段,且非流水线时间应按各段之和算而非 $k\Delta t$。

流水线冒险(Hazards)

类型根因主要对策
结构冒险硬件资源冲突哈佛结构 / 多端口 / 暂停
数据冒险指令间数据相关前递 / 暂停 / 编译调度
控制冒险PC 改变导致预取无效分支预测 / 延迟槽 / 提前判断

结构冒险(Structural Hazard)

两条指令在同一周期争用同一部件。典型场景:单端口存储器——指令 I1 处于 MEM 阶段访存,同时 I4 正在 IF 阶段取指,二者都要访问存储器。

解决方法:
1. 哈佛结构(指令 Cache 与数据 Cache 分开)  ← 最常用
2. 多端口存储器
3. 流水线暂停一拍(插入气泡)

数据冒险(Data Hazard)⭐

三种相关类型

类型全称示例说明
RAW写后读ADD R1,R2,R3SUB R4,R1,R5真相关,顺序流水线中唯一会真实发生的冒险
WAR读后写ADD R1,R2,R3SUB R2,R4,R5反相关,仅乱序执行时出现
WAW写后写ADD R1,R2,R3SUB R1,R4,R5输出相关,仅乱序执行时出现
为什么 RAW 会出问题ADD 要到 WB 阶段才把结果写入 R1,而 SUBID 阶段就要读 R1——此时 R1 还是旧值。

解决方法

  1. 插入气泡(Stall):暂停 1~2 个周期等结果写回。简单但降低性能。
  2. 数据前递 / 旁路(Forwarding / Bypassing):把 EX 或 MEM 阶段的中间结果通过专用数据通路直接送到后续指令的 EX 输入端,不必等 WB。可解决大部分 RAW 冒险。
  3. 编译器调度:重排指令顺序,在相关指令之间插入无关指令填补间隙。
前递解决不了的情形Load-Use 冒险LW R1,0(R2) 紧接 ADD R3,R1,R4。数据要到 MEM 结束才拿到,而下一条 EX 已经开始,即使前递也必须再停 1 拍

控制冒险(Control Hazard)⭐

分支 / 跳转指令改变 PC,流水线中已经预取的后续指令可能作废。

$$\text{分支代价(延迟损失)} = \text{分支结果确定的阶段序号} - 1$$

五种对策

方法做法代价
暂停等分支结果确定后再取指最简单也最慢
预测不跳转继续顺序取指猜对 0 代价,猜错清空流水线
预测跳转直接取目标地址指令需先算出目标地址
延迟槽分支后一条指令总是执行靠编译器填有用指令,否则填 NOP
动态分支预测用历史记录预测需 BHT / BTB 硬件开销

静态预测 vs 动态预测

  • 静态:总是不跳 / 总是跳 / 按方向预测(向后跳预测为跳转,对应循环,命中率高)。
  • 动态 · 1 位预测器:只记录上次结果,翻转时出错——循环的最后一次和重入的第一次都会预测错。
  • 动态 · 2 位饱和计数器00/01 预测不跳,10/11 预测跳;需要连续错两次才改变预测方向,抗抖动能力更强。

循环 $n$ 次时的预测准确率近似:

  • 1 位预测器:约 $(1 - 2/n)$(每轮循环错 2 次:退出 1 次 + 重入 1 次)
  • 2 位预测器:约 $(1 - 1/n)$(只在退出时错 1 次)

流水线的多发射

技术并行由谁负责核心特征CPI
超标量(Superscalar)硬件每拍取 / 发射多条指令,配多套功能部件可 < 1
超长指令字(VLIW)编译器把多条指令打包成一条超长指令,硬件按包并行执行可 < 1
超流水线(Superpipeline)硬件把每段再细分,提高时钟频率仍为 1

动态流水线调度(乱序执行)

乱序执行 Out-of-Order Execution:
  · 指令不必按程序顺序执行,只要操作数就绪即可进入执行
  · 结果通过重排序缓冲区 ROB 按原序提交(保证精确异常)
  · Intel / AMD 的现代 x86 处理器均采用
乱序 = 乱序执行 + 顺序提交正因为"顺序提交",程序员看到的结果仍与顺序执行一致;也正因为"乱序执行",WAR / WAW 这两类假相关才会显现,需要寄存器重命名来消除。

流水线寄存器

IF ID EX MEM WB IF/ID ID/EX EX/MEM MEM/WB 橙色竖条 = 流水线寄存器(锁存器),在每个时钟边沿把上一段结果传给下一段 五级流水线与四组流水线寄存器
图:$k$ 级流水线需要 $k-1$ 组流水线寄存器,用于隔离相邻各段
寄存器保存内容
IF/ID取回的指令、PC + 4
ID/EX读出的操作数、扩展后的立即数、控制信号
EX/MEMALU 结果、标志位、待写存储器的数据
MEM/WB从存储器读出的数据或 ALU 结果、写回寄存器号

为什么必须有流水线寄存器

  • 隔离各段:让每段在同一时刻处理不同指令而互不干扰;
  • 保存中间结果:本段算完的值必须锁存到下一拍才可用;
  • 防止数据串扰:避免组合逻辑的信号跨段"穿透"。
代价锁存器本身有建立 / 保持时间开销,因此 $\Delta t = \max\{\Delta t_i\} + t_{\text{锁存}}$。级数分得越细,锁存开销占比越大——这正是流水线深度不能无限增加的原因之一。

常见考法

  1. 时空图填写:给出指令序列和冒险条件,画出含气泡的时空图并数总周期数。
  2. 三大指标计算:$TP$ / $S$ / $E$ 套公式,注意各段不等长时 $\Delta t$ 取最长段。
  3. 判断冒险类型:给一段汇编,指出属于结构 / 数据(RAW/WAR/WAW)/ 控制冒险。
  4. 前递能否消除停顿:重点判断 Load-Use 这类必须停 1 拍的情形。
  5. 分支预测准确率:1 位 / 2 位预测器在循环中的错误次数。
  6. 超标量 vs VLIW:区分硬件并行与编译器并行。

易错点

必记
  1. 流水线不能减少单条指令的延迟,只能提高吞吐率——单条指令甚至因锁存开销略微变慢。
  2. 最大加速比 = 流水线级数 $k$(理论上限,$n\to\infty$ 才逼近)。
  3. 数据冒险中最常见、顺序流水线中唯一真实发生的是 RAW
  4. 前递能解决大部分数据冒险,但解决不了 Load-Use(必须停 1 拍)。
  5. 分支代价取决于分支结果在哪一阶段确定,把判断提前到 ID 段可把代价从 3 拍降到 1 拍。
  6. 2 位预测器比 1 位准确率高,因为需要连续两次错误才翻转预测。
  7. 超标量是硬件并行,VLIW 是编译器并行;超流水线只是把段分得更细,CPI 仍为 1。
  8. 流水线深度增加可提高主频,但同时加剧冒险惩罚、增大功耗,存在最优深度。

核心结论

  1. 流水线通过重叠执行提高吞吐率,理想情况下每拍流出一条指令。
  2. $T_{\text{流}} = (k+n-1)\Delta t$ 是一切性能公式的出发点。
  3. $S = \dfrac{nk}{k+n-1} \to k$,$E = S/k \to 1$,$TP \to 1/\Delta t$。
  4. 三类冒险分别源于资源冲突、数据相关、控制转移
  5. 前递是解决 RAW 的主力,Load-Use 仍需停顿一拍。
  6. 动态分支预测(2 位饱和计数器)是降低控制冒险代价的关键手段。
  7. 多发射(超标量 / VLIW)让 CPI 突破 1 的下限。
  8. $k$ 级流水线需要 $k-1$ 组流水线寄存器来隔离各段。

记忆卡片

五级流水线是哪五级?
IF 取指 → ID 译码 → EX 执行 → MEM 访存 → WB 写回。
$n$ 条指令 $k$ 级流水多久?
$(k+n-1)\Delta t$,其中 $k-1$ 是填充 / 排空开销。
流水线时钟周期由谁决定?
最慢的一段加上锁存器延迟(木桶效应)。
$S$、$E$、$TP$ 的关系?
$E = S/k$,$TP = E/\Delta t$,三者同源。
顺序流水线只会出现哪种数据相关?
RAW(真相关);WAR / WAW 只在乱序执行中出现。
前递唯一搞不定的冒险?
Load-Use:取数指令的结果 MEM 才出来,后一条 EX 已开始,必须停 1 拍。
2 位预测器为何更准?
需连续错两次才改变预测,能容忍循环边界的单次抖动。
超标量 vs VLIW?
超标量靠硬件动态调度多发射;VLIW 靠编译器静态打包。
$k$ 级流水要几组流水线寄存器?
$k-1$ 组,分别位于相邻两段之间。
流水线能缩短单条指令时间吗?
不能。它只提高吞吐率,单条指令延迟甚至略增。

交互动画 · 五级流水线时空图

手动模式
5 条指令 · 5 级流水线 · 共 (5+5-1)=9 个时钟周期 123 456 789 I1I2I3 I4I5 IF ID EX MEM WB IF ID EX MEM WB IF ID EX MEM WB IF ID EX MEM WB IF ID EX MEM WB
看图学公式时空图的总格数 $= n \times k = 25$ 是有效时空区;外接矩形 $= k \times (k+n-1) = 5\times 9 = 45$ 是总时空区。于是 $E = 25/45 \approx 55.6\%$——指令条数越多,左下 / 右上两个"三角空洞"被摊得越薄,效率越接近 1。

相关知识点

instruction-execution pipeline-hazard-detail pipeline-performance-analysis

↑ 以上为站内 HTML 相对链接(纯网页可浏览);本页右上「在 Obsidian 中打开」跳回源笔记。