CPU 流水线
CPU 流水线把指令处理分为取指、译码、执行、访存、写回五级,让不同指令同时占用不同级。流水线填满且没有停顿时,每周期可完成一条指令。它提高吞吐量;单条指令仍要走完五级,遇到相关还可能等待。
洗衣、烘干、折叠也能说明重叠执行。每项各占一个时隙,四批衣物逐批做完需要十二个时隙;第一批进烘干机时让第二批开始洗,四批只需六个时隙。单台机器没有变快,空闲时间减少了。CPU 用五级重叠执行,但后一条指令若需要前一条尚未产出的值,就必须处理这种依赖。
流水线如何工作
每条指令依次经过同样的五级:IF 读取指令字;ID 译码并读源寄存器;EX 执行 ALU 运算;MEM 访问数据内存;WB 写目标寄存器。本模型每周期发射一条指令,按程序顺序前进,不能超车,各级在时钟边沿交接。
数据问题来自 ID 读寄存器与 WB 写寄存器之间的距离。消费者已经进入 ID 时,前面的生产者可能尚未写回。此时读取寄存器会得到旧值。
无转发硬件时,相关检测把消费者留在 ID,直到值可用。这是停顿。消费者未进入 EX,便在后级形成向前移动的空位,也就是气泡。气泡代表数据依赖造成的额外周期,要与填充和排空的正常空闲区分。
无相关且无其他停顿时,n 条指令耗时 n+4 周期:初始填充开销四周期,随后每周期完成一条。五条需要九周期,而逐条执行需要二十五周期;五百条则为 504 对 2500。固定开销被更多指令分摊。
逐步演示
默认硬件只有停顿,没有转发。值必须写回寄存器后才能使用:
I1—add $t1, $s1, $s2I2—sub $t2, $s3, $s4I3—lw $t3, 0($s0)I4—or $t4, $t3, $t1I5—and $t5, $t4, $t2
前三条相互独立。I4 使用 I3 载入的 $t3,I5 使用 I4 算出的 $t4。
- 周期 1:I1 取指,其余四级为空,流水线开始填充。
- 周期 2:I1 译码,读取
$s1, $s2;I2 取指。 - 周期 3:I1 在 EX,I2 在 ID,I3 在 IF。
- 周期 4:I1 在 MEM,I2 在 EX,I3 在 ID,I4 在 IF。
- 周期 5:I1 在 WB,I2 在 MEM,I3 在 EX,I4 在 ID,I5 在 IF。五级同时有指令,但 I4 需要
$t3,I3 还没访存,要到周期 7 才写回。 - 周期 6、7:I4 留在 ID,I5 留在 IF,EX 两次没有新指令,产生两个气泡。周期 7,I3 在前半周期写
$t3,I4 在后半周期读,因此同周期读写合法,无须再等一周期。 - 周期 8:I4 带着正确
$t3进入 EX。I5 到 ID,又要等 I4 在周期 10 写回$t4。 - 周期 9、10:再停顿两个周期,增加两个气泡。
- 周期 11–13:只剩 I5,依次经过 EX、MEM、WB,完成排空。
五条指令共十三周期,比理想九周期多四个气泡,仍少于逐条执行的二十五周期。动画中空出的级框展示气泡,指令行中带虚线的重复 ID 展示等待。
数据相关、停顿与转发
写后读相关(RAW)不是程序错误。I4 本就可以使用 I3 的载入结果,硬件要保证读到正确值。
没有转发时,紧邻生产者的消费者要等两个周期;生产者再远一条,等待一个周期;相距三条时,生产者的 WB 与消费者的 ID 同周期,不用等。代价取决于值何时写回以及消费者何时读取。
转发也称旁路,把流水寄存器中的结果直接接到 EX 输入,省去等待写回再读出的过程。载入值在 MEM 结束时位于 MEM/WB 流水寄存器中,可在下一周期交给消费者的 EX。
切换硬件后,同样五条只需十周期。I4 在周期 7 的 EX 算出 $t4,旁路在周期 8 把它送入 I5 的 EX,因此这一 ALU 依赖不再停顿。
为什么转发仍有下限
剩下的一个停顿来自 load-use。ALU 结果在 EX 结束时出现,下一条在下周期 EX 使用,时间来得及;load 的数据到 MEM 结束才出现,而紧邻消费者想在同周期的 EX 使用,数据尚未到达。
在本课具备全部所需旁路、内存一周期响应的五级机器上,载入后紧接使用仍需一个停顿。lw / use pairs 预设有四条指令、两对紧邻载入与使用,产生两个气泡,从理想八周期变为十周期。
lw / use, rescheduled 保留相同两条载入、两条加法和结果,先安排两条载入,使每个载入与其使用之间隔一条无关指令。十周期变八周期,两个气泡消失。改变的是指令顺序,硬件没变。这是编译器指令调度填补等待空隙的方式;本课的顺序硬件不会自行寻找后面的独立工作。
每条都依赖前一条结果的五条 ALU 链,转发时九周期,不转发时十七周期,后者有八个气泡,每条平均 3.4 周期。
边界情况
- WB 与 ID 同周期:寄存器堆前半周期写、后半周期读,消费者不用停顿。这是设计约定;若不支持,默认运行会从 13 周期变成 15 周期,两次停顿各多一周期。
- 填充与排空:因为还没有指令取进来、或已没有指令可取而空出的级不是气泡;气泡是前后都有指令时空出的级。填充与排空是理想下限为
n+4的原因。长指令流能分摊这四周期开销。 - 依赖距离足够:I4 还读取 I1 写入的
$t1,两者相距三条。I4 到 ID 时 I1 已到 WB,不增加停顿。 - 指令独立:五条操作码若使用互不冲突的操作数,有无转发都耗时九周期。转发减少相关代价,不会突破这个模型的无相关下限。
- 一个消费者有两个生产者:I5 读取
$t4和$t2,等待较晚就绪的那个即可,不能把两项等待直接相加。
常见错误
- 认为流水线缩短每条指令的处理路径。五级仍要走完;收益要看多条指令的吞吐量,停顿还会增加单条延迟。
- 看见一次相关就只算一个周期。无转发的紧邻依赖在此模型要等两个周期,应从生产与消费时刻计算。
- 从 EX/MEM 旁路载入结果。
lw在该处只有 ALU 算出的地址,尚无内存数据;把地址当值会得到看似合理的错误结果。 - 认为停顿只影响当前指令。顺序流水线不能超车,后方指令也要停。
- 把图中三个 ID 框当成三次译码。它是一条指令在 ID 占了三周期,虚线标出重复等待。
模型范围
这是教材式 MIPS 五级顺序流水线。没有分支和跳转,控制相关由分支预测课说明;内存固定一周期,缓存未命中不会造成停顿;每周期按序发射一条,不模拟超标量或乱序执行。
实际处理器的流水深度与发射方式因设计而异,有些会达到十四至二十级。更深的流水线可能增加相关与误预测的代价,也使预测和转发更重要。本课用于理解这些技术的基础,不是当前设备微架构的说明。