Files
final-exam/计算机系统结构/重点复习/小题3-控制冲突的解决措施.md

6.8 KiB
Raw Permalink Blame History

tags, create time
tags create time
计算机系统结构
重点复习
流水线
控制冲突
2026-06-16 21:21

小题 3 — 控制冲突的解决措施

概述

本题考查流水线中控制冲突(Control Hazard)的概念,以及为减少分支指令引起的延迟所采取的有效措施。控制冲突是流水线三大冲突之一,理解其解决方案对理解现代处理器设计至关重要。

[!tip] 考试重点 重点掌握三大类解决措施:暂停、预测、延迟分支。其中延迟分支的"延迟槽"概念和分支预测的基本原理是常考知识点。

正文

一、什么是控制冲突?

控制冲突(Control Hazard)是由分支指令(如 if-else、循环跳转)引起的。当处理器执行分支指令时,需要等到分支结果确定后才能知道下一条应该取哪里的指令。但在等待期间,流水线已经预取了后续指令——如果预测错误,这些预取的指令就必须作废。

graph LR
    A["Branch Instruction"] --> B{"Branch Taken?"}
    B -- "Yes" --> C["Target Address"]
    B -- "No" --> D["PC + 4 (Next)"]

    style B fill:#ff9800

[!question] 控制冲突的代价有多大? 假设分支指令在 EX 段(第 3 段)确定结果,那么在 5 段流水线中,分支指令后面有 2 条指令已经被取入流水线。如果分支跳转了,这 2 条指令就要作废——浪费 2 个时钟周期。对于深度流水线(如 15~20 段),分支延迟更大。

二、解决措施总览

措施 原理 性能收益 硬件开销
暂停(Stall) 等待分支结果确定后再取指 无(性能最差) 无
预测(Predict) 猜测分支方向,提前取指 高(预测准确时) 中~高
延迟分支(Delayed Branch) 分支指令后的延迟槽总被执行 中等 低

三、措施详解

3.1 暂停(Stall)

最简单的方法:分支指令进入流水线后,暂停后续指令的取指,直到分支结果确定。

  • 优点:实现最简单,零硬件开销
  • 缺点:性能损失严重。对于 k 段流水线,分支在第 m 段确定结果时,浪费 m-1 个时钟周期

[!warning] 为什么暂停不可接受? 分支指令在程序中占比约 15%25%。如果每条分支指令都暂停 23 拍,流水线效率将下降 30%~75%。这就是为什么必须采用预测技术。

3.2 分支预测(Branch Prediction)

在分支结果确定之前,预测分支方向并提前取指。预测分为两大类:

预测类型 方法 预测准确率 硬件复杂度
静态预测 编译时确定,运行时不变 60%~70% 低
动态预测 运行时根据历史信息动态调整 90%~95% 高

静态预测的常见策略:

策略 预测行为 适用场景
总是预测不跳转 分支不发生,继续顺序取指 循环体外的分支
总是预测跳转 分支发生,跳转到目标地址 循环体内的分支(循环通常继续)
根据分支方向预测 向后跳转预测为跳转(循环),向前跳转预测为不跳转 通用场景
由编译器标注 编译器在分支指令中设置预测位 Profile-guided 优化

动态预测的常见策略:

策略 原理 状态数
1 位预测器 记录上次分支结果 2
2 位饱和计数器 需要连续 2 次预测错误才改变方向 4
相关预测器 参考其他分支的历史 4+
锦标赛预测器 多个预测器投票 多
stateDiagram-v2
    [*] --> StronglyNotTaken
    StronglyNotTaken --> WeaklyNotTaken: "Taken"
    WeaklyNotTaken --> WeaklyTaken: "Taken"
    WeaklyTaken --> StronglyTaken: "Taken"
    StronglyTaken --> WeaklyTaken: "Not Taken"
    WeaklyTaken --> WeaklyNotTaken: "Not Taken"
    WeaklyNotTaken --> StronglyNotTaken: "Not Taken"

[!note] 2 位饱和计数器的工作原理 2 位饱和计数器是最经典的动态预测方案:

  • 4 个状态:强不跳转(00)、弱不跳转(01)、弱跳转(10)、强跳转(11)
  • 预测规则:高位为 1 预测跳转,高位为 0 预测不跳转
  • 更新规则:分支跳转时计数器+1(饱和),不跳转时-1(饱和)
  • 优势:偶发的方向改变不会立即改变预测(需要连续 2 次才翻转),适合循环场景

3.3 延迟分支(Delayed Branch)

核心思想:编译器将分支指令后面的一条指令定义为延迟槽(Delay Slot),延迟槽中的指令无论分支是否跳转都会被执行。

BEQ  R1, R2, TARGET   ; 分支指令
ADD  R3, R4, R5       ; 延迟槽:总被执行
SUB  R6, R7, R8       ; 分支目标(如果跳转)

编译器的任务是找到一条安全的、有用的指令填入延迟槽:

填充策略 方法 效果
从前调度 将分支指令前面的独立指令移入延迟槽 最常用
从目标调度 将分支目标处的指令复制到延迟槽 适用于循环
从失败路径调度 将分支不跳转时的下一条指令移入延迟槽 适用于 if-else
填充 NOP 找不到合适指令时填空操作 无收益但保证正确性

[!question] 思考:延迟分支有什么局限?

  1. 只能补偿1 拍的分支延迟(延迟槽只有 1 条指令的空间)
  2. 对于深度流水线(延迟 2~3 拍),延迟分支力不从心
  3. 需要编译器配合,增加了编译器设计的复杂度

因此现代深度流水线处理器主要依靠动态分支预测,延迟分支主要用于简单 RISC 处理器。

四、三种措施的对比

对比维度 暂停 分支预测 延迟分支
性能 最差 最好 中等
硬件开销 无 中~高 低
需要编译器支持 否 否 是
适用流水线深度 浅 深/浅均可 浅(1~2 拍延迟)
预测错误时的处理 不需要 需要冲刷流水线 不需要
现代处理器使用 仅作后备 主要手段 辅助手段

[!abstract]- 答案 为减少分支指令引起的控制冲突延迟,采取的有效措施包括:

(1)暂停:等待分支结果确定后再取指,简单但性能最差。

(2)分支预测:静态预测(预测不跳转/预测跳转)和动态预测(1 位/2 位饱和计数器、相关预测器)。

(3)延迟分支:编译器在分支指令后的延迟槽中填入必定执行的指令。

关联笔记