把指令处理分成阶段

指令流水线是中央处理器重叠处理多条指令的组织方式。它把取指、译码或读取操作数、执行、访存、写回等工作分到不同阶段,由级间寄存器保存中间结果。一条指令向后推进时,后续指令可以利用已经空出的前级,因此各硬件部分不必等待整条指令完成才开始下一项工作。

以理想五级、单发射模型为例,第一条指令在第五个周期结束时完成,此后若没有冲突,可以每周期完成一条。十条指令共需十四个周期,而不是五十个。这个算例假定各级每周期都能接收新工作,忽略了缓存未命中等停顿;它展示的是重叠带来的吞吐改善,不是某款处理器的实测速度。

参考:[1]

吞吐率不等于单条指令延迟

延迟衡量一条指令从进入到完成经历多久,吞吐率衡量单位时间完成多少条。流水化后,单条指令仍需走过多个阶段,级间保存和控制还会增加开销。只有阶段划分足够均衡,时钟周期才可能接近按级数缩短;实际周期受最慢阶段及寄存器时序约束,五级不能直接解释为五倍加速。

阶段数量也不是指令集统一规定的常数。Arm介绍的Cortex-M3核心采用取指、译码、执行三级,并在分支处理期间安排推测取指。教学中的五级数据通路则把访存、写回单列。它们说明同一原则可有不同实现,不能把一个模型的周期表套用于所有CPU。

参考:[1] [2]

重叠执行遇到的三类冒险

结构冒险来自同一时刻对有限硬件资源的竞争,例如取指和数据读取争用一个不能同时服务两者的存储端口。增加端口、分开通路或暂停其中一项工作,都是可能的处理方式。Cortex-M3采用分开的指令与数据总线,正体现了减少这类竞争的一种设计选择。

数据冒险则涉及指令间依赖:前一条加法还没写回寄存器,后一条减法已经要读它的结果。转发或旁路把已算出的值直接送往需要它的阶段,不必总等到正式写回;但若加载的数据尚未从存储器返回,转发也不能制造未产生的结果,此时仍可能插入气泡并暂停相关阶段。

参考:[2] [3]

控制流与性能边界

控制冒险发生在下一条指令的位置尚未确定时,例如条件分支的结果还在计算。处理器可以等待,也可以先预测方向执行;预测错误时必须舍弃不应执行的工作,恢复正确路径。流水线越深,不意味着这种损失自动消失。硬件中断和异常同样要求谨慎处理已进入流水线但尚未完成的指令。

指令流水线利用的是指令处理阶段的重叠,不等于创建多个线程,也不意味着每个阶段都独立运行一整个程序。评价它必须同时看时钟周期、平均每条指令所用周期和工作负载,尤其要计入依赖、分支与存储等待,而不能只比较级数。

参考:[1] [3]