--- tags: - 计算机系统结构 - 重点复习 - 指令级并行 - ILP create time: 2026-06-16 21:21 --- # 小题 5 — 指令级并发的开发方法 ## 概述 本题考查**指令级并行**(Instruction-Level Parallelism, ILP)的开发方法,包括**静态方法**(编译器主导)和**动态方法**(硬件主导)两大类。ILP 是提升单处理器性能的核心技术途径。 > [!tip] 考试重点 > 了解有哪些主要的 ILP 开发方法即可,重点区分"静态"和"动态"的分类及代表技术。不需要深入每种方法的实现细节。 ## 正文 ### 一、什么是指令级并行(ILP)? **指令级并行**是指程序中多条指令**同时执行或重叠执行**的可能性。ILP 的开发目标是在不改变程序语义的前提下,尽可能让更多的指令在同一时刻处于执行状态。 > [!question] ILP 的理论基础是什么? > 程序中大部分指令之间**没有**数据依赖或控制依赖。研究表明,一个典型程序中每条指令平均只有 0.5~1.5 条真依赖。这意味着在理论上,一个程序可以同时执行 3~5 条指令——但需要硬件或编译器来发现和利用这种并行性。 ### 二、开发方法总览 ```mermaid graph TD ROOT["ILP Development"] --> S["Static Methods"] ROOT --> D["Dynamic Methods"] S --> S1["Loop Unrolling"] S --> S2["Software Pipelining"] S --> S3["Trace Scheduling"] S --> S4["Instruction Scheduling"] D --> D1["Superscalar"] D --> D2["Out-of-Order Execution"] D --> D3["Speculative Execution"] D --> D4["Register Renaming"] D --> D5["Branch Prediction"] D --> D6["Dynamic Scheduling"] ``` ### 三、静态方法(编译器主导) 静态方法在**编译时**分析和优化指令顺序,运行时按优化后的顺序执行。 | 方法 | 原理 | 效果 | |------|------|------| | **循环展开**(Loop Unrolling) | 将循环体复制多份,减少循环控制指令的开销 | 减少分支指令占比,增加调度空间 | | **软件流水**(Software Pipelining) | 从不同迭代中抽取指令组成新的循环体 | 使每次迭代中各段重叠执行 | | **轨迹调度**(Trace Scheduling) | 选择最可能执行的路径(trace),在该路径上全局优化 | 对热路径的优化效果显著 | | **指令调度**(Instruction Scheduling) | 重排指令顺序以避免数据冲突和结构冲突 | 减少 Stall,提高流水线利用率 | > [!note] 循环展开示例 > > **原始代码**(4 次迭代): > ``` > for (i = 0; i < 4; i++) > C[i] = A[i] + B[i]; > ``` > > **循环展开 2 次**: > ``` > C[0] = A[0] + B[0]; > C[1] = A[1] + B[1]; // 与上一条无依赖,可并行 > C[2] = A[2] + B[2]; > C[3] = A[3] + B[3]; // 与上一条无依赖,可并行 > ``` > > 展开后分支指令从 4 条减为 0 条(或 1 条),且相邻指令的独立性更高,编译器有更多调度自由度。 > [!question] 静态方法的局限性? > 1. 编译时无法知道**运行时信息**(如 Cache 是否命中、分支方向),调度可能不是最优的 > 2. 不同的输入数据可能改变最优的指令顺序 > 3. 编译器必须保守处理——如果不确定两条指令是否相关,就假定相关,不做并行化 ### 四、动态方法(硬件主导) 动态方法在**运行时**由处理器硬件发现和利用 ILP。 | 方法 | 原理 | 效果 | |------|------|------| | **超标量**(Superscalar) | 每个时钟周期发射**多条指令**到多个功能部件 | 基础并行执行能力 | | **乱序执行**(Out-of-Order Execution) | 指令不按程序顺序执行,就绪即可执行 | 消除等待,提高利用率 | | **推测执行**(Speculative Execution) | 在分支结果确定前就执行分支目标处的指令 | 隐藏分支延迟 | | **寄存器重命名**(Register Renaming) | 将逻辑寄存器映射到物理寄存器,消除名相关 | 消除 WAR 和 WAW 冲突 | | **分支预测**(Branch Prediction) | 预测分支方向,提前取指和执行 | 减少控制冲突 | | **动态调度**(Dynamic Scheduling) | 如 Tomasulo 算法,硬件动态分配资源和调度指令 | 处理数据相关的等待 | ```mermaid graph LR subgraph InOrder["In-Order Issue"] I1["Instruction 1"] --> I2["Instruction 2"] --> I3["Instruction 3"] end subgraph OutOfOrder["Out-of-Order Execution"] O1["Instruction 1"] --> O_EX1["Execute"] O2["Instruction 2"] -->|"Stall (waiting)"| O2_W["Wait"] O3["Instruction 3"] -->|"Ready first"| O_EX3["Execute"] end ``` > [!note] Tomasulo 算法简介 > Tomasulo 算法是 IBM 在 1967 年为 System/360/91 开发的动态调度算法,核心思想: > 1. **保留站**(Reservation Station):每个功能部件有若干保留站,存放等待执行的指令及其操作数 > 2. **公共数据总线**(CDB):运算结果通过 CDB 广播,所有等待该结果的保留站同时获取 > 3. **寄存器重命名**:通过保留站标签替代寄存器号,自动消除 WAR 和 WAW 冲突 > > Tomasulo 算法是现代超标量处理器乱序执行引擎的理论基础。 ### 五、静态 vs 动态方法对比 | 对比维度 | 静态方法 | 动态方法 | |----------|----------|----------| | 决策时机 | 编译时 | 运行时 | | 信息来源 | 程序结构分析 | 实际运行状态 | | 适应性 | 差(无法适应运行时变化) | 好(根据实际情况调整) | | 硬件开销 | 低 | 高 | | 典型代表 | 循环展开、指令调度 | 超标量、乱序执行 | | 适用场景 | 嵌入式、低功耗处理器 | 高性能通用处理器 | > [!question] 现代处理器如何组合使用? > 现代处理器(如 Intel Core、ARM Cortex-A)**同时使用**静态和动态方法: > - 编译器做指令调度和循环展开(静态) > - 硬件做超标量发射、乱序执行和分支预测(动态) > - 两者互补:编译器提供良好的初始顺序,硬件进一步挖掘运行时并行性 ## 关联笔记 - [[计算机系统结构/复习文档/流水线技术]] - [[小题3-控制冲突的解决措施]] - [[小题2-流水线的分类]]