QueryPerformanceCounter或GetSystemTimePreciseAsFileTime使用SNTP时?

时间:2016-01-01 15:26:41

标签: performancecounter

以下段落让我感到困惑:

来自文章:Acquiring high-resolution time stamps

  

当您需要分辨率为1微秒或更高的时间戳时   并且您不需要将时间戳同步到外部   时间参考,选择QueryPerformanceCounter,   KeQueryPerformanceCounter,或KeQueryInterruptTimePrecise。当你   需要UTC同步时间戳,分辨率为1微秒   或者更好,选择GetSystemTimePreciseAsFileTime或   KeQuerySystemTimePrecise。

短语" 与外部时间参考同步" 这意味着什么? 我学到的是:

  1. 如果您的PC未连接到GPS(通过串行端口或SNTP),请使用 QueryPerformanceCounter
  2. 如果已连接PC,请使用 GetSystemTimePreciseAsFileTime
  3. 这个假设是否正确?

2 个答案:

答案 0 :(得分:8)

各种Windows功能返回的“当前”时间并不总是以每分钟60秒的速度计数。

有时Windows 故意让时钟慢一点,或者更快一点:

  • 如果您的PC时钟目前落后于当前正确的时间:稍微更快以便赶上
  • 如果您的PC时钟目前超过当前的正确时间:稍微以让正确的时间赶上这个

这样做而不是让您的时钟突然 JUMP ,现在您的日志文件存在时间异常。

您可以使用GetSystemTimeAdjustment查看Windows当前是否正在以更快更慢或以名义价格计算时钟。例如,现在在我的电脑上:

  • 系统时间调整:已停用
  • 每次更新增加名义上的15,6250毫秒

但如果您的时钟距离正确的时间太远,Windows只会 BONK 您的时间到正确的时间。

时间可以快速,慢速,向前跳跃,向后跳跃。 QueryPerformanceCounter不会

所以返回的时间是:

| Function                       | Return type       | Resolution | Timezone |
|--------------------------------|-------------------|------------|----------|
| GetLocalTime                   | SYSTEM_TIME (1ms) | ~10-15 ms  | Local    |
| GetSystemTime                  | SYSTEM_TIME (1ms) | ~10-15 ms  | UTC      |
| GetSystemTimeAsFileTime        | FILE_TIME (0.1us) | ~10-15 ms  | UTC      |
| GetSystemTimeAsPreciseFileTime | FILE_TIME (0.1us) | 0.1 us     | UTC      |

随着时钟的跳跃,所有人都可以快速,慢速或跳跃。虽然 QueryPerformanceCounter 永远不会加速或减速。它总是以60s / min的速率计数。

| Function                       | Return type       | Resolution | Timezone |
|--------------------------------|-------------------|------------|----------|
| GetLocalTime                   | SYSTEM_TIME (1ms) | ~10-15 ms  | Local    |
| GetSystemTime                  | SYSTEM_TIME (1ms) | ~10-15 ms  | UTC      |
| GetSystemTimeAsFileTime        | FILE_TIME (0.1us) | ~10-15 ms  | UTC      |
| GetSystemTimeAsPreciseFileTime | FILE_TIME (0.1us) | 0.1 us     | UTC      |
|                                |                   |            |          |
| GetTickCount                   | Int32 (1ms)       | ~10-15 ms  | n/a      |
| GetTickCount64                 | Int64 (1ms)       | ~10-15 ms  | n/a      |
| QueryPerformanceCounter        | Int64 (ticks)     | 0.1 us     | n/a      |

那你关心什么

只要您的计算机时钟当前不在SystemTimeAdjustment,经过的时间间隔就会测量:

  • GetSytemTimeAsPreciseFileTime
  • QueryPerformanceCounter的

将:

  • 同步
  • 彼此在十分之几微秒内
  • 的最终分辨率为100ns(0.1 us)

对于准确的时间测量,这些是您应该使用的两个功能。问题是,你关心哪个任务:

  • GetSystemTimeAsPreciseFileTime :“现在”的高分辨率测量

    • 适用于日志文件
    • 事件的时间戳
    • 与UTC同步以获得“now”
    • 的跨机器协议
  • QueryPerformanceCounter :“经过时间”的高分辨率测量

    • 适合做替补标记
    • 测量过程的持续时间

Bonus Chatter

应该注意SYSTEM_TIMEGetLocalTime返回的GetSystemTime结构固有地限于毫秒精度。 GetSystemTime无法为您提供亚毫秒级的分辨率,因为返回类型无法为您提供微秒:

struct SYSTEMTIME {
     WORD wYear;
     WORD wMonth;
     WORD wDay;
     WORD wHour;
     WORD wMinute;
     WORD wSecond;
     WORD wMilliseconds; //<---- that's the limit
}

当您希望Windows将时间缩短为数年,数月,数天,数小时,分钟,秒时,您应该只使用SYSTEM_TIME。另一方面,FILE_TIME结构的最终精度为100ns(0.1 us)。

精确时间功能

在我使用的语言中,我们使用DateTime精度浮点Double,其中:

  • 整数部分表示自12/30/1899以来的天数
  • 小数部分代表24小时工作日的一小部分

这是COM,OLE,Delphi,VB,Excel,Lotus 123使用的日期时间方案;和SQL Server使用的日期时间方案类似(尽管它们使用的是1/1/1900而不是12/30/1899)

DateTime UtcNowPrecise()
{
   const UInt64 OA_ZERO_TICKS = 94353120000000000; //12/30/1899 12:00am in ticks
   const UInt64 TICKS_PER_DAY = 864000000000;      //ticks per day

   FILE_TIME ft;
   GetSystemTimePreciseAsFileTime(out ft);

   ULARGE_INTEGER dt; //needed to avoid alignment faults
   dt.LowPart  = ft.dwLowDateTime;
   dt.HighPart = ft.dwHighDateTime;

   return (dt.QuadPart - OA_ZERO_TICKS) / TICKS_PER_DAY;
}

DateTime NowPrecise()
{
   const UInt64 OA_ZERO_TICKS = 94353120000000000; //12/30/1899 12:00am in ticks
   const UInt64 TICKS_PER_DAY = 864000000000;      //ticks per day

   FILE_TIME ft;
   GetSystemTimePreciseAsFileTime(out ft);

   //Convert from UTC to local
   FILE_TIME ftLocal;
   if (!FileTimeToLocalFileTime(ft, ref ftLocal))
      RaiseLastNativeError();

   ULARGE_INTEGER dt; //needed to avoid alignment faults
   dt.LowPart  = ftLocal.dwLowDateTime;
   dt.HighPart = ftLocal.dwHighDateTime;

   return (dt.QuadPart - OA_ZERO_TICKS) / TICKS_PER_DAY;
}

答案 1 :(得分:0)

QueryPerformanceCounter()将告诉您自上次调用QueryPerformanceCounter()以来经过了多长时间。作为秒表非常有用,可以计算经过的时间。

GetSystemTimePreciseAsFileTime()会根据某些参考(例如系统时钟)略微精确地告诉您当前的日历/日期时间。例如,您可以使用它打印出2016年12月12日14:17:51&#34;。

因此,您的假设不正确。连接到GPS或网络时间源无论是否呼叫其中一个都不会改变。您的应用程序的需求将决定您应该调用哪个。

基本上你需要知道什么时间(GSTPAFT)或多少时间(QPC)?