分支预测错误
所有喧嚣的原因是分支错误预测的成本。
当分支出现时,CPU 会预测所采用的分支并将这些指令预加载到管道中。
如果预测错误,则需要清除管道并加载新指令。
这可能需要长达number_of_stages_in_pipeline
周期加上从缓存加载数据所需的任何周期。每次错误预测通常有 14 到 25 个周期。
原因:处理器设计
K8 和 K10 遭受此问题的原因是 AMD 的出色优化。
AMD K8 和 K10 将预解码缓存中的指令并跟踪它们在 CPU L1 指令缓存中的长度。
为了做到这一点,它有额外的位。
对于每 128 位(16 字节)指令,存储有 76 位附加数据.
下表详细说明了这一点:
Data Size Notes
-------------------------------------------------------------------------
Instructions 128 bits The data as read from memory
Parity bits 8 bits One parity bit for every 16 bits
Pre-decode 56 bits 3 bits per byte (start, end, function)
+ 4 bit per 16 byte line
Branch selectors 16 bits 2 bits for each 2 bytes of instruction code
Total 204 bits 128 instructions, 76 metadata
由于所有这些数据都存储在 L1 指令缓存中,K8/10 cpu 在解码和分支预测上花费的工作量要少得多。这节省了硅。
而且由于 AMD 的晶体管预算不如英特尔,因此它需要更智能地工作。
但是,如果代码是 esp。紧跳和 ret 可能占用相同的两个字节槽,这意味着RET
被预测为未采取(因为它后面的跳转是)。
通过使RET占据两个字节REP RET
这种情况永远不会发生,并且 RET 总是会被预测为正常。
Intel 没有这个问题,但(过去)受到预测槽数量有限的影响,而 AMD 则没有。
nop ret
从来没有理由去做nop ret
。这是两条指令,浪费了一个额外的周期来执行nop
和ret
可能仍然与跳跃“配对”。
如果你想对齐使用REP MOV
相反或使用multibyte nop
.
结束语
仅本地分支预测与指令一起存储在高速缓存中。
还有一个单独的全局分支预测表。