为什么微秒时间戳使用(私有)gettimeoftheday()即epoch是重复的

时间:2012-11-01 10:55:58

标签: c++ performance time timestamp epoch

我使用gettimeofday()连续打印微秒。如程序输出中所示,您可以看到时间不是更新的微秒间隔,而是某些样本的重复时间,然后增量不是以微秒为单位,而是以毫秒为单位。

while(1)
{
  gettimeofday(&capture_time, NULL);
  printf(".%ld\n", capture_time.tv_usec);
}

节目输出:

.414719
.414719
.414719
.414719
.430344
.430344
.430344
.430344

 e.t.c

我希望输出顺序递增,如

.414719
.414720
.414721
.414722
.414723

.414723, .414723+x, .414723+2x, .414723 +3x + ...+ .414723+nx

当我从capture_time.tv_usec获取它时,似乎没有刷新微秒。

================================= //完整计划

#include <iostream>
#include <windows.h>
#include <conio.h>
#include <time.h>
#include <stdio.h>

#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
  #define DELTA_EPOCH_IN_MICROSECS  11644473600000000Ui64
#else
  #define DELTA_EPOCH_IN_MICROSECS  11644473600000000ULL
#endif

struct timezone 
{
  int  tz_minuteswest; /* minutes W of Greenwich */
  int  tz_dsttime;     /* type of dst correction */
};

timeval capture_time;  // structure

int gettimeofday(struct timeval *tv, struct timezone *tz)
{
  FILETIME ft;
  unsigned __int64 tmpres = 0;
  static int tzflag;

  if (NULL != tv)
  {
    GetSystemTimeAsFileTime(&ft);

    tmpres |= ft.dwHighDateTime;
    tmpres <<= 32;
    tmpres |= ft.dwLowDateTime;

    /*converting file time to unix epoch*/
    tmpres -= DELTA_EPOCH_IN_MICROSECS; 
    tmpres /= 10;  /*convert into microseconds*/
    tv->tv_sec = (long)(tmpres / 1000000UL);
    tv->tv_usec = (long)(tmpres % 1000000UL);
  }

  if (NULL != tz)
  {
    if (!tzflag)
    {
      _tzset();
      tzflag++;
    }

    tz->tz_minuteswest = _timezone / 60;
    tz->tz_dsttime = _daylight;
  }

  return 0;
}

int main()
{
   while(1)
  {     
    gettimeofday(&capture_time, NULL);     
    printf(".%ld\n", capture_time.tv_usec);// JUST PRINTING MICROSECONDS    
   }    
}

4 个答案:

答案 0 :(得分:7)

您观察到的时间变化为0.414719 s至0.430344 s。差异是15.615毫秒。数字表示为微秒的事实意味着它增加1微秒。事实上,我预计会有15.625毫秒。这是标准硬件上的系统时间增量。我仔细研究了herehere。 这称为系统时间的粒度

<强>窗:

但是,有一种方法可以改善这种情况,这是一种减少粒度的方法:Multimedia Timers。特别是Obtaining and Setting Timer Resolution将公开一种增加系统中断频率的方法。

代码:

#define TARGET_PERIOD 1         // 1-millisecond target interrupt period


TIMECAPS tc;
UINT     wTimerRes;

if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR) 
// this call queries the systems timer hardware capabilities
// it returns the wPeriodMin and wPeriodMax with the TIMECAPS structure
{
  // Error; application can't continue.
}

// finding the minimum possible interrupt period:

wTimerRes = min(max(tc.wPeriodMin, TARGET_PERIOD ), tc.wPeriodMax);
// and setting the minimum period:

timeBeginPeriod(wTimerRes); 

这将强制系统以其最大中断频率运行。作为结果 系统时间的更新也会更频繁地发生,大多数系统的系统时间增量的粒度将为close to 1 milisecond

当您需要超出此范围的分辨率/粒度时,您必须查看QueryPerformanceCounter。但是在长时间使用时要小心使用。可以通过调用QueryPerformanceFrequency来获得此计数器的频率。操作系统将此频率视为常量,并始终给出相同的值。但是,某些硬件会产生此频率,而真实频率与给定值不同。它有一个偏移,它显示出热漂移。因此,误差应假定在几微秒至几微秒的范围内。有关这方面的更多详细信息,请参见上面的第二个“此处”链接。

<强> Linux的:

Linux的情况有所不同。请参阅this以了解相关信息。 Linux的 使用函数getnstimeofday使用函数timekeeping_get_ns(自纪元以来的秒数)和来自高频率计数器(微秒)的信息混合CMOS时钟的信息。这不是微不足道的,并且在准确性方面存在问题,因为两个源都有不同的硬件支持。这两个源不是锁相的,因此可以更多/更少,而不是每秒一百万微秒。

答案 1 :(得分:1)

Windows系统时钟每隔几毫秒才会打勾 - 在您的情况下每秒64次,所以当它打勾时,系统时间会增加15.625毫秒。

解决方案是使用更高分辨率的计时器,即系统时间(QueryPerformanceCounter)。

你仍然不会看到.414723,.414723 + x,.414723 + 2x,.414723 + 3x + ... + .414723 + nx,因为你的代码每次{{1微秒。它会尽可能快地运行,但没有特别的理由应该始终是一个恒定的速度,或者如果它是一个整数微秒。

答案 2 :(得分:1)

我建议你查看C ++ 11 <chrono>标题。

  

high_resolution_clock(C ++ 11)具有最短滴答时间的时钟

此处提到的节拍周期是时钟更新的频率。如果我们查看more details

template<
     class Rep,
     class Period = std::ratio<1>
> class duration;
     

类模板std::chrono::duration表示时间间隔。

     

它包含Rep类型的刻度计数和刻度周期,其中刻度周期是编译时有理常数,表示从一个刻度到下一个刻度的秒数。

以前,像gettimeofday这样的函数会给你一个以微秒表示的时间,但是他们完全没有告诉你这个时间表达式被刷新的时间间隔。

在C ++ 11标准中,此信息现在已经明确,显而易见的是,表达时间的单位与刻度周期之间没有关系。因此,您肯定需要将两者都考虑在内。

当您想要测量接近它的持续时间时, tick 期间非常重要。如果你想测量的持续时间低于滴答期,那么你将像你观察到的那样“离散地”测量它:0,0,0,1,0,0,0,1,0,0,0,1, ......我建议在这一点上谨慎。

答案 3 :(得分:0)

这是因为运行代码的进程并不总是安排执行。

虽然它确实如此,它会快速绕过循环,每微秒打印多个值 - 这是现代CPU上相对较长的一段时间。

有些时间段没有安排系统执行,因此无法打印值。

如果您要执行的操作是每微秒执行一次,则可以使用在高性能硬件上运行的某些实时操作系统。