我很难理解处理器时间。该程序的结果:
#include <iostream>
#include <chrono>
// the function f() does some time-consuming work
void f()
{
volatile long double d;
int size = 10000;
for(int n=0; n<size; ++n)
for(int m=0; m<size; ++m)
d = n*m;
}
int main()
{
std::clock_t start = std::clock();
f();
std::clock_t end = std::clock();
std::cout << "CPU time used: "
<< (end - start)
<< "n";
}
似乎在21万、22万和23万之间随机波动。起初我很惊讶,为什么这些离散值。然后我发现std::clock()
只返回近似的处理器时间。因此,std::clock()
返回的值可能四舍五入为10000的倍数。这也可以解释为什么CPU时间之间的最大差是20000(10000==第一次调用std::clock()
时的舍入误差和第二次调用时的舍入错误(。
但如果我在f()
的主体中改为int size = 40000;
,我会得到3400000到35000000范围内的波动,这不能用四舍五入来解释。
根据我在维基百科上读到的关于时钟速率的内容:
CPU需要固定数量的时钟节拍(或时钟周期(执行每个指令。时钟越快,指令越多CPU可以每秒执行一次。
也就是说,如果程序是确定性的(我希望我的是确定性的(,那么完成所需的CPU时间应该是:
- 总是一样
- 略高于执行的指令数量
我的实验也没有显示,因为我的程序至少需要执行3 * size * size
指令。你能解释一下我做错了什么吗?
首先,您从维基百科引用的语句完全是假的。这在20年前可能是真的(但并非总是如此,甚至然后(,但这在今天是完全错误的。有很多东西这会影响你的时间:
-
第一:如果你在Windows上运行,
clock
坏了,而且完全不可靠。它返回已用时间的差值时间,而不是CPU时间。经过的时间取决于处理器可能正在做的其他事情。 -
除此之外:像缓存未命中这样的事情具有非常重要的意义对时间的影响。以及特定数据是否在缓存与否取决于您的程序是否在上次访问和这次访问之间中断。
一般来说,任何低于10%的情况都很容易是由于缓存问题。我看到了10倍的差异在Windows下,取决于是否有正在运行的生成不
您没有说明在什么硬件上运行二进制文件。
它有中断驱动的CPU吗?
它是一个多任务操作系统吗?
你把CPU的周期时间(维基百科所指的CPU时钟(与从开始到结束执行特定代码所需的时间以及糟糕的CPU必须同时做的所有其他事情搞错了。
此外。。。所有正在执行的代码都在1级缓存中,或者在2级或主内存中,或者磁盘上。。。下次你运行它时呢?
您的程序不是确定性的,因为它使用的库和系统函数不是确定性的。
作为一个特殊的例子,当您分配内存时,这是虚拟内存,它必须映射到物理内存。虽然这是一个运行内核代码的系统调用,但它发生在您的线程上,并将计入您的时钟时间。这需要多长时间取决于整体内存分配情况。
对于给定的一组情况,CPU时间确实是"固定的"。然而,在现代计算机中,系统中还会发生其他事情,这些事情会干扰代码的执行。当你的电子邮件软件醒来检查是否有新的电子邮件时,或者当HP打印机软件检查更新时,或者防病毒软件决定运行一点检查你的内存是否包含病毒等时,缓存可能会被清除。
部分原因还在于,任何系统中的CPU时间计算都不是100%准确的——它在"时钟滴答"和类似的事情上工作,因此,例如,中断为传入的网络数据包提供服务所用的时间,或硬盘服务中断所用的时间,或计时器中断说"又是一毫秒"所用的时候,这些都计入了"当前运行的进程"。假设这是Windows,还有另一个"功能",即由于历史和其他原因,std::clock()
只是返回现在的时间,而不是您的进程实际使用的时间。例如:
t = clock();
cin >> x;
t = clock() - t;
如果输入x
的值需要10秒,则t
将剩下10秒的时间,即使这10秒中的9.999秒是在空闲过程中度过的,而不是您的程序。