流水线冒险

流水线操作可以通过并行地执行指令来隐藏指令的延迟,但也会产生一些潜在的问题——通常称为流水线冒险(pipeline hazards),即下一条指令无法在下一个时钟周期执行的情况。

这种情况可能通过多种方式发生:

  • 当两个或多个指令需要CPU的同一部分(例如执行单元)时,就会发生结构冒险(structural hazard)。

  • 当必须等待从前面的某个步骤计算而得的操作数时,就会发生数据冒险(data hazard)。

  • 当CPU无法判断下一步需要执行哪些指令时,就会发生控制冒险(control hazard)。

解决冒险的唯一方法是流水线停滞(pipeline stall):停止之前所有步骤的进度,直到阻塞的原因消失。这会在流水线中产生气泡(bubbles)——类似于流体管道中的气泡——即执行单元处于空闲状态且没有做任何有用功的一种时间传递状态。

不同的冒险有不同的代价:

  • 在结构冒险中,你必须等待(通常再等待一个周期),直到执行单元准备就绪。它们是性能的基本瓶颈,无法避免——你在设计代码时不得不与其同行。
  • 在数据冒险中,你必须等待计算所需的数据(关键路径(critical path)的延迟)。可以通过重构计算过程来解决数据冒险,从而缩短关键路径。
  • 在控制冒险中,通常必须刷新(flush)整个流水线并重新开始,浪费整个15-20个周期。它们可以通过完全删除分支或使分支可预测来解决,这样CPU就可以有效地预测下一步将执行什么。

由于它们对性能的影响非常不同,我们将按照相反的顺序,从影响最严重的冒险开始介绍。