是什么原因导致我的循环在第一次迭代中运行得更慢?

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.

Mar*_*oom 4

在微架构实现定义的时间之后,如果 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。