分支预测优化
Branch prediction optimizations
我试图了解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 的输出(使用 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"条件移动"指令)。
它避免了内部循环中的分支,因此性能不依赖于分支预测。因此,对输入进行排序没有区别(如在第二个示例中所做的那样)。
相关文章:
- 如何确保在使用基于布尔值的两个方法之一调用方法时避免分支预测错误
- std::shared_ptr vs std::make_shared:意外的缓存未命中和分支预测
- 如何禁用分支预测C++/Mac/英特尔
- C++ 中的可移植分支预测提示
- 常量条件的分支预测
- 分支预测和分支目标预测之间的性能差异
- 分支预测与分支目标预测
- 分支预测优化
- 分支预测的加速是否取决于谓词的复杂性?
- 我可以在现代英特尔酷睿CPU上测量分支预测故障吗
- 如何优化间接基数排序?(又名如何优化不可预测的内存访问模式)
- 针对已知的更常见的路径优化分支
- 分支预测变量结果是否在流程使用其时间片后保存
- 分支预测 - 全球份额实施说明
- 为什么我不是分支预测的受害者
- 函数指针上的分支预测
- 分支预测及分支目标预测优化
- 分支预测与除零
- 为什么VS 2015编译器不能在浮点数的abs()实现中优化分支?
- 编译器有一定的优化启发式来支持分支预测吗?如果没有,为什么没有呢?