vault backup: 2026-06-16 21:34:37
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
---
|
||||
tags:
|
||||
- 计算机系统结构
|
||||
- 重点复习
|
||||
- 流水线
|
||||
- 控制冲突
|
||||
create time: 2026-06-16 21:21
|
||||
---
|
||||
|
||||
# 小题 3 — 控制冲突的解决措施
|
||||
|
||||
## 概述
|
||||
|
||||
本题考查流水线中**控制冲突**(Control Hazard)的概念,以及为**减少分支指令引起的延迟**所采取的有效措施。控制冲突是流水线三大冲突之一,理解其解决方案对理解现代处理器设计至关重要。
|
||||
|
||||
> [!tip] 考试重点
|
||||
> 重点掌握三大类解决措施:**暂停**、**预测**、**延迟分支**。其中延迟分支的"延迟槽"概念和分支预测的基本原理是常考知识点。
|
||||
|
||||
## 正文
|
||||
|
||||
### 一、什么是控制冲突?
|
||||
|
||||
**控制冲突**(Control Hazard)是由**分支指令**(如 if-else、循环跳转)引起的。当处理器执行分支指令时,需要等到分支结果确定后才能知道下一条应该取哪里的指令。但在等待期间,流水线已经预取了后续指令——如果预测错误,这些预取的指令就必须作废。
|
||||
|
||||
```mermaid
|
||||
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%。如果每条分支指令都暂停 2~3 拍,流水线效率将下降 30%~75%。这就是为什么必须采用预测技术。
|
||||
|
||||
#### 3.2 分支预测(Branch Prediction)
|
||||
|
||||
在分支结果确定之前,**预测**分支方向并提前取指。预测分为两大类:
|
||||
|
||||
| 预测类型 | 方法 | 预测准确率 | 硬件复杂度 |
|
||||
|----------|------|:----------:|:----------:|
|
||||
| **静态预测** | 编译时确定,运行时不变 | 60%~70% | 低 |
|
||||
| **动态预测** | 运行时根据历史信息动态调整 | 90%~95% | 高 |
|
||||
|
||||
**静态预测的常见策略**:
|
||||
|
||||
| 策略 | 预测行为 | 适用场景 |
|
||||
|------|----------|----------|
|
||||
| 总是预测不跳转 | 分支不发生,继续顺序取指 | 循环体外的分支 |
|
||||
| 总是预测跳转 | 分支发生,跳转到目标地址 | 循环体内的分支(循环通常继续) |
|
||||
| 根据分支方向预测 | 向后跳转预测为跳转(循环),向前跳转预测为不跳转 | 通用场景 |
|
||||
| 由编译器标注 | 编译器在分支指令中设置预测位 | Profile-guided 优化 |
|
||||
|
||||
**动态预测的常见策略**:
|
||||
|
||||
| 策略 | 原理 | 状态数 |
|
||||
|------|------|:------:|
|
||||
| 1 位预测器 | 记录上次分支结果 | 2 |
|
||||
| 2 位饱和计数器 | 需要连续 2 次预测错误才改变方向 | 4 |
|
||||
| 相关预测器 | 参考其他分支的历史 | 4+ |
|
||||
| 锦标赛预测器 | 多个预测器投票 | 多 |
|
||||
|
||||
```mermaid
|
||||
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)延迟分支**:编译器在分支指令后的延迟槽中填入必定执行的指令。
|
||||
|
||||
## 关联笔记
|
||||
- [[计算机系统结构/复习文档/流水线技术]]
|
||||
- [[小题2-流水线的分类]]
|
||||
- [[小题4-流水寄存器的作用]]
|
||||
Reference in New Issue
Block a user