【问题标题】:Microsecond resolution timestamps on WindowsWindows 上的微秒分辨率时间戳
【发布时间】:2011-01-25 17:47:19
【问题描述】:

如何在 Windows 上获取微秒分辨率时间戳?

我正在寻找比 QueryPerformanceCounterQueryPerformanceFrequency 更好的东西(这些只能给你一个自启动以来经过的时间,如果它们在不同的线程上调用它们不一定准确 - 也就是说,QueryPerformanceCounter 可能返回不同不同 CPU 上的结果。还有一些处理器会调整频率以节省电量,这显然并不总是反映在他们的QueryPerformanceFrequency 结果中。)

Implement a Continuously Updating, High-Resolution Time Provider for Windows,但好像不牢固。 When microseconds matter 看起来不错,但现在无法下载了。

另一个资源是Obtaining Accurate Timestamps under Windows XP,但它需要一些步骤,运行一个帮助程序和一些初始化程序,我不确定它是否适用于多个 CPU。

我还查看了 Wikipedia 文章 Time Stamp Counter,这很有趣,但没那么有用。

如果答案是用 BSD 或 Linux 来做这件事,那会容易得多,这很好,但我想确认这一点,并解释一下为什么这在 Windows 中如此困难而在 Windows 中如此容易Linux 和BSD。都是一样的好硬件...

【问题讨论】:

  • 有没有例子说明如何在 Linux 或 BSD 中轻松实现?
  • 您知道,如果您阅读 QueryPeformanceCounter,它会明确表示它在从不同线程调用时确实工作,并且不受电源影响保存。唯一的例外是有缺陷的 BIOS、驱动程序和/或硬件。在关闭 API 之前阅读文档;)

标签: c++ windows boost time


【解决方案1】:

我相信这仍然有用:System Internals: Guidelines For Providing Multimedia Timer Support

它很好地解释了各种可用的计时器及其限制。您的大敌可能不是分辨率,而是延迟。

QueryPerformanceCounter 并不总是以 CPU 速度运行。事实上,它可能会尝试避免使用RDTSC,尤其是在多处理器(/多核)系统上:它会在 Windows Vista 及更高版本上使用HPET(如果可用)或ACPI/PM timer。 在我的系统(Windows 7 x64,双核 AMD)上,计时器以 14.31818 MHz 运行。

The same is true for earlier systems:

默认情况下,Windows Server 2003 Service Pack 2 (SP2) 对所有多处理器 APIC 或 ACPI HAL 使用 PM 计时器,除非确定 BIOS 是否支持 APIC 或 ACPI HAL 的检查过程失败。"

问题是,当检查失败时。这仅仅意味着您的计算机/BIOS 在某种程度上被破坏了。然后你可以修复你的 BIOS(推荐),或者至少暂时改用ACPI timer (/usepmtimer)

在 C# 中很容易 - 没有 P/Invoke - 使用 Stopwatch.IsHighResolution 检查高分辨率计时器支持,然后查看 Stopwatch.Frequency。它将在内部进行必要的 QueryPerformanceCounter 调用。

还要考虑,如果计时器坏了,整个系统将遭到破坏,并且通常会出现奇怪的行为,报告负的经过时间、速度变慢等 - 不仅仅是您的应用程序。

这意味着您实际上可以依赖 QueryPerformanceCounter。

...与普遍看法相反,QueryPerformanceFrequency()"cannot change while the system is running"

编辑:正如QueryPerformanceCounter() 上的文档所述,“调用哪个处理器无关紧要” - 事实上,只有在 APIC/ACPI 检测失败并且系统求助于使用TSC。这是一个不应该发生的度假胜地。如果它发生在较旧的系统上,则可能有制造商提供的 BIOS 更新/驱动程序修复。如果没有,/usepmtimer 引导开关仍然存在。如果这也失败了,因为系统除了 Pentium TSC 之外没有适当的计时器,您实际上可能会考虑弄乱线程关联性 - 即使这样,页面“社区内容”区域中其他人提供的示例也是由于在每个启动/停止调用上设置线程关联,它具有不可忽略的开销,因此具有误导性 - 这会引入相当大的延迟,并可能首先降低使用高分辨率计时器的好处。

Game Timing and Multicore Processors 是关于如何正确使用它们的建议。请考虑到它现在已经 5 年了,当时完全符合/支持 ACPI 的系统更少 - 这就是为什么在抨击它时,这篇文章详细介绍了 TSC 以及如何工作通过保持仿射线程来绕过其局限性。

我相信现在要找到一台支持零 ACPI 且没有可用 PM 计时器的普通 PC 是一项相当艰巨的任务。最常见的情况可能是 BIOS 设置,当 ACPI 支持设置不正确时(有时可悲的是出厂默认设置)。

Anecdotes tell 八年前,在极少数情况下情况有所不同。 (读起来很有趣,开发人员围绕设计“缺点”工作并抨击芯片设计师。公平地说,反之亦然。:-)

【讨论】:

  • 所以“使用 QueryPerformanceCounter”?哇,要是我想到了就好了……而且,即使在我的新核心 i7 上,这仍然会返回负面结果,所以要小心。另外,我认为没有人建议您更改线程亲和性只是为了调用 QueryPerformanceCounter 然后将其更改回来。只需将线程设置为一个核心即可。
  • @matt:我并不是说 - 或者这个线程中的任何人 - 建议在每次调用时更改线程关联。但是,在此页面上提供的社区内容就是这样做的:msdn.microsoft.com/en-us/library/ms644904%28VS.85%29.aspx
  • @matt:所以事实上,是的,使用 QPC - 但请确保它不使用 RDTSC,否则您最终会得到一个伪装得很好的对 RDTSC 的 API 调用。
  • 如果您需要 HPET,请确保 BIOS 中的设置正确。我遇到的一个是“ACPI HPET Table => Enabled”。另一个是“HPET Support => Enabled”,然后是“HPET Mode => 32bit/64bit”,具体取决于您运行的是 Vista(Win7) x86 还是 x64。 HPET:blog.fpmurphy.com/2009/07/linux-hpet-support.html HPET 仅适用于 Vista 及更高版本。 PM (ACPI) 计时器也可以在旧系统上使用。
  • @andras:很酷,我一定会检查一下 BIOS 设置!我肯定在至少一台频率与 CPU 时钟无关的计算机上完成了 QPC,并且可能更接近 14mhz 标记。 +1
【解决方案2】:

QueryPerformanceCounter / QueryPerformanceFrequency,处理器速度分辨率

请注意多线程。处理器上的每个内核都可以有自己的计数器。

更多信息在Obtaining Accurate Timestamps under Windows XP

如果你最终不得不求助于这种方法:

当我尝试手动将数据写入串行端口(用于红外发射器)时,我发现将进程和线程优先级设置为最大(实时)大大提高了它的可靠性(因为没有错误),这就是如果我也记得的话,它的分辨率必须在 40 kHz 左右,所以它应该保持足够精确到毫秒级的分辨率。

【讨论】:

  • 这些只能为您提供自启动以来经过的时间,如果它们在不同的线程上调用,则不一定准确 - 即 QueryPerformanceCounter 可能在不同的 CPU 上返回不同的结果。还有一些处理器为了省电而调整频率,这显然并不总是反映在它们的 QueryPerformanceFrequency 结果中。
  • @Kibibu 没错。我在问题中暗示我需要比 QueryPerformanceCounter QueryPerformanceFrequency 更好的东西,但没有详细说明原因。感谢您指出这一点。
  • @kibibu,如果这很重要,那么您已经让代码在特定处理器上运行。我忘了这叫什么……是处理器亲和性吗?
  • @kenny,是的,处理器亲和力。无论如何,这是我用来做所有高精度工作(例如分析)的方法,是的,我应该先阅读 msdn 链接,它建议将此作为解决方案,然后解释它是如何不完美的。 @Nikhil:我很好奇你为什么需要这个?理论上,所有 PC 都有一个系统时钟,可以在处理器断电时保持时间。我不知道那会是什么分辨率,或者如何得到它。
  • +1 表示正确回复。我知道正确的答复并不总是想要的答复。 QPC 是标准 Windows 发行版上可用的最高分辨率计时器 - 除非您想安装自定义硬件/驱动程序,否则您需要解决 QPC 的限制。
【解决方案3】:
  1. Windows 不是real-time OS

  2. 多任务操作系统上的进程需要将其时间让给另一个线程/进程。这会给计时带来一些开销。

  3. 每个函数调用都会有开销,因此在返回请求时会有一点延迟。

  4. 此外,调用系统调用将需要您的进程从用户空间模式切换到具有相对较高延迟的内核空间模式。您可以通过在内核模式下运行整个进程(例如设备驱动程序代码)来克服这个问题。

  5. 一些操作系统,如LinuxBSD,性能更好,但它们仍然无法保持精确到亚微秒的时间分辨率(例如,nanosleep() 在 Linux 上的精度约为 1 ms ,不少于 1 毫秒),除非您将内核修补到某些特定的调度程序,从而为您的应用程序带来好处。

所以我认为,最好调整您的应用程序以解决这些问题,例如通过经常重新校准您的计时程序,这就是您的链接所提供的。 AFAIK,Windows 的最高计时器分辨率仍然是 GetPerformanceCounter/Frequency(),无论其准确性如何。您可以通过在单独的线程中运行计时器池例程来获得更高的准确性,并将该线程关联设置为一个核心处理器,并将线程优先级设置为您可以获得的最高优先级。

【讨论】:

    【解决方案4】:

    我认为您不会找到比 QueryPerformanceCounter 更好的解决方案。标准技术是设置您的代码以捕获和丢弃可能由线程切换CPUs 导致的向后时间跳转和大量异常值。如果您正在测量非常小的间隔(如果不是,那么您不需要那种精度),那么这无论如何都不是常见的事情。只需将其设为可容忍错误而不是严重错误即可。

    在极少数情况下,您绝对需要确保它永远不会发生,那么通过设置处理器关联掩码来锁定您的线程是唯一的选择。

    【讨论】:

      【解决方案5】:

      QueryPerformanceCounter 是解决此问题的正确方法。与你和一些回答你的人写的相反,这个调用即使在多处理器系统中也能给出正确的答案(除非有问题的系统被破坏了),它甚至可以处理 CPU 频率的变化。在大多数现代系统上,它源自RDTSC,但会为您处理所有这些多 CPU 和频率变化的细节。 (不过,它比 RDTSC 慢得多)。

      QueryPerformanceCounter

      在多处理器计算机上,调用哪个处理器并不重要。但是,由于基本输入/输出系统 (BIOS) 或硬件抽象层 (HAL) 中的错误,您可能会在不同的处理器上得到不同的结果。

      【讨论】:

        【解决方案6】:

        到目前为止,答案中有很多很好的信息。

        如果您正在寻找一种在 Windows XP 或更高版本上以毫秒或更高分辨率获取自 1970 年 1 月 1 日以来经过的时间的简单方法,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 微秒或更好)返回系统日期和时间。

        【讨论】:

        【解决方案7】:

        我从The Code Project 使用过the DateTimePrecise class

        我遇到的唯一问题是,如果我不至少每 10 秒调用一次它会给出疯狂的结果——我认为内部存在某种整数溢出——所以我有一个执行的计时器DateTimePrecise.Now 每隔几秒。

        如果您希望时间完全准确,您还应该在机器上运行NTP

        祝你好运……

        【讨论】:

          【解决方案8】:

          我发现使用PerformanceCounterPerformanceCounterFrequency 有困难,因为给定的PerformanceCounterFrequency 与实际频率有偏差。

          它偏离了一个偏移量,并且还显示了热漂移。较新的硬件似乎漂移较少,但漂移和偏移量相当可观。几 ppm 的漂移已经在很大程度上损害了微秒精度,因为 1 ppm 是 1 µs/s!因此,当使用PerformanceCounterPerformanceCounterFrequency 时,强烈建议仔细进行特定于硬件的校准。这也可能是在不频繁调用某些函数时观察到“疯狂结果”的原因。

          我对这件事做了一些更详细的调查。可以在 Microsecond Resolution Time Services for Windows 中找到描述。

          【讨论】:

            猜你喜欢
            • 2012-11-12
            • 2015-01-17
            • 1970-01-01
            • 2015-08-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多