【问题标题】:Why are gettimeofday() intervals occasionally negative?为什么 gettimeofday() 间隔偶尔为负数?
【发布时间】:2011-02-16 08:13:29
【问题描述】:

我有一个实验库,我正在尝试衡量其性能。为此,我编写了以下内容:

struct timeval begin;
gettimeofday(&begin, NULL);
{
    // Experiment!
}
struct timeval end;
gettimeofday(&end, NULL);

// Print the time it took!
std::cout << "Time: " << 100000 * (end.tv_sec - begin.tv_sec) + (end.tv_usec - begin.tv_usec) << std::endl;

有时,我的结果会包含负时间,其中一些是荒谬的。例如:

Time: 226762
Time: 220222
Time: 210883
Time: -688976

发生了什么事?

【问题讨论】:

  • 你会得到否定,因为 timeval 是一个多组件结构。简而言之,由秒和微秒组成。如果您天真地将第二台电视中的常见组件与第一台电视进行区分,您将得到否定。例如,将 tv1 视为距纪元 1 秒 3 微秒,而 tv2 距纪元 4 秒和 1 微秒。如您所见,您现在在 usec 组件之间的差异中得到一个负值。
  • 这个问题你有 4 个答案,其中没有一个接近于提供正确答案,但你仍然选择了最不相关的一个作为最终答案。
  • 有趣的补充,但仅在使用其中一个组件时才相关,就像我正在做的那样(仅使用 tv_usec 组件,而不是 tv_sec 组件)。

标签: c++ c linux timing gettimeofday


【解决方案1】:

你有一个错字。更正了最后一行(注意0的数量):

std::cout << "Time: " << 1000000 * (end.tv_sec - begin.tv_sec) + (end.tv_usec - begin.tv_usec) << std::endl;

顺便说一句,timersub 是一种用于获取两个时间间隔之间差异的内置方法。

【讨论】:

  • 妈的,太丢人了。 :)
  • 为什么这被认为是答案?它不正确,它只是修复了时间表示中的一个小错误。它没有解决为什么会出现负面时期的核心问题。读者注意——这不是一个有效的答案!
  • @Zenikoder 是的。通常,被减数的绝对值(秒 * 1000000)会大于被减数,所以即使你转了一秒也不会得到负数。在这种情况下,被减数总是太小(缺少零,因数 10),所以第二个环绕在减数中产生了相对较大的负数。
  • 所以基本上,你需要对错误动脑筋才能深入理解它,但几乎……它仍然回答了这个问题。 :)
【解决方案2】:

posix 实时库更适合测量高精度间隔。你真的不想知道当前时间。您只想知道两点之间的时间。这就是单调时钟的用途。

struct timespec begin;
clock_gettime( CLOCK_MONOTONIC, &begin );
{
    // Experiment!
}
struct timespec end;
clock_gettime(CLOCK_MONOTONIC, &end );

// Print the time it took!
std::cout << "Time: " << double(end.tv_sec - begin.tv_sec) + (end.tv_nsec - begin.tv_nsec)/1000000000.0 << std::endl;

链接时需要添加-lrt

使用单调时钟有几个优点。它经常使用硬件定时器(Hz 晶振或其他),因此它通常比gettimeofday() 调用更快。即使 ntpd 或用户在使用系统时间,单调计时器也可以保证永远不会倒退。

【讨论】:

  • 我忘记了那些东西! Mac OS 没有实现 POSIX 实时库。不过,你是完全正确的。
【解决方案3】:

std::cout

如前所述,每秒有 1000000 usec,而不是 100000。

更一般地说,您可能需要注意计算机上计时的不稳定性。 ntpd 等进程可能会更改时钟时间,从而导致不正确的增量时间。您可能对 POSIX 工具感兴趣,例如 timer_create

【讨论】:

  • ntpd 的阴险之处在于,它会随着时间的推移分小步进行,因此更难被注意到。
【解决方案4】:

您处理了负值,但它仍然不正确。毫秒变量之间的差异是错误的,例如我们将开始时间和结束时间分别设置为 1.100 秒和 2.051 秒。根据接受的答案,这将是 1.049 秒的经过时间,这是不正确的。

下面的代码处理了只有毫秒而不是秒的差异以及毫秒值溢出的情况。

if(end.tv_sec==begin.tv_sec)
printf("Total Time =%ldus\n",(end.tv_usec-begin.tv_usec));
else
printf("Total Time =%ldus\n",(end.tv_sec-begin.tv_sec-1)*1000000+(1000000-begin.tv_usec)+end.tv_usec);

【讨论】:

    【解决方案5】:

    $ time ./proxy-application

    下次

    【讨论】:

    • 这让我无法为实验本身计时。所有的:内存分配器初始化、静态对象构造和程序的加载都包括在内。此外,这只是以秒为单位。
    猜你喜欢
    • 1970-01-01
    • 2013-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-12
    • 2014-11-18
    相关资源
    最近更新 更多