1. 基本参数回顾
-
程序里有 17% 的指令是分支:
pbranch=0.17 p_{\rm branch}=0.17 pbranch=0.17
-
真正会 跳转 的分支占所有分支的 33%:
P(taken)=0.33,P(not taken)=0.67 P(\text{taken})=0.33,\quad P(\text{not taken})=0.67 P(taken)=0.33,P(not taken)=0.67
-
每发生一次分支错误预测,要付出大约 17 个时钟周期的罚款:
penalty=17 cycles \text{penalty}=17\ \text{cycles} penalty=17 cycles
2. “Always-taken” 下的错误率
-
我们把所有分支都预测为“跳转”(taken)。
-
那么对于实际不跳转的 67% 分支就会全部预测失败:
P(mispredict per branch)=P(not taken)=0.67 P(\text{mispredict per branch}) = P(\text{not taken}) = 0.67 P(mispredict per branch)=P(not taken)=0.67
-
平均每条指令上,会有多少次“错误预测”?
mispredicts per instr=pbranch × P(mispredict per branch)=0.17×0.67≈0.1139 \text{mispredicts per instr} = p_{\rm branch}\;\times\;P(\text{mispredict per branch}) = 0.17 \times 0.67 \approx 0.1139 mispredicts per instr=pbranch×P(mispredict per branch)=0.17×0.67≈0.1139
3. 平均每条指令额外付出的周期
每次错误要付 17 周期,所以每条指令平均罚款:
ΔTper instr=0.1139×17≈1.936 cycles \Delta T_{\rm per\ instr} = 0.1139 \times 17 \approx 1.936 \text{ cycles} ΔTper instr=0.1139×17≈1.936 cycles
原本每条指令至少要 1 个周期(完美流水线假设),现在多了这罚款,所以
Tnew≈1+1.936=2.936 cycles/instr T_{\rm new} \approx 1 + 1.936 = 2.936\ \text{cycles/instr} Tnew≈1+1.936=2.936 cycles/instr
4. 慢了多少倍?
和完美流水线(1 cycle/instr)比,时钟节拍不变,但 CPI(cycles per instruction)从 1 涨到 2.936,整体慢
slowdown=2.9361≈2.94× \text{slowdown} = \frac{2.936}{1} \approx 2.94\times slowdown=12.936≈2.94×
如果用“相对慢多少”来讲,也就是 CPU 运行 2.94 倍那个程序要相同指令数,或者说性能降低到 1/2.94 ≈ 0.34×。
5. 跟 always-not-taken 下的 1.95× 比较
- “always-not-taken” 的错误率是 33%,算下来平均 CPI≈1+0.17×0.33×17≈1.95,所以慢 1.95×;
- “always-taken” 的错误率更高(67%),所以更糟:慢 ≈2.94×。
所以在分支预测非常简单、只有一个静态策略时,预测“总不跳”和预测“总跳转”哪个都不行,失误率都很高,最终都把流水线打得支离破碎。现代 CPU 就用更复杂的动态预测器去尽量把 mispredict 率降到个位数,才把分支损失压到可忍受的范围。