分支预测优化

时间:2015-03-16 11:47:23

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

我试图了解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会做什么样的巫术。

1 个答案:

答案 0 :(得分:2)

以下是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

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

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