跳到主要内容

前端性能模型:从 MPKI 到 IPC

前端设计不能从“再加一张表会更准”开始,而要先问:当前 workload 每千条指令损失多少周期,损失来自预测、Cache、TLB 还是后端背压?

最小吞吐模型​

先选定统计窗口:每提交 1000 条指令(1 kinst)。设分支误预测、ICache miss 和 ITLB miss 的事件率分别为 M_b、M_i、M_t,其平均有效代价分别为 P_b、P_i、P_t。粗略前端损失为:

lost_cycles_per_kinst ≈ M_b·P_b + M_i·P_i + M_t·P_t + starvation_cycles
effective_IPC ≈ 1000 / (1000/base_IPC + lost_cycles_per_kinst)

符号和单位​

符号含义单位例子
W每周期最多可提交的指令数,即机器提交宽度上限instruction/cycleCommitWidth=8 时 W=8
base_IPC暂时移除所统计前端损失后,机器在该 workload 上可达到的 IPC;它不是必然等于 Winstruction/cycle后端仍有限制时可能为 4.0
M_b每 1000 条已提交指令发生的分支误预测次数,即 branch MPKIevent/kinstM_b=3.5
P_b每次分支误预测造成的平均不可隐藏停顿cycle/event平均损失 16 周期
M_i每 1000 条已提交指令的 ICache miss 次数event/kinstM_i=1.2
P_i每次 ICache miss 造成的平均不可隐藏停顿cycle/event平均损失 22 周期
M_t每 1000 条已提交指令的 ITLB miss 次数event/kinstM_t=0.15
P_t每次 ITLB miss 造成的平均不可隐藏停顿cycle/event平均损失 35 周期
starvation_cycles未被前三类事件解释、但前端无法向后端提供有效指令的周期数cycle/kinst跨行、FTQ full 等共 12 周期
lost_cycles_per_kinst每 1000 条指令由上述前端事件增加的总周期cycle/kinst计算结果 99.65
effective_IPC加入这些前端损失后的估算 IPCinstruction/cycle计算结果 2.86

这里 M_i·P_i 是乘法,不是 M_i/P_i 的除法。量纲检查如下:

(event / kinst) × (cycle / event) = cycle / kinst

而基础执行时间是:

1000 instruction ÷ base_IPC(instruction/cycle)
= 1000/base_IPC cycle

两者都是“执行 1000 条指令所需的周期”,所以可以相加。

完整计算例子​

假设测得:

base_IPC = 4.0
M_b = 3.5, P_b = 16
M_i = 1.2, P_i = 22
M_t = 0.15, P_t = 35
starvation_cycles = 12

各项损失为:

branch loss = 3.5 × 16  = 56.00 cycle/kinst
ICache loss = 1.2 × 22 = 26.40 cycle/kinst
ITLB loss = 0.15 × 35 = 5.25 cycle/kinst
other loss = 12.00 cycle/kinst

lost_cycles_per_kinst = 99.65 cycle/kinst
base_cycles_per_kinst = 1000 / 4.0 = 250 cycle/kinst
total_cycles_per_kinst ≈ 250 + 99.65 = 349.65 cycle/kinst
effective_IPC ≈ 1000 / 349.65 = 2.86 instruction/cycle

W=8 只给出绝对上限。这里 base_IPC=4.0,说明即使没有所列前端损失,数据依赖、执行端口、访存和提交利用率仍使程序达不到 8 IPC。

“平均损失周期”应如何理解​

P_b/P_i/P_t 不能直接填物理器件的原始延迟。例如一次 ICache miss 从请求到 refill 用了 40 周期,但乱序窗口可能掩盖其中一部分;若最终只让提交额外停了 22 周期,则模型应使用约 22,而不是 40。

有两种常用获取方式:

  1. 用 top-down 计数器统计归属于该原因的停顿周期,再除以事件数;
  2. 做受控实验,只改变一种机制,用总周期差除以事件数。

第二种更接近边际代价,但需要确保两次运行路径和指令数可比。

这个模型什么时候会算错​

它假设各类损失可以近似相加。真实处理器中存在重叠:一次 branch mispredict 可能发生在 ICache miss 期间,此时把两个完整 penalty 都相加会重复计算。更完整的写法是:

total_cycles = base_cycles
+ branch_loss
+ icache_loss
+ itlb_loss
+ other_frontend_loss
- overlapped_loss

如果使用的 top-down 统计已经保证每个周期只归入一个原因,就不要再次减 overlap;如果各计数器独立累计,则必须检查交集。这个模型的用途是建立优化优先级和数量级判断,不是替代周期精确仿真。

如果误预测损失占主导,扩大 ICache 不会解决核心问题;反过来,如果大部分 branch penalty 与 ICache miss 重叠,单看 M_b·P_b 又会高估预测器优化收益。

分支预测的两个维度​

准确率​

通常用 MPKI(mispredictions per kilo instructions)比单纯 accuracy 更有意义,因为不同程序分支密度不同。

恢复代价​

相同 MPKI 下,从预测到分支解析越深,错误路径占用的周期和资源越多。恢复代价至少包括:发现延迟、redirect 传输、BPU 重新预测、ICache/IFU 重新供给,以及后端重新填充。

有效取指带宽​

FetchWidth 只是物理上限。有效带宽还受这些因素限制:

  • 取指块内第一个 taken branch 截断后续槽位;
  • 32/16 位指令边界和跨行拼接;
  • ICache bank、TLB、PMP 与 refill;
  • FTQ/IBuffer 满导致的 backpressure;
  • 预测覆盖(override)造成前面取到的块作废。

昆明湖参数的读法​

Parameters.scala 中可看到当前基线含 numBr=2、FtqSize=64、IBufSize=48、DecodeWidth=6、CommitWidth=8。这些数字不能孤立理解:预测器每块表达能力、FTQ 在途深度、IBuffer 去耦能力和后端消费宽度共同决定前端供给。

历史长度由预测器配置推导:

val allHistLens = SCHistLens ++ ITTageTableInfos.map(_._2) ++
TageTableInfos.map(_._2) :+ UbtbGHRLength
val HistoryLength = allHistLens.max + numBr * FtqSize + 9

它不仅容纳最长相关历史,还为大量在途预测和实现余量留空间。

架构师练习​

假设 workload 的 branch MPKI 从 4 降到 3,平均误预测代价 18 周期;另一方案保持 MPKI=4,但把恢复代价降到 14 周期。先用上式比较,再讨论两种方案对面积、频率和不同 workload 的稳健性。

真实测量清单​

不要只收集总 IPC。至少同时记录:预测请求数、各级 override、FTB/TAGE/SC/ITTAGE/RAS miss、backend redirect latency、BPU update latency、FTQ occupancy、IBuffer full、ICache/ITLB miss 和前端空泡归因。