为什么CLOCKS_PER_SEC不是每秒钟实际的时钟数?

35

我刚刚写了这个简短的C++程序,用于近似计算每秒钟的时钟滴答数。

#include <iostream>
#include <time.h>

using namespace std;

int main () {

    for(int i = 0; i < 10 ; i++) {

        int first_clock = clock();
        int first_time = time(NULL);

        while(time(NULL) <= first_time) {}

        int second_time = time(NULL);
        int second_clock = clock();

        cout << "Actual clocks per second = " << (second_clock - first_clock)/(second_time - first_time) << "\n";

        cout << "CLOCKS_PER_SEC = " << CLOCKS_PER_SEC << "\n";

    }

    return 0;

}
当我运行程序时,输出的结果看起来像这样。
Actual clocks per second = 199139
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 638164
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 610735
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 614835
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 642327
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 562068
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 605767
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 619543
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 650243
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 639128
CLOCKS_PER_SEC = 1000000

为什么实际时钟每秒的滴答数与CLOCKS_PER_SEC不匹配?它们甚至不近似相等。这里发生了什么?


5
请注意,你可能会循环不到一秒钟。如果你调用了 time,并且离下一秒还有200毫秒的时间,那么你将循环大约200毫秒。无论如何,这可能不是主要的问题。 - mfontanini
1
我明白,这就是为什么循环的第一次迭代返回比后续迭代更小的结果的原因。但我的问题是关于后续迭代的。我想我应该把这个问题表述清楚。 - Kevin H. Lin
1
现在,在每个后续迭代中,您仍然会得到cout的开销。等到你到第二个开始之前再开始测量。 - David
6个回答

37

clock函数返回程序运行时间。一秒钟总共有1,000,000个时钟周期*,你的程序消耗了其中60%。

其它进程/程序占用了剩余的40%。

*好吧,在现实中并不是精确的1,000,000次时钟周期。这个数字被标准化为程序感知的1,000,000个时钟周期。


21

clock(3)的man页面中可以得知:

根据POSIX标准,CLOCKS_PER_SEC应该等于1000000,不管实际分辨率是多少。

你的实现看起来至少在这方面遵循了POSIX标准。

在这里运行你的程序,我得到了:

Actual clocks per second = 980000
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 1000000
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 990000
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 1000000
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 1000000
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 1000000
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 1000000
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 1000000
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 1000000
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 1000000
CLOCKS_PER_SEC = 1000000

在闲置的机器上产生类似的输出,以及像这样的输出

Actual clocks per second = 50000
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 600000
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 530000
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 580000
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 730000
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 730000
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 600000
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 560000
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 600000
CLOCKS_PER_SEC = 1000000
Actual clocks per second = 620000
CLOCKS_PER_SEC = 1000000

您在一台繁忙的机器上进行测试。clock()函数测量了程序使用的(大致)时间,因此看起来您是在一台繁忙的机器上进行测试,导致您的程序只获得了约60%的CPU时间。


5
虽然从技术上讲这是正确的,因为他正在使用的系统调用也尊重这一点,但这有点无用。 - Joshua

6
  1. 在POSIX中,CLOCKS_PER_SECOND是一个常量,等于1000000。
  2. CLOCKS_PER_SECOND并不应该显示进程中的时钟数。它是一个分辨率数字,可以用来将时钟数转换为时间数量。(请参见clock()函数的手册页)

例如,如果您计算:

(second_clock-first_clock)/CLOCKS_PER_SEC

您将获得第一次和第二次调用“clock()”函数之间的总时间。


CLOCKS_PER_SEC。不要难过 - 我的glibc的time.h文件中也在注释中使用了CLOCKS_PER_SECOND。 - Jetski S-type

1

C99标准

C99 N1256标准草案唯一关于CLOCKS_PER_SEC的说明是:

CLOCKS_PER_SEC 它扩展为一个具有clock_t类型(下文描述)的表达式,表示每秒钟由clock函数返回的值的数量。

正如其他人所提到的,POSIX将其设置为100万,这限制了精度为1微秒。我认为这只是历史遗留问题,当时最大的CPU频率是以兆赫为单位测量的。


0
当你设置int first_time = time(NULL);时,time(NULL)可能距离+1只有“1纳秒”(因为它被截断)。因此,while(time(NULL) <= first_time) {}可以比你预期的更快地跳过超过1秒,更快地完成。

这就是为什么在你的“1秒钟”中有较少的时钟。


-2

当然。你不知道计时开始的时间在当前秒钟中的哪个位置,对吧?所以你可以得到从1到CLOCKS_PER_SEC的任何结果。在你的内部循环中尝试这个:

int first_time = time(NULL);
// Wait for timer to roll over before starting clock!
while(time(NULL) <= first_time) {}

int first_clock = clock();
first_time = time(NULL);
while(time(NULL) <= first_time) {}

int second_time = time(NULL);
int second_clock = clock();

cout << "Actual clocks per second = " << (second_clock - first_clock)/(second_time - first_time) << "\n";

cout << "CLOCKS_PER_SEC = " << CLOCKS_PER_SEC << "\n";

请查看 ideone获取完整的源代码。它报告实际每秒钟的时钟数为1000000,正如您所期望的那样。(我不得不将迭代次数减少到2,以便ideone没有超时。)


1
这仅仅解释了为什么第一个结果是错误的;除非输入/输出因某种奇怪的原因需要整整三分之一秒钟,否则它与其他九个结果无关。 - user1084944
1
@Hurkyl:无论原因是什么,很明显这两个cout语句需要大约三分之一秒的时间才能执行。如果你不相信我,请试试我的版本。 - TonyK
1
这并不明确——它只是一种可能性。另一个主要的可能性是,差异是由于clock没有测量墙上时钟时间造成的。在我看来,接下来最有可能的原因是clock和/或time的分辨率低。 - user1084944
1
@Hurkyl:为什么不试试我的版本?然后我们就有一些数据可以讨论了。完整的源代码在ideone链接上。 - TonyK
1
在你发表回答之前,我已经删除了一个包含相同修复程序的答案。我删除它的原因基本上就是我在上面评论中给出的原因。请注意,Rob已经发布了clock函数的一个“陷阱”,而Daniel已经证明了它的相关性。 - user1084944

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接