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

Osa*_*aid 2 c++ performance time timestamp epoch

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

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

节目输出:

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

 e.t.c
Run Code Online (Sandbox Code Playgroud)

我希望输出顺序递增,如,

.414719
.414720
.414721
.414722
.414723
Run Code Online (Sandbox Code Playgroud)

要么

.414723, .414723+x, .414723+2x, .414723 +3x + ...+ .414723+nx
Run Code Online (Sandbox Code Playgroud)

当我从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    
   }    
}
Run Code Online (Sandbox Code Playgroud)

Arn*_*rno 7

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

视窗:

但是,有一种方法可以改善这种,这是一种减少粒度的方法:多媒体计时器.特别是获取和设置定时器分辨率将公开一种增加系统中断频率的方法.

代码:

#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); 
Run Code Online (Sandbox Code Playgroud)

这将强制系统以其最大中断频率运行.因此,更频繁地更新系统时间,并且系统时间增量的粒度将close to 1 milisecond在大多数系统上.

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

Linux的:

Linux的情况看起来有些不同.看到这个以获得一个想法.Linux的混合使用函数CMOS时钟的信息getnstimeofday使用功能(对于自纪元秒),并从高freqeuncy计数器(用于微秒)信息timekeeping_get_ns.这不是微不足道的,并且在准确性方面存在问题,因为两个源都有不同的硬件支持.这两个源不是锁相的,因此每秒可以获得多于/少于一百万微秒.