【问题标题】:Why is CLOCKS_PER_SEC not the actual number of clocks per second?为什么 CLOCKS_PER_SEC 不是每秒的实际时钟数?
【发布时间】:2012-05-14 09:58:43
【问题描述】:

我刚刚编写了这个简短的 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 不匹配?他们甚至不大致相等。这是怎么回事?

【问题讨论】:

  • 请注意,您可能会循环不到一秒钟。如果你打电话给time,下一秒还有 200 毫秒,那么你将循环约 200 毫秒。无论如何,这可能不是这里的主要问题。
  • 是的,我意识到这就是循环的第一次迭代返回的结果比后续迭代小的原因。但我的问题是关于后续的迭代。我想我应该说清楚。
  • 现在您仍然会在每次后续迭代中获得 cout 的开销。等到你开始测量前一秒。

标签: c++ clock system-clock


【解决方案1】:

来自clock(3)的手册页:

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 时间。

【讨论】:

  • 虽然这在技术上是正确的,但因为他使用的系统调用也尊重它是无用的。
【解决方案2】:

clock 返回在您的程序中花费的时间。每秒总共有 1,000,000 个时钟滴答*。看来您的程序消耗了其中的 60%。

其他 40% 被其他人使用。

*好的,实际上每秒有 1,000,000 个时钟滴答。实际数字已标准化,因此您的程序可以感知 1,000,000 个滴答声。

【讨论】:

    【解决方案3】:

    嗯嗯。你不知道你开始计时的当前秒有多远,是吗?所以你可以得到从 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 才不会超时。)

    【讨论】:

    • 这只是解释为什么第一个结果是错误的;它与其他九个无关。 (除非出于某种奇怪的原因,I/O 需要整整三分之一秒)
    • @Hurkyl:不管是什么原因,很明显这两个cout 语句需要大约三分之一秒的时间来执行。不信,试试我的版本。
    • 这不是明确 - 这只是一种可能性。另一个主要可能性是差异是由于clock 没有测量挂钟时间。下一个最有可能的是 IMO,clock 和/或 time 的分辨率较低。
    • @Hurkyl:你为什么不试试我的版本?然后我们将有一些数据来讨论。完整的源代码在ideone link
    • 在您发布答案之前,我已经删除了一个包含相同修复的答案。我删除它的原因基本上是我在上面的 cmets 中给出的。请注意,Rob 已经发布了 clock 函数的“陷阱”之一,Daniel 已经证明了它的相关性。
    【解决方案4】:
    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。
    【解决方案5】:

    C99 标准

    C99 N1256 standard draft 关于CLOCKS_PER_SEC 的唯一说法是:

    CLOCKS_PER_SEC 它扩展为一个 clock_t 类型的表达式(如下所述),即 时钟函数返回值的每秒数

    正如其他人提到的,POSIX 将其设置为 100 万,这将其精度限制为 1 微秒。我认为这只是以兆赫兹为单位测量最大 CPU 频率的日子的历史值。

    【讨论】:

      【解决方案6】:

      当您设置 int first_time = time(NULL); 时,time(NULL) 可能是“1 纳秒之外”,(因为它被截断了),从变为 +1。因此,while(time(NULL) 可以比 1 秒更快地跳过,比您预期的要快。

      这就是为什么你的那“1 秒”中的时钟更少。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-06-09
        • 1970-01-01
        • 2020-10-16
        • 2010-10-02
        • 2018-06-19
        • 1970-01-01
        • 2012-06-05
        • 2011-03-15
        相关资源
        最近更新 更多