【问题标题】:Branch prediction optimizations分支预测优化
【发布时间】:2015-03-16 11:47:22
【问题描述】:

我试图了解 gcc/clang 对这段代码做了什么样的魔法优化。

#include <random>
#include <iostream>

int main()
{
    std::random_device rd;
    std::mt19937 mt(rd());
    const unsigned arraySize = 100000;
    int data[arraySize];

    for (unsigned c = 0; c < arraySize; ++c)
        data[c] = mt() % 256;

    long long sum = 0;

    for (unsigned i = 0; i < 100000; ++i)
    {
        for (unsigned c = 0; c < arraySize; ++c)
        {
            if (data[c] >= 128)
                sum += data[c];
        }
    }
    std::cout << sum << std::endl;
}

还有这段代码

#include <random>
#include <iostream>
#include <algorithm>
int main()
{
    std::random_device rd;
    std::mt19937 mt(rd());
    const unsigned arraySize = 100000;
    int data[arraySize];

    for (unsigned c = 0; c < arraySize; ++c)
        data[c] = mt() % 256;

    std::sort(data, data + arraySize);
    long long sum = 0;

    for (unsigned i = 0; i < 100000; ++i)
    {
        for (unsigned c = 0; c < arraySize; ++c)
        {
            if (data[c] >= 128)
                sum += data[c];
        }
    }
    std::cout << sum << std::endl;
}

基本上,当我在大约 3 年前编译并运行它时,由于更好的分支预测,第二个代码的速度快了 4 倍。我现在编译运行的时候,几乎是在同一时间运行的,不知道gcc/clang到底做了什么巫术。

【问题讨论】:

  • 你看过汇编器的输出吗(想把它贴出来吗?) - gcc.godbolt.org 我还假设你正在比较苹果和苹果,并且你已经尝试过新旧编译器的输出在具有相同库的相同硬件上?
  • 你在编译两者时使用了哪些标志?
  • 在第二个示例中,您正在对数组进行排序。通过这样做,一旦您开始点击高于 127 的数据,那么您将始终调用 += 运算符。由于您每次迭代都在执行此操作,因此应该缓存此操作。我读过一篇很好的tutorial,它解释了保持内存和操作“热”以提高性能的好处。
  • @user657267 -std=c++11 -O3
  • 一个常见的误解是,这是分支预测,而不是预测。

标签: c++ optimization g++ branch prediction


【解决方案1】:

这是 gcc 的输出(使用 gcc.godbolt.org,带有 -O3)

.L4: //Inner loop
    movslq  (%rax), %rdx
    movq    %rdx, %rcx
    addq    %rsi, %rdx
    cmpl    $127, %ecx
    cmovg   %rdx, %rsi
    addq    $4, %rax
    cmpq    %rdi, %rax
    jne .L4

您可以看到它进行了比较“cmpl $127,$ecx”,但是在比较之后它没有分支。相反,它总是添加(在比较上方的行中使用“addq”),然后根据比较使用添加的结果(感谢“cmovg”“条件移动”指令)。

它避免了内部循环中的分支,因此性能不依赖于分支预测。因此,对输入进行排序没有区别(就像您在第二个示例中所做的那样)。

【讨论】:

    猜你喜欢
    • 2015-11-24
    • 2013-09-04
    • 2018-07-02
    • 2014-04-25
    • 2014-03-03
    • 1970-01-01
    • 2017-04-26
    • 2016-07-01
    相关资源
    最近更新 更多