使用-O3或-Ofast编译基准代码现实吗?还是会删除代码
Is it realistic to use -O3 or -Ofast to compile your benchmark code or will it remove code?
当用-O3
编译下面的基准代码时,它在延迟方面的差异给我留下了深刻的印象,所以我开始怀疑编译器是否通过某种方式删除代码来"作弊"。有办法检查一下吗?使用-O3
进行基准测试安全吗?期望速度提高15倍是否现实?
无-O3
的结果:平均值:239纳米最小值:230纳米(900万次迭代(-O3
的结果:平均值:14纳米,最小值:12纳米(900万次迭代(
int iterations = stoi(argv[1]);
int load = stoi(argv[2]);
long long x = 0;
for(int i = 0; i < iterations; i++) {
long start = get_nano_ts(); // START clock
for(int j = 0; j < load; j++) {
if (i % 4 == 0) {
x += (i % 4) * (i % 8);
} else {
x -= (i % 16) * (i % 32);
}
}
long end = get_nano_ts(); // STOP clock
// (omitted for clarity)
}
cout << "My result: " << x << endl;
注意:我使用clock_gettime
来测量:
long get_nano_ts() {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1000000000 + ts.tv_nsec;
}
在启用优化的情况下编译时,编译器肯定会"作弊"并删除不必要的代码。实际上,它花了很长的时间来加快代码的速度,这几乎总是会带来令人印象深刻的速度。如果它能够以某种方式推导出一个在恒定时间内计算结果的公式,而不是使用这个循环,它会的。常数因子15并不是什么特别的。
但这并不意味着您应该评测未优化的构建!事实上,当使用像C和C++这样的语言时,未优化构建的性能几乎完全没有意义。你根本不用担心。
当然,这可能会干扰微观基准,就像您上面展示的那样。两点:
- 通常情况下,这种微观优化也无关紧要。更喜欢分析实际程序,然后消除瓶颈
- 如果你真的想要这样一个微基准测试,让它依赖于一些运行时输入并显示结果。这样,编译器就不能删除功能本身,只需使其相当快
既然您似乎正在这样做,那么您显示的代码很有可能成为一个合理的微基准。需要注意的一点是,编译器是否将对get_nano_ts();
的两个调用都移到循环的同一侧。允许这样做,因为"运行时"不算作可观察到的副作用。(标准甚至没有要求你的机器以有限的速度运行。(这里有人认为这通常不是问题,尽管我无法真正判断给出的答案是否有效。
如果你的程序除了你想基准测试的事情之外没有做任何昂贵的事情(如果可能的话,无论如何都不应该做(,你也可以将时间测量"移到外面",例如随着时间。
对您认为正在测量的内容进行基准测试可能非常困难。在内环的情况下:
for (int j = 0; j < load; ++j)
if (i % 4 == 0)
x += (i % 4) * (i % 8);
else x -= (i % 16) * (i % 32);
一个精明的编译器可能能够看穿这一点,并将代码更改为类似的代码
x = load * 174; // example only
我知道这是不等价的,但有一些相当简单的表达式可以代替那个循环。
确保这一点的方法是使用gcc -S
编译器选项并查看它生成的汇编代码。
您应该始终启用优化的基准测试。但是,重要的是要确保您想要计时的东西不会被编译器优化掉。
一种方法是在计时器停止后打印出计算结果:
long long x = 0;
for(int i = 0; i < iterations; i++) {
long start = get_nano_ts(); // START clock
for(int j = 0; j < load; j++) {
if (i % 4 == 0) {
x += (i % 4) * (i % 8);
} else {
x -= (i % 16) * (i % 32);
}
}
long end = get_nano_ts(); // STOP clock
// now print out x so the compiler doesn't just ignore it:
std::cout << "check: " << x << 'n',
// (omitted for clarity)
}
在比较几种不同算法的基准时,也可以检查每种算法是否产生相同的结果。
- 为什么示例代码访问IUnknown中已删除的内存
- 你能检查一下为什么在这个代码中从链接列表中删除项目不起作用吗
- 从 C 样式字符串中删除子字符串 "in place" 在C++代码中
- 是否可以使用 C++ 中的模板减小删除代码大小
- 删除C++继承中虚拟类成员的代码重复
- 当我从下面的代码中删除关键字 virtual 时,它可以正常工作,否则会出现错误。在这里"virtual"字的意义是什么?
- 删除继承中的代码重复?
- 从排序数组中删除重复项,具有不同代码方式的相同解决方案具有不同的输出
- G++ 发出警告,要求删除一个代码的数组,但不删除另一个代码的数组
- 删除原子多线程代码中的容器
- 使用 ostream 变量删除代码重复
- 可视代码 删除函数括号内的空格
- Qt创建者-如何删除Clang代码模型
- 更正代码c++指针并删除
- 有没有一种预处理器的方法可以从调试符号中删除代码段
- 删除被注释掉的代码,而不是实际的赞美
- 在 cpp 中验证路径:无法使用 ASCII 代码删除特殊字符
- 旧项目中的重复代码删除策略
- 应由库或客户端代码删除已加载库中的对象实例
- 内联和死代码删除优化是否可以阻止模板实例化