💡 Core Concept (英文速记)
Pipelining improves performance by increasing instruction throughput (the number of instructions completed per unit time) through overlapping the execution of multiple instructions in different stages.
📂 1. 流水线的基本原理与阶段 (Pipeline Stages)
流水线技术(Pipelining)是一种将指令执行过程分解为多个独立子步骤,并让多条指令在不同执行阶段重叠执行以提高处理器吞吐率的硬件并行技术。
在经典的 MIPS 5级流水线 中,一条指令的生命周期被划分为以下五个阶段:
| 阶段 | 英文简称 | 功能描述 (Functionality) |
|---|---|---|
| 取指 | IF (Instruction Fetch) | 根据程序计数器(PC)的值从指令存储器中读取指令,并计算 。 |
| 译码 | ID (Instruction Decode) | 对指令进行译码,同时从通用寄存器堆中读取源操作数,并进行分支目标的计算与控制信号生成。 |
| 执行 | EX (Execute) | 使用算术逻辑单元(ALU)进行运算。若是访存指令则计算有效内存地址,若是分支指令则计算分支条件。 |
| 访存 | MEM (Memory Access) | 若是加载(Load)指令则从数据存储器中读取数据,若是存储(Store)指令则将数据写入数据存储器。 |
| 写回 | WB (Write Back) | 将执行阶段或访存阶段得到的结果数据写回到目的寄存器中。 |
流水线时空图示例 (Overlapping Execution)
通过在不同阶段重叠执行多条指令,流水线可以实现每个时钟周期完成一条指令的理想状态():
时钟周期 -> CC1 CC2 CC3 CC4 CC5 CC6 CC7 CC8 CC9指令 1 (I1) IF ID EX MEM WB指令 2 (I2) IF ID EX MEM WB指令 3 (I3) IF ID EX MEM WB指令 4 (I4) IF ID EX MEM WB📊 2. 流水线性能评估 (Performance Evaluation)
评估流水线处理器性能通常使用以下三个核心指标:吞吐率、加速比 和 效率。
1. 吞吐率 (Throughput, TP)
吞吐率是指单位时间内流水线完成的指令条数。 若流水线在时间 内完成了 条指令,则吞吐率为:
假设一个 级流水线,每个阶段的延迟(时钟周期)为 ,在没有冒险(Hazards)的理想情况下,完成 条指令所需的总时间为:
此时,实际吞吐率为:
当指令条数 时,最大极限吞吐率趋近于:
TIP吞吐率的本质:流水线并不能缩短单条指令的执行时间(甚至因为插入流水线寄存器而稍微增加单条指令的延迟),但它通过重叠执行极大地提高了单位时间内完成的指令数量。
2. 加速比 (Speedup, S)
加速比是指不使用流水线(顺序执行)与使用流水线执行相同指令序列的时间比值:
同样,当指令条数 时,最大极限加速比趋近于流水线级数 :
3. 效率 (Efficiency, E)
效率是指流水线设备的利用率。由于流水线存在建立期(前 个周期)和排空期,各部分的硬件并未在整个过程中完全占满。 时空图中,效率等价于指令占用的时空区面积与总时空区面积之比:
⚔️ 3. 流水线冒险与消除 (Pipeline Hazards)
在实际处理器中,受制于资源和指令依赖关系,流水线无法一直保持每个周期流出一条指令的理想状态。阻碍流水线正常流动的情况称为流水线冒险(Pipeline Hazards),主要分为三类:
1. 结构冒险 (Structural Hazards)
- 成因:多条指令在同一时钟周期内争夺同一个硬件资源。
- 经典场景:单端口存储器架构中,第 条指令在 MEM 阶段 读取/写入数据,而第 条指令在 IF 阶段 同时尝试读取指令,发生端口冲突。
- 解决对策:
- 资源复制:将统一的存储器拆分为独立的指令存储器(Instruction Memory)和数据存储器(Data Memory),或在 L1 缓存中采用独立的 I-Cache 和 D-Cache。
- 流水线挂起:让冲突指令暂停一个周期(Stall / Bubble)。
2. 数据冒险 (Data Hazards)
- 成因:后面的指令需要使用前面指令尚未写回寄存器的计算结果(发生数据依赖关系)。
- 冒险分类:
- RAW (Read-After-Write,写后读):最常见,后面的指令尝试读取前面指令还没写入的值。
- WAR (Write-After-Read,读后写) 和 WAW (Write-After-Write,写后写):在乱序执行(Out-of-Order)中可能出现,在经典顺序 MIPS 流水线中不会发生。
- 解决对策:
- 数据旁路 / 前送技术 (Data Bypassing / Forwarding):将前序阶段(如 EX 阶段的 ALU 输出或 MEM 阶段的访存结果)计算好的数据,直接通过旁路多路复用器直接送往后面指令的 EX 阶段输入端,从而无需等待 WB 阶段写回寄存器。
- 加载-使用冒险 Stall (Load-Use Stall):如果前序指令是
Load指令,由于数据要在 MEM 阶段结束时才准备好,后面的使用指令即使有 Forwarding 也必须挂起 1 个周期。 - 编译器调度 (Compiler Scheduling):通过重新排列无依赖指令来填充 Stall 空隙。
3. 控制冒险 (Control Hazards)
- 成因:由于分支指令(Branch/Jump)在较晚的阶段(如 ID 或 EX 阶段)才能决定下一条指令的实际跳转目标地址,此时流水线已经提前取出了后续的顺序指令,导致取错指令。
- 解决对策:
- 分支预测 (Branch Prediction):
- 静态预测:一律预测不跳转(Predict Not Taken)或根据历史静态方向预测。
- 动态预测:使用分支预测缓冲(BPB/BHT)或分支目标缓冲(BTB)记录历史跳转记录进行动态预测。
- 延迟分支 (Delayed Branch):编译器将一条与分支无关的指令放入分支指令后面的“延迟槽(Delay Slot)”中,无论分支是否跳转,延迟槽中的指令都会被执行。
- 硬挂起:在分支结果确定前,挂起流水线。
- 分支预测 (Branch Prediction):