【问题标题】:What effect will branch prediction have on the following C loop?分支预测会对后面的 C 循环产生什么影响?
【发布时间】:2015-08-12 16:31:15
【问题描述】:

我在 C 语言方面的经验相对较少,而且我对它在现代 CPU 上的编译输出缺乏很好的理解。背景:我正在为 Android 应用程序进行图像处理。我已经读过内部循环首选无分支机器代码,所以我想知道这样的事情之间是否存在显着的性能差异:

if (p)      { double for loop, computing f() }

else if (q) { double for loop, computing g() }

else        { double for loop, computing h() }

与在循环中进行条件检查的不太冗长的版本相比:

for (int i = 0; i < xRes; i++)
{
    for (int j = 0; j < yRes; j++)
    {
        image[i][j] = p ? f() : (q ? g() : h());
    }
}

在这段代码中,p 和 q 是类似mode == 3 的表达式,其中mode 被传递到函数中,并且在其中永远不会改变。我有三个简单的问题:

(1) 第一个更冗长的版本会比第二个版本编译成更高效的代码吗?

(2) 对于第二个版本,如果我将pq 的结果评估并存储在循环上方,那么我可以将循环中的布尔表达式替换为变量吗?

(3) 我是否应该担心这一点,或者分支预测(或其他一些优化)会确保循环中的布尔表达式几乎永远不会被评估?

最后,如果有人能说出这 3 个问题的答案是否取决于架构,我会很高兴。我对主要的 Android NDK 平台感兴趣:ARM、MIPS、x86 等。提前致谢!

【问题讨论】:

  • 优化会将 p 和 q 的评估移出循环,但不会移出分支。将条件移出循环,并拥有 3 个双循环副本。
  • 斯塔克,这是我最初的怀疑,但听到它得到证实我很失望。为了获得最佳性能,真的有必要将相同的循环写 3 次吗?
  • 实际上,由于循环中的分支和等待内存读取和写入,它不会有太大的区别。缓存效果很难做到正确。
  • 我看到这个几乎相同的问题给出了很好的答案:stackoverflow.com/questions/12251160/…。因此,我将等待一段时间,看看是否有人对 MIPS 和 ARM 有更具体的答案,如果没有,则将这个问题作为重复问题关闭。
  • 如果您的编译器可以看到 pq 在每次循环迭代中都相同以便能够将条件拉出循环,那么架构就不会改变。

标签: c android-ndk compiler-optimization micro-optimization branch-prediction


【解决方案1】:

看起来问题已经得到很好的回答here: 编译器可能会执行循环取消切换,从循环中删除条件并自动生成循环的 3 个副本,就像 stark建议。此外,从那里和上面给出的 cmets 来看,分支预测似乎对这些循环非常有效。

【讨论】:

    猜你喜欢
    • 2018-07-29
    • 2011-03-15
    • 1970-01-01
    • 2017-01-23
    • 2010-11-28
    • 1970-01-01
    • 2018-11-30
    相关资源
    最近更新 更多