当我编写一些需要快速工作的紧凑循环时,我经常被关于处理器分支预测将如何表现的想法所困扰。例如,我尽量避免在最内层的循环中使用if语句,特别是结果不太一致(随机计算为true或false )的语句。
我倾向于这样做,因为有些常识是处理器预取指令,如果结果是它错误地预测了一个分支,那么预取是无用的。
我的问题是-这真的是现代处理器的问题吗?分支预测能有多好呢?
哪些编码模式可以让它变得更好?
(为了便于讨论,假设我已经超越了“早期优化是万恶之源”阶段)
发布于 2008-11-14 11:45:06
这些天分支预测非常好。但这并不意味着可以消除分支的惩罚。
在典型的代码中,您可能会获得99%以上的正确预测,但性能影响仍然很大。这其中有几个因素在起作用。
一个是简单的分支延迟。在普通PC CPU上,对于错误预测,这可能是12个周期的量级,或者对于正确预测的分支,这可能是1个周期。为了便于讨论,让我们假设所有分支都被正确预测,那么您就可以回家了,对吧?不完全是。
分支的简单存在抑制了许多优化。编译器无法跨分支有效地重新排序代码。在基本代码块(即顺序执行的代码块,没有分支、一个入口点和一个出口)中,它可以随心所欲地重新排序指令,只要代码的含义得到保留,因为它们迟早都会被执行。在分支机构中,它变得更加棘手。我们可以在这个分支之后下移这些指令来执行,但是我们如何保证它们被执行呢?将它们放在两个分支中?这是额外的代码大小,这也是混乱的,如果我们想要在多个分支上重新排序,它就不能扩展。
即使有最好的分支预测,分支仍然很昂贵。不仅仅是因为预测错误,还因为指令调度变得非常困难。
这也意味着,重要的因素不是分支的数量,而是它们之间的块中有多少代码。每隔一行执行一次分支是不好的,但是如果您可以在分支之间的块中使用十几行代码,那么很可能会合理地调度这些指令,这样分支就不会对CPU或编译器造成太大的限制。
但在典型的代码中,分支基本上是免费的。在典型的代码中,在性能关键型代码中,没有那么多分支紧密地聚集在一起。
发布于 2008-11-14 07:12:39
(为了便于讨论,假设我已经超越了“早期优化是万恶之源”阶段)
太棒了。然后,您可以分析应用程序的性能,使用gcc的标记进行预测并再次分析,使用gcc的标记进行相反的预测并再次分析。
现在假设理论上有一个CPU预取了两个分支路径。对于两个路径中的后续if语句,它将预取四个路径,依此类推。CPU不会神奇地增长四倍的缓存空间,因此它将预取每个路径的较短部分,而不是单个路径。
如果你发现一半的预取被浪费了,比如说损失了5%的CPU时间,那么你确实想要寻找一个不会分支的解决方案。
发布于 2008-11-14 07:12:26
如果我们超越了“早期优化”阶段,那么我们肯定也超越了“我可以衡量那个”阶段?随着现代CPU体系结构的异常复杂,唯一确定的方法就是尝试和测量。当然,在很多情况下,你可以选择两种方法来实现某些东西,其中一种需要分支,另一种不需要。
https://stackoverflow.com/questions/289405
复制相似问题