QueryPerformanceCounter 或 GetSystemTimePreciseAsFileTime 使用 SNTP 时?
Posted
技术标签:
【中文标题】QueryPerformanceCounter 或 GetSystemTimePreciseAsFileTime 使用 SNTP 时?【英文标题】:QueryPerformanceCounter or GetSystemTimePreciseAsFileTime When using SNTP? 【发布时间】:2016-01-01 15:26:40 【问题描述】:下面这段让我很困惑:
来自文章:Acquiring high-resolution time stamps
当您需要分辨率为 1 微秒或更高的时间戳时 而且您不需要将时间戳同步到外部 时间参考,选择 QueryPerformanceCounter, KeQueryPerformanceCounter 或 KeQueryInterruptTimePrecise。当你 需要分辨率为 1 微秒的 UTC 同步时间戳 或更好,选择 GetSystemTimePreciseAsFileTime 或 KeQuerySystemTimePrecise。
短语“要同步到外部时间参考”是什么意思? 确切的意思是这里? 我学到的是:
-
如果您的 PC 未连接到 GPS(通过串行端口或 SNTP),请使用 QueryPerformanceCounter。
如果 PC 已连接,则使用 GetSystemTimePreciseAsFileTime。
这个假设正确吗?
【问题讨论】:
【参考方案1】:各种 Windows 函数返回的“当前”时间并不总是以每分钟 60 秒的速度递增。
有时 Windows 有意让时钟走得慢一点,或者快一点:
如果您的 PC 时钟当前落后于当前正确时间:稍微运行快赶上 如果您的 PC 时钟当前领先于当前的正确时间:稍微慢一点让正确的时间赶上这个时间它会这样做而不是让你的时钟突然JUMP,现在你的日志文件有时间异常。
您可以使用GetSystemTimeAdjustment
查看Windows 当前是在更快 还是更慢 或以名义速率计时。例如,现在在我的电脑上:
但如果您的时钟距离正确时间太远,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 |
GetSystemTimePreciseAsFileTime |
FILE_TIME (0.1us) |
0.1 us | UTC |
随着你的时钟跳来跳去,都可以快、慢或跳来跳去。而 QueryPerformanceCounter 永远不会加速或减速。它始终以 60 秒/分钟的准确速率递增。
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 |
GetSystemTimePreciseAsFileTime |
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
,则经过的时间间隔由:
两者都会:
保持同步 彼此相差不到十分之几微秒 具有 100ns (0.1 us) 的终极分辨率要获得准确的时间测量,您应该使用这两个函数。问题,你关心哪一个任务:
GetSystemTimeAsPreciseFileTime:“现在”的高分辨率测量
适用于日志文件 事件的时间戳 “现在”的跨机协议同步到 UTCQueryPerformanceCounter:“经过时间”的高分辨率测量
适合基准测试 测量过程的持续时间奖金聊天
需要注意的是,GetLocalTime
和GetSystemTime
返回的SYSTEM_TIME
结构本质上仅限于毫秒精度。 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
精度浮点数,其中:
这是 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;
【讨论】:
如果您离得太远,您关于 windows 将如何将您的时间调整到正确时间的评论引起了我的注意。根据文档,听起来只有在禁用系统时间调整时才会这样做。当它被启用时,它没有完成,所以我想一个人完全有责任在他们这样做时保持时钟准确?如果启用系统时间调整并将调整设置为 0,那么您基本上只剩下具有不同返回类型的 QueryPerformanceCounter/Frequency 的副本吗?【参考方案2】:QueryPerformanceCounter() 会非常准确地告诉您自上次调用 QueryPerformanceCounter() 以来已经过去了多少时间。这作为秒表非常有用,可以计算经过的时间。
GetSystemTimePreciseAsFileTime() 根据某些参考(例如系统时钟)告诉您当前日历/日期时间的精确度稍差。例如,您可以使用它来打印“Dec 12 14:17:51 2016”。
因此,您的假设是不正确的。无论您拨打哪个电话,连接到 GPS 或网络时间源都不会改变。您的应用程序的需求将决定您应该调用哪个。
基本上你需要知道什么时间(GSTPAFT)或多少时间(QPC)?
【讨论】:
以上是关于QueryPerformanceCounter 或 GetSystemTimePreciseAsFileTime 使用 SNTP 时?的主要内容,如果未能解决你的问题,请参考以下文章
为啥与两者相比得到不同的毫秒值(QTIme 和 QueryPerformanceCounter)
QueryPerformanceCounter 是不是保证在启动后给您时间?