如何在Windows上获得微秒级分辨率时间戳?
我正在寻找比QueryPerformanceCounter
和QueryPerformanceFrequency
更好的东西(这些只能给你一个自启动以来经过的时间,如果在不同的线程上调用它们,则不一定准确 - 即{{ 1}}可能会在不同的CPU上返回不同的结果。还有一些处理器会调整其频率以节省电量,这显然并不总是反映在他们的QueryPerformanceCounter
结果中。)
有 Implement a Continuously Updating, High-Resolution Time Provider for Windows ,但它似乎并不稳固。 When microseconds matter 看起来很棒,但不能再下载了。
另一个资源是 Obtaining Accurate Timestamps under Windows XP ,但它需要许多步骤,运行辅助程序以及一些初始化程序,我不确定它是否适用于多个CPU。
我还查看了维基百科的文章 Time Stamp Counter ,这篇文章很有意思,但没那么有用。
如果答案只是用BSD或Linux来做,那就更容易了,这很好,但我想确认这一点并得到一些解释,为什么在Windows中这么难以及如此容易Linux和BSD。它是相同的精品硬件......
答案 0 :(得分:19)
我相信这仍然有用:System Internals: Guidelines For Providing Multimedia Timer Support。
它很好地解释了各种可用的计时器及其局限性。可能你的大敌不会是解决方案,而是延迟。
QueryPerformanceCounter并不总是以CPU速度运行。实际上,它可能会尝试避免RDTSC,尤其是在多处理器(/多核)系统上:它将在Windows Vista及更高版本上使用HPET(如果可用)或{{3 }}。 在我的系统(Windows 7 x64,双核AMD)上,定时器运行在14.31818 MHz。
默认情况下,Windows Server 2003 Service Pack 2(SP2)对所有多处理器APIC或ACPI HAL使用PM计时器,除非用于确定BIOS是否支持APIC或ACPI HAL的检查过程失败。“
问题是,检查失败时。这只是意味着您的计算机/ BIOS在某种程度上被破坏了。然后你可以修复你的BIOS(推荐),或者至少暂时改用The same is true for earlier systems:。
通过ACPI timer (/usepmtimer)检查高分辨率计时器支持,然后查看P/Invoke,可以很容易地从C#开始 - 没有Stopwatch.IsHighResolution
。它将在内部进行必要的QueryPerformanceCounter调用。
同时考虑如果计时器坏了,整个系统将会受到严重破坏,一般情况下表现奇怪,报告负经过时间,放慢速度等等 - 而不仅仅是你的应用程序。
这意味着您实际上可以依赖QueryPerformanceCounter。
...与普遍看法相反,QueryPerformanceFrequency()
Stopwatch.Frequency
。
编辑:正如"cannot change while the system is running"上的文档所述,“调用哪个处理器应该无关紧要” - 事实上,只有在APIC / ACPI检测失败且系统出现时,才需要通过线程关联进行整个黑客攻击决定使用QueryPerformanceCounter()
。这是一个不应该发生的度假胜地。如果它发生在较旧的系统上,则可能是制造商提供的BIOS更新/驱动程序修复。如果没有,则/usepmtimer
启动开关仍然存在。如果这也失败了,因为系统除了Pentium TSC之外没有合适的计时器,你实际上可能会考虑搞乱线程亲和力 - 即使这样,其他人在页面的“社区内容”区域提供的样本也是如此。误导,因为它在每次启动/停止呼叫时设置了线程亲和力,因此具有不可忽略的开销 - 这会引入相当大的延迟,并且可能会降低首先使用高分辨率计时器的好处。
TSC 是关于如何正确使用它们的建议。请考虑它现在五年岁,并且当时更少的系统完全符合ACPI标准/支持 - 这就是为什么在抨击它时,文章详细介绍了TSC以及如何工作保持一个仿射线程围绕其局限性。
我认为现在找一个没有ACPI支持且没有可用的PM计时器的普通PC是一项相当艰巨的任务。最常见的情况可能是BIOS设置,当ACPI支持设置不正确时(有时可能出乎工厂默认设置)。
八年前,情况在极少数情况下有所不同。{p> Game Timing and Multicore Processors (做一个有趣的阅读,开发人员围绕设计“缺点”和抨击芯片设计师。公平地说,它可能是相同的反之亦然。: - )答案 1 :(得分:11)
QueryPerformanceCounter / QueryPerformanceFrequency,处理器速度分辨率
小心多线程。处理器上的每个核心都可以拥有自己的计数器。
更多信息位于 Obtaining Accurate Timestamps under Windows XP 。
如果你最终不得不采用这种方法:
当我尝试手动将数据写入串口(用于红外发射器)时,我发现将进程和线程优先级设置为最大值(实时)大大提高了其可靠性(因为没有错误),这是一些东西如果我也记得那么它必须具有大约40 kHz的分辨率,所以它应该保持足够精确到毫秒分辨率。
答案 2 :(得分:6)
Windows不是real-time OS。
多任务操作系统上的进程需要将时间转移到另一个线程/进程。这为计时提供了一些开销。
每次函数调用都会产生开销,因此在返回请求时会有一点延迟。
此外,调用系统调用将需要您的进程从用户空间模式切换到具有相对较高延迟的内核空间模式。您可以通过在内核模式下运行整个过程(例如设备驱动程序代码)来解决此问题。
某些操作系统(如Linux或BSD)更好,但仍无法将精确的时序分辨率维持在亚微秒级(例如nanosleep()的准确度在Linux上大约1毫秒,不少于1毫秒),除了你将内核修补到一些特定的调度程序,给你的应用程序带来好处。
所以我认为,最好调整您的应用程序以遵循这些问题,例如经常重新校准您的计时例程,这是您的链接提供的。 AFAIK,Windows的最高计时器分辨率仍然是GetPerformanceCounter / Frequency(),无论其准确性如何。通过在单独的线程中运行计时器池例程,并将该线程关联设置为一个核心处理器,并将线程优先级设置为可以获得的最高优先级,可以获得更高的准确性。
答案 3 :(得分:6)
QueryPerformanceCounter是对此的正确解决方案。与您和某些人回答您所写的内容相反,即使使用多处理器系统,此调用也会给出正确的答案(除非系统被破坏),并且它甚至可以处理更改的CPU频率。在大多数现代系统中,它源自RDTSC,但为您处理所有这些多CPU和频率变化的细节。 (但它明显慢于RDTSC。)
在多处理器计算机上,调用哪个处理器无关紧要。但是,由于基本输入/输出系统(BIOS)或硬件抽象层(HAL)中的错误,您可以在不同的处理器上获得不同的结果。
答案 4 :(得分:5)
我认为你不会找到比QueryPerformanceCounter更好的解决方案。标准技术是设置代码以捕获和丢弃可能由线程切换CPUs引起的后向时间跳转和大量异常值。如果你测量的间隔非常小(如果没有,那么你不需要那么精确),那么这种情况并不常见。只是让它成为一个容忍的错误,而不是一个严重的错误。
在绝对需要确保它永远不会发生的极少数情况下,通过设置处理器关联掩码来锁定线程是唯一的选择。
答案 5 :(得分:3)
到目前为止,答案中有很多好的信息。
如果你正在寻找的是一种直接的方式来获得自1970年1月1日以来在Windows XP或更高版本上以毫秒或更高分辨率获得的经过时间,那么这是一个非常简单的跨平台示例。 the CurrentTime.cpp of Apple's OSS release of JavaScriptCore for MacOS 10.7.5(我似乎无法在10.8+版本中找到它)。我引用的代码在CurrentTime()
函数中。
它使用标准技术使用QueryPerformanceCounter()
计算高于毫秒分辨率的经过时间差异,然后定期将其与系统时钟同步以计算时间戳并考虑时钟漂移。为了获得更高分辨率的时间戳,它需要您运行Windows XP或更高版本,以确保对QueryPeformanceFrequency()
的调用成功。
它没有考虑上下文切换略微抛弃(如"Implement a Continuously Updating, High-Resolution Time Provider for Windows"和"The Windows Timestamp Project"),但它会不断重新同步。我不会用它发射火箭,但是在大约50行代码中它很容易实现并且足够用于许多目的。
此外,如果您知道保证运行Windows 8 / Windows Server 2012,则应使用GetSystemTimePreciseAsFileTime()
,因为它以尽可能高的精度(1微秒或更高)返回系统日期和时间)。
答案 6 :(得分:1)
我使用了the DateTimePrecise class中的The Code Project。
我遇到的唯一问题是,如果我至少每10秒钟没有调用它会产生疯狂的结果 - 我认为内部存在某种整数溢出 - 所以我有一个执行的计时器每隔几秒DateTimePrecise.Now
。
如果您希望时间准确无误,您还应该在机器上运行NTP。
祝你好运......答案 7 :(得分:1)
我发现将PerformanceCounter
与PerformanceCounterFrequency
一起使用会遇到困难,因为给定的PerformanceCounterFrequency
会偏离实际频率。
偏离偏移,它也显示热漂移。较新的硬件似乎具有较小的漂移,但漂移和偏移是相当可观的。由于1 ppm为1μs/ s,因此几微ppm的漂移已经在很大程度上损害微秒精度!因此,在PerformanceCounter
与PerformanceCounterFrequency
一起使用时,强烈建议进行仔细的硬件特定校准。这也可能是在不经常调用某些功能时观察到“疯狂结果”的原因。
我对此事做了一些更详细的调查。可以在 Microsecond Resolution Time Services for Windows 中找到说明。