【发布时间】: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