当我写一些需要快速工作的紧密循环时,我常常被关于处理器分支预测将如何表现的想法所困扰.例如,我尽量避免在最内部循环中使用if语句,尤其是结果不一致的结果(比如判断为true或false随机).
我倾向于这样做,因为处理器预先获取指令有一些常见的知识,如果事实证明它错误地预测了一个分支,那么预取是没用的.
我的问题是 - 这真的是现代处理器的问题吗?预期分支预测有多好?
可以使用哪些编码模式来使其更好?
(为了讨论起见,假设我超越了"早期优化是所有邪恶的根源"阶段)
如今,分支预测非常好.但这并不意味着可以消除分支的惩罚.
在典型的代码中,您可能获得超过99%的正确预测,但性能损失仍然很大.这有几个因素在起作用.
一个是简单的分支延迟.在普通的PC CPU上,错误预测可能大约为12个周期,正确预测的分支可能为1个周期.为了争论,让我们假设你的所有分支都被正确预测,然后你就可以自由了,对吗?不完全的.
分支的简单存在抑制了许多优化.编译器无法跨分支有效地重新排序代码.在基本块(即,顺序执行的代码块,没有分支,一个入口点和一个出口)中,只要保留代码的含义,它就可以根据需要重新排序指令,因为它们是所有人迟早都会被处决.跨越分支机构,它变得更加棘手.我们可以将这些指令移到该分支后执行,但是我们如何保证它们被执行?把它们放在两个分支?这是额外的代码大小,也是混乱的,如果我们想要在多个分支上重新排序,它就不会扩展.
即使具有最佳分支预测,分支仍然可能很昂贵.不仅仅是因为误预测,还因为指令调度变得如此困难.
这也意味着,不是分支的数量,重要的因素是它们之间的块中有多少代码.每隔一行的分支都很糟糕,但是如果你可以在分支之间的一个块中获得十几行,那么很可能可以很好地调整这些指令,因此分支不会过多地限制CPU或编译器.
但在典型的代码中,分支基本上是免费的.在典型的代码中,在性能关键代码中没有那么多分支紧密地聚集在一起.