计算机体系结构核心 20% — 把”为什么慢”算出来

一句话:性能只有一条主公式 时间 = 指令数 × CPI × 时钟周期,存储层次只有三个数字(寄存器 1 周期、L2 约 10 周期、内存约 200 周期)。抓住这两件事,就抓住了体系结构 80% 的实用知识。


🎯 这 20% 能解决哪些问题

常见困惑本质本页答案
主频高就一定快吗主频不进入唯一性能公式的分母判断见「一条性能公式」
循环顺序换一下为什么快 10 倍缓存行与访问局部性见「存储层次」
多线程加一倍核数没快一倍Amdahl 定律见「加速比上限」
分支预测失败的代价有多大流水线冲刷见「四种冒险」
数组遍历和链表遍历差在哪预取与局部性见「三条实用准则」

一、一条性能公式

[ T = IC \times CPI \times \frac{1}{f} ]

符号含义谁能影响它
IC(指令数)执行了多少条指令编译器、算法、指令集
CPI每条指令平均周期数流水线、缓存命中率、分支
f时钟频率工艺、功耗预算

推论(考试与实际都常考):

  • 优化语言层面(如减少指令数)只影响 IC。
  • 优化内存访问模式影响 CPI,常比减指令更有效。
  • 提高主频受功耗墙限制:功耗 ∝ f × V²,频率涨 20% 可能功耗涨 40%。

二、存储层次:先记住五个数

graph LR
    R["寄存器<br/>1 周期"] --> L1["L1 缓存<br/>4 周期"]
    L1 --> L2["L2 缓存<br/>12 周期"]
    L2 --> L3["L3 缓存<br/>40 周期"]
    L3 --> M["主存<br/>200 周期"]
    M --> D["SSD<br/>10 万周期"]
层次典型容量命中延迟关键机制
寄存器几百字节1 周期编译器分配
L132–64 KB4 周期缓存行 64 B
L2512 KB–2 MB12 周期组相联
L38–64 MB40 周期多核共享
主存8–512 GB200 周期预取、多通道

最有用的一个数字:缓存行 64 字节。一次访存会把相邻 64 B 一起搬进缓存——这解释顺序访问为什么快、struct 字段顺序为什么有讲究。


三、四种流水线冒险

冒险原因典型解决办法
结构冒险硬件资源冲突分开指令/数据缓存
数据冒险后一条依赖前一条结果转发(forwarding)、插入气泡
控制冒险分支结果未知分支预测、延迟槽
内存冒险访存顺序内存屏障、一致性协议

两个实用结论:

  1. 分支可预测时代价接近 0;预测失败约损失 15–20 个周期。
  2. 数据依赖链长(如累加求和)会限制指令级并行;拆成多个累加器即可提速。

四、加速比上限:Amdahl 定律

[ S = \frac{1}{(1-p) + p/s} ]

并行比例 p无限并行加速比上限
50%2×
80%5×
90%10×
95%20×
99%100×

实践含义:想把程序提速 10 倍,先找那 5% 无法并行的部分。优化串行部分比加核更划算。


五、缓存友好的三条准则

准则具体做法收益来源
顺序访问按行遍历二维数组(行主序语言)命中整条缓存行
数据紧凑热字段放一起、避免指针追逐减少缓存行浪费
分块矩阵乘按 32×32 分块提高 L1/L2 复用

反例:链表遍历每次跳指针 → 几乎每次都是缓存未命中,比数组慢 5–20 倍。


六、多核与内存一致性

概念一句话
缓存一致性多核各自缓存同一地址时,需协议(MESI)保证看到同一值
伪共享两个核改同一缓存行的不同变量,互相失效拖慢
内存序编译器与 CPU 都可能重排,跨线程共享需屏障

伪共享是新手最常踩的坑:多线程计数器数组放在连续内存,性能反而不如单线程。解决:按缓存行对齐填充。


📋 一页速查

问题答案
唯一性能公式T = IC × CPI × 1/f
缓存行多大64 字节
内存延迟约 200 周期
分支预测失败代价约 15–20 周期
加速比上限由串行比例决定(Amdahl)
最便宜的提速手段改善访问局部性

🔗 相关链接

主题链接
硬件基础概览硬件基础
GPU 并行计算GPU 并行计算核心 20%
芯片设计芯片设计核心 20%
量子计算量子计算核心 20%
算法与数据结构算法与数据结构