我编写了以下程序来试用一下 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;
}
}
我在没有启用编译器优化的情况下使用 G++ 编译了它:
g++ chrono.cpp -o chrono
我随后运行了这个程序几次,得到了一个有趣的模式。对于前 500-1000 次迭代,程序的运行速度比其余迭代慢 7-8 倍。
这是该程序的示例输出:https://pastebin.com/tUQsQEAQ
是什么导致了这种运行时差异?我的第一 react 是缓存,但是那会不会很快就饱和了?
以防万一,我的操作系统是 Ubuntu 18.04,我的 g++ 版本是 7.3.0。
最佳答案
在微架构实现定义的时间之后,如果 CPU 可以找到相同的热功率余量,频率缩放就会开始将要求苛刻的核心的时钟加速到最大值(在 TDP 的限制内)。
Intel 的实现称为 Turbo boost .
如果您在系统中禁用频率缩放(例如使用 sudo cpupower frequency-set --governor performance
- cpupower
位于 cpupowerutils
package)每次迭代的时间大致相同。
循环本身很容易预测,如果不是只有一个在末尾em>来自循环控制,您可以预期只有少数错误预测 - C++ 库中的代码可能更难预测,但即使这样 BPU 就不会花那么长时间(1000 次迭代)来跟上您的代码。
所以你可以排除分支预测错误。
I-cache 或多或少相同(很少使用 D-cache,除非 C++ 库实现大量使用变量)。
代码应该足够小以适应 L1-I,并且大部分甚至可以适应 DSB。
L1-I 未命中不需要 1000 次迭代来解决,如果缓存中存在严重的集合冲突,这将显示为一般减速,并且在 1000 次迭代后不会消失。
一般来说,由于 CPU 第一次填充缓存(数据、指令、TLB),代码从带有依赖链的循环的第二次迭代开始运行得更快是众所周知的效果。
如果 CPU 资源耗尽,它最终可能会再次变慢,例如,如果有很大的端口压力(例如,许多相同的有限端口长延迟指令)RS 可能会填满使 FE 停止,或者如果有大量加载/存储填充 MOB/SB/LB 或大量跳跃填充 BOB。
然而,这些影响很快就会出现,以至于它们支配了代码的运行时间。
在这种情况下,减速发生得非常晚(在 CPU 时间中),这使得考虑按需过程是可取的——比如 Turbo boost。
关于c++ - 是什么导致我的循环在其第一次迭代中运行得更慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52240143/