Bar*_*vbl 5 c++ optimization performance
我编写了以下程序来使用std :: chrono:
#include <iostream>
#include <chrono>
int main(int argc, char** argv) {
const long iterationCount = 10000;
long count = 0;
for(long i = 0; i < iterationCount; i++) {
auto start = std::chrono::high_resolution_clock::now();
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
count++;count++;count++;count++;count++;count++;count++;count++;count++;count++;
auto end = std::chrono::high_resolution_clock::now();
auto timeTaken = std::chrono::duration_cast<std::chrono::nanoseconds>(end - start).count();
std::cout << timeTaken << " " << std::endl;
}
}
Run Code Online (Sandbox Code Playgroud)
我使用G ++编译了这个,没有启用编译器优化:
g++ chrono.cpp -o chrono
Run Code Online (Sandbox Code Playgroud)
我随后运行了几次这个程序,得到了一个有趣的模式.对于前500-1000次迭代,程序运行速度比其余迭代速度慢约7-8倍.
以下是该程序的示例输出:https://pastebin.com/tUQsQEAQ
导致运行时间出现这种差异的原因是什么?我的第一反应是缓存,但是那个不会很快变得饱和吗?
如果重要,我的操作系统是Ubuntu 18.04,我的g ++版本是7.3.0.
在微架构实现定义的时间之后,如果 CPU 可以找到相同的热功率余量,则会启动频率缩放,以将要求严格的核心的时钟加速到最大值(在 TDP 的限制内)。
英特尔的实现称为睿频加速。
如果您在系统中禁用频率缩放(例如,在包中使用sudo cpupower frequency-set --governor performance- ),则每次迭代的时间或多或少是相同的。cpupowercpupowerutils
循环本身很容易预测,如果不只在循环控制的最后出现一个错误预测,那么您可能只会出现一些错误预测 - C++ 库内的代码可能更难预测,但即使如此,也不会花那么长时间( 1000 次迭代)让 BPU 赶上您的代码。
所以你可以排除分支错误预测。
或多或少同样适用于 I-cache(很少使用 D-cache,除非 C++ 库实现大量使用变量)。
代码应该足够小以适合 L1-I,甚至大部分代码都适合 DSB。
L1-I 未命中不需要 1000 次迭代才能解决,如果缓存中存在严重的设置冲突,则会显示为总体速度减慢,并且在 1000 次迭代后不会消失。
一般来说,众所周知,代码从循环携带依赖链的第二次迭代开始运行得更快,因为 CPU 第一次填充了缓存(数据、指令、TLB)。
如果 CPU 耗尽资源,它最终可能会再次变慢,例如,如果存在大量端口压力(例如,大量相同的有限端口长延迟指令),RS 可能会填满,从而导致 FE 停顿,或者如果存在大量加载/存储填充 MOB/SB/LB 或大量跳转填充 BOB。
然而,这些效果很快就会发挥作用,以至于它们主导了代码的运行时间。
在这种情况下,减速发生得非常晚(以 CPU 时间计算),因此需要考虑按需进程 - 例如 Turbo boost。