指令流水线的基本概念
前五节讲的是”怎样把一条指令做对”。从这一节开始,问题换成”怎样把很多条指令做快”——这是5.1.1 立的第二条主线的起点。
做对和做快是两个独立的问题,这一点必须先立住:流水线不改变任何一条指令的语义,也不改变任何一条指令的执行结果。它改变的只有一件事——同一时刻有多少条指令正在被处理。
机制
从”串行”到”重叠”
5.2.3 已经把一条指令切成了若干阶段。非流水线的做法是:一条指令走完全部阶段,下一条才开始。
指令1: [取指][译码][执行][访存][写回]
指令2: [取指][译码][执行][访存][写回]
每一时刻只有一个部件在工作,其余四个全部闲着。 这是纯粹的浪费——取指部件在译码阶段完全没事干。
流水线的做法:让每个部件一直有活干。
指令1: [取指][译码][执行][访存][写回]
指令2: [取指][译码][执行][访存][写回]
指令3: [取指][译码][执行][访存][写回]
指令4: [取指][译码][执行][访存][写回]
从第 5 拍开始,五个部件同时在为五条不同的指令工作。
这就是流水线的全部思想:不是让单件事变快,而是让所有工位同时开工。工厂装配线是同一个道理——一辆车的组装时间没变,但下线速度变成了每个工位周期一辆。
吞吐率与延迟:必须分开的两个量
这是本节最需要焊死的区分,5.6 后面四节全部依赖它。
| 延迟(Latency) | 吞吐率(Throughput) | |
|---|---|---|
| 定义 | 一条指令从进入到完成的时间 | 单位时间完成的指令条数 |
| 流水线后 | 不变,甚至略增(多了段间寄存器的延迟) | 提高约 |
| 对应公式里的 | 单条指令的执行时间 |
为什么延迟反而会略增:切成
单条指令走完
这个区分是很多说法的判据来源:
- “流水线使指令执行速度提高了 5 倍” → 说法不严谨,提高的是吞吐率
- “流水线降低了 CPI” → 对,理想情况下 CPI 从
降到 1 - “流水线缩短了程序执行时间” → 对,因为程序有很多条指令
时空图
横轴时间、纵轴指令,是流水线所有计算题的作图工具。
| 指令 \ 时钟 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|
| I1 | IF | ID | EX | MEM | WB | |||
| I2 | IF | ID | EX | MEM | WB | |||
| I3 | IF | ID | EX | MEM | WB | |||
| I4 | IF | ID | EX | MEM | WB |
三段读法:
| 阶段 | 时钟范围 | 特征 |
|---|---|---|
| 建立(填充) | 第 1 ~ | 流水线还没装满,部分段空闲 |
| 稳定(满载) | 第 | 每拍完成一条指令 |
| 排空 | 最后 | 不再有新指令进入 |
这个式子是 5.6.4 全部性能公式的起点,必须能直接写出来。
流水线的分类
四组分类,考试主要考后两组的辨析。
| 分类依据 | 类别 | 说明 |
|---|---|---|
| 层次 | 部件级(运算操作流水线) | 把一次浮点加分成对阶、尾数加、规格化等段 |
| 处理机级(指令流水线) | 本节讨论的就是它 | |
| 处理机间级(宏流水线) | 多个处理机各处理一道工序 | |
| 功能数 | 单功能流水线 | 只能完成一种固定功能 |
| 多功能流水线 | 各段可重新连接以完成不同功能 | |
| 连接方式 | 静态流水线 | 同一时间只能按一种功能连接 |
| 动态流水线 | 同一时间可按多种功能连接,各段可同时为不同功能服务 | |
| 是否有反馈 | 线性流水线 | 每段只经过一次 |
| 非线性流水线 | 有反馈回路,某段可被多次使用 |
静态 / 动态只对多功能流水线才有意义——单功能流水线只有一种连法,无从”静”或”动”。这是这组分类最容易被问的一点。
“动态流水线”和后面 5.6.5 的”动态调度(乱序执行)“是两个不同的概念,中文里都带”动态”,容易串。前者说的是各段能否同时服务于不同功能,后者说的是硬件能否按运行时依赖打乱指令顺序。
流水线成立的三个条件
不是任何任务都能流水化,需要满足:
- 各段的时间应尽量相等——否则
被最慢段绑架,快的段大量空闲 - 各段之间要有缓冲(段间寄存器)——存放上一段的结果,供下一段使用
- 各段的功能部件必须独立——不能两段共用同一个部件,否则每拍都会冲突
第 1 条是”要整齐就得按最慢的来”在本章的第四次出现(前三次见 5.4.2)。它是RISC 设计的直接动机:指令定长、格式规整、只有 Load/Store 访存——这三条都是为了让五段的时间尽量接近。
第 3 条是结构冒险的来源,见 5.6.3。它也解释了为什么流水线 CPU 必须用专用数据通路而不是总线结构(5.3.3):总线是全局共享的,天然违反”各段独立”。
指令集对流水线的要求
这一节是 4.4.2 那三条 RISC 特征的收口。
| RISC 的特征 | 对流水线的好处 |
|---|---|
| 定长指令 | IF 段时间固定;PC 增量是常数,不必等译码(4.1.3) |
| 格式规整、寄存器号位置固定 | ID 段可以在译码的同时就去读寄存器,不必先知道是哪条指令 |
| 只有 Load/Store 访存 | 只有一个段(MEM)需要访存,各段时间容易拉齐 |
| 寻址方式少 | 地址计算统一放在 EX 段,不需要额外的间址周期 |
第二条最微妙:正因为寄存器号总在同一位置,ID 段可以并行地做两件事——译码器在看操作码的同时,寄存器堆已经按固定位置的字段去取数了。若指令格式不规整,就必须先译码知道是哪条指令、寄存器号在哪,才能去取——ID 段就要被拆成两拍。
这正是 4.1.4 那条主线的最终收口:变长编码省了空间,代价是”必须先译码才知道下一步做什么”,而在流水线上,这个代价直接表现为段数变多、或者某一段被迫串行化。
边界
边界辨析:吞吐率 / 延迟
- 吞吐率:单位时间完成多少条指令 → 流水线提高它
- 延迟:一条指令从头到尾的时间 → 流水线不缩短它,甚至略增
说”流水线加快了指令的执行速度”是含糊的;准确说法是加快了指令的完成速率。
边界辨析:静态流水线 / 动态流水线
边界辨析:流水线的段数 / 指令周期的阶段数
5.2.1 的四个阶段(取指/间址/执行/中断)是逻辑划分,与流水线的五段(IF/ID/EX/MEM/WB)不是同一套划分。
流水线的分段依据是”各段时间尽量相等且部件独立”,与逻辑阶段无关。别把两套名字混用。
对照速查
| 说法 | 判断 |
|---|---|
| 流水线提高了吞吐率 | ✅ |
| 流水线缩短了单条指令的执行时间 | ❌ 甚至略增 |
| 流水线降低了 CPI | ✅ 理想情况下降到 1 |
| 段数越多性能越好 | ❌ 段间寄存器开销 + 冒险代价,见 5.6.4 |
| 静态流水线可以同时按多种功能连接 | ❌ 那是动态流水线 |
| 单功能流水线分静态和动态 | ❌ 只有多功能才分 |
| 流水线各段时间应尽量相等 | ✅ 三个成立条件之一 |
| 流水线需要段间寄存器 | ✅ |
考点
- 吞吐率与延迟的分辨:几乎每年都以某种形式出现。
- 画时空图:横轴时钟、纵轴指令,注意填充与排空。
- 总时间公式
:一切性能计算的起点。 - 静态 / 动态流水线辨析:只对多功能流水线有意义。
- 流水线成立的三个条件:段时间相等、有缓冲、部件独立。
- RISC 的哪些特征有利于流水:定长、规整、Load/Store、寻址方式少,每条都要能说出对应的好处。
链接
- 🏠 返回总览:计算机组成原理第 5 章:中央处理器总览
- ⬅️ 上一节:5.5.3 异常和中断响应过程
- ➡️ 下一节:5.6.2 流水线的基本实现
- 🔗 三种执行方案:5.2.3 指令执行方案
- 🔗 RISC 的配套设计:4.4.2 RISC 的基本概念
- 📖 名词库:第 5 章名词库