Windows 上的微秒分辨率时间戳
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2414359/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Microsecond resolution timestamps on Windows
提问by Nikhil
How do I get microsecond resolution timestamps on Windows?
如何在 Windows 上获得微秒分辨率的时间戳?
I am loking for something better than QueryPerformanceCounter
and QueryPerformanceFrequency
(these can only give you an elapsed time since boot and are not necessarily accurate if they are called on different threads - that is, QueryPerformanceCounter
may return different results on different CPUs. There are also some processors that adjust their frequency for power saving, which apparently isn't always reflected in their QueryPerformanceFrequency
result.)
我正在寻找比QueryPerformanceCounter
and更好的东西QueryPerformanceFrequency
(这些只能给你一个自启动以来经过的时间,如果在不同的线程上调用它们不一定准确 - 也就是说,QueryPerformanceCounter
可能在不同的 CPU 上返回不同的结果。还有一些处理器可以调整他们的节电频率,这显然并不总是反映在他们的QueryPerformanceFrequency
结果中。)
There is Implement a Continuously Updating, High-Resolution Time Provider for Windows, but it does not seem to be solid. When microseconds matterlooks great, but it's not available for download any more.
有实现一个用于Windows的不断更新,高解析度时间提供,但它似乎并不稳固。当微秒很重要时,它不再可供下载。
Another resource is Obtaining Accurate Timestamps under Windows XP, but it requires a number of steps, running a helper program plus some init stuff also, I am not sure if it works on multiple CPUs.
另一个资源是在 Windows XP 下获取准确的时间戳,但它需要许多步骤,运行帮助程序以及一些初始化程序,我不确定它是否适用于多个 CPU。
I also looked at the Wikipedia article Time Stamp Counterwhich is interesting, but not that useful.
我还查看了 Wikipedia 文章Time Stamp Counter,它很有趣,但不是很有用。
If the answer is just do this with BSD or Linux, it's a lot easier and that's fine, but I would like to confirm this and get some explanation as to why this is so hard in Windows and so easy in Linux and BSD. It's the same fine hardware...
如果答案只是在 BSD 或 Linux 上执行此操作,那就容易多了,这很好,但我想确认这一点,并解释为什么这在 Windows 中如此困难而在 Linux 和BSD 中如此简单。它是相同的精美硬件......
回答by Andras Vass
I believe this is still useful: System Internals: Guidelines For Providing Multimedia Timer Support.
我相信这仍然有用:系统内部:提供多媒体定时器支持的指南。
It does a good job of explaining the various timers available and their limitations. It might be that your archenemy will not so much be resolution, but latency.
它很好地解释了各种可用的计时器及其限制。可能你的大敌不是分辨率,而是延迟。
QueryPerformanceCounterwill not always run at CPU speed. In fact, it might try to avoid RDTSC, especially on multi-processor(/multi-core) systems: it will use the HPETon Windows Vista and later if it is available or the ACPI/PM timer. On my system (Windows 7 x64, dual core AMD) the timer runs at 14.31818 MHz.
QueryPerformanceCounter不会总是以 CPU 速度运行。事实上,它可能会尝试避免RDTSC,尤其是在多处理器(/多核)系统上:它将在 Windows Vista 和更高版本上使用HPET(如果可用)或ACPI/PM 计时器。在我的系统(Windows 7 x64,双核 AMD)上,计时器以 14.31818 MHz 运行。
The same is true for earlier systems:
By default, Windows Server 2003 Service Pack 2 (SP2) uses the PM timer for all multiprocessor APIC or ACPI HALs, unless the check process to determine whether the BIOS supports the APIC or ACPI HALs fails."
默认情况下,Windows Server 2003 Service Pack 2 (SP2) 对所有多处理器 APIC 或 ACPI HAL 使用 PM 计时器,除非确定 BIOS 是否支持 APIC 或 ACPI HAL 的检查过程失败。”
The problem is, when the check fails. This simply means that your computer/BIOS is broken in a way. Then you might either fix your BIOS (recommended), or at least switch to using the ACPI timer (/usepmtimer)for the time being.
问题是,当检查失败时。这只是意味着您的计算机/BIOS 以某种方式损坏了。然后您可以修复您的 BIOS(推荐),或者至少暂时切换到使用ACPI 计时器 (/usepmtimer)。
It is easy from C# - without P/Invoke- to check for high-resolution timer support with Stopwatch.IsHighResolution
and then peek at Stopwatch.Frequency
. It will make the necessary QueryPerformanceCounter call internally.
从 C# 很容易 - 没有P/Invoke- 检查高分辨率计时器支持,Stopwatch.IsHighResolution
然后查看Stopwatch.Frequency
. 它将在内部进行必要的 QueryPerformanceCounter 调用。
Also consider that if the timers are broken, the whole system will go havoc and in general, behave strangely, reporting negative elapsed times, slowing down, etc. - not just your application.
还要考虑的是,如果计时器坏了,整个系统将发生严重破坏,并且通常会表现得很奇怪,报告经过的时间为负数,速度变慢等 - 不仅仅是您的应用程序。
This means that you can actually rely on QueryPerformanceCounter.
这意味着您实际上可以依赖 QueryPerformanceCounter。
... and contrary to popular belief, QueryPerformanceFrequency()
"cannot change while the system is running".
...与流行的看法相反,QueryPerformanceFrequency()
“系统运行时无法更改”。
Edit: As the documentation on QueryPerformanceCounter()
states, "it should not matter which processor is called" - and in fact the whole hacking around with thread affinity is only needed if the APIC/ACPI detection fails and the system resorts to using the TSC. It is a resort that should not happen. If it happens on older systems, there is likely a BIOS update/driver fix from the manufacturer. If there is none, the /usepmtimer
boot switch is still there. If that fails as well, because the system does not have a proper timer apart from the Pentium TSC, you might in fact consider messing with thread affinity - even then, the sample provided by others in the "Community Content" area of the page is misleading as it has a non-negligible overhead due to setting thread affinity on every start/stop call - that introduces considerable latency and likely diminishes the benefits of using a high resolution timer in the first place.
编辑:正如有关文档QueryPerformanceCounter()
所述,“调用哪个处理器无关紧要” - 事实上,只有当 APIC/ACPI 检测失败并且系统求助于使用TSC 时,才需要使用线程关联进行整个黑客攻击。这是一个不应该发生的度假胜地。如果它发生在较旧的系统上,则制造商可能会进行 BIOS 更新/驱动程序修复。如果没有,则/usepmtimer
开机开关还在。如果这也失败了,因为系统除了 Pentium TSC 之外没有合适的计时器,您实际上可能会考虑弄乱线程关联 - 即使这样,页面的“社区内容”区域中其他人提供的示例是误导,因为由于在每次启动/停止调用时设置线程关联性,它具有不可忽略的开销 - 这会引入相当大的延迟并可能首先减少使用高分辨率计时器的好处。
Game Timing and Multicore Processorsis a recommendation on how to use them properly. Please consider that it is now fiveyears old, and at that time fewer systems were fully ACPI compliant/supported - that is why while bashing it, the article goes into so much detail about TSC and how to work around its limitations by keeping an affine thread.
游戏计时和多核处理器是关于如何正确使用它们的建议。请考虑到它现在已经有五年历史了,当时完全符合/支持 ACPI 的系统更少——这就是为什么在抨击它的同时,文章详细介绍了 TSC 以及如何通过保持仿射来解决其局限性线。
I believe it is a fairly hard task nowadays to find a common PC with zero ACPI support and no usable PM timer. The most common case is probably BIOS settings, when ACPI support is incorrectly set (sometimes sadly by factory defaults).
我相信如今要找到具有零 ACPI 支持且没有可用 PM 计时器的通用 PC 是一项相当艰巨的任务。最常见的情况可能是 BIOS 设置,当 ACPI 支持设置不正确时(有时令人遗憾的是出厂默认设置)。
Anecdotes tellthat eight years ago, the situation was different in rare cases. (Makes a fun read, developers working around design "shortcomings" and bashing chip designers. To be fair, it might be the same way vice versa. :-)
轶事表明,八年前,情况在极少数情况下有所不同。(读起来很有趣,开发人员在解决设计“缺点”并抨击芯片设计人员。公平地说,反之亦然。:-)
回答by matt
QueryPerformanceCounter / QueryPerformanceFrequency, processor speed resolution
QueryPerformanceCounter / QueryPerformanceFrequency,处理器速度分辨率
Just be careful with multi-threaded. Each core on a processor can have its own counter.
小心多线程。处理器上的每个内核都可以有自己的计数器。
Some more information is in Obtaining Accurate Timestamps under Windows XP.
在 Windows XP 下获取准确时间戳中提供了更多信息。
If you do end up having to resort to this method:
如果你最终不得不求助于这种方法:
When I was trying to manually write data to a serial port (for an infrared transmitter) I found that setting the process and thread priority to maximum (real time) greatly improved its reliability (as in no errors), this is something that had to have a resolution of around 40 kHz if I remember too, so it should remain accurate enough for millisecond resolution.
当我尝试手动将数据写入串行端口(对于红外发射器)时,我发现将进程和线程优先级设置为最大(实时)大大提高了其可靠性(因为没有错误),这是必须的如果我也记得的话,它的分辨率大约为 40 kHz,所以它应该保持足够精确的毫秒分辨率。
回答by uray
Windows is not a real-time OS.
Processes on a multitasking OS will need to yield its time to another thread/process. This gives some overhead for timing.
Every function call will have overhead thus giving a little delay when returning the request.
Furthermore, the calling system call will need your process to switch from user space mode to kernel space mode, which has relatively high latency. You can overcome this by running the entire process in kernel mode (such as device driver code).
Some OSes, like Linuxor BSD, are better, but they still can not maintain accurate timing resolution to sub-microsecond (for example, the accuracy of nanosleep()on Linux is about 1 ms, not less than 1 ms), except you patch the kernel to some specific scheduler that give your application benefits.
Windows 不是实时操作系统。
多任务操作系统上的进程需要将时间让给另一个线程/进程。这为计时提供了一些开销。
每个函数调用都会有开销,因此在返回请求时会有一点延迟。
此外,调用系统调用将需要您的进程从用户空间模式切换到内核空间模式,这具有相对较高的延迟。您可以通过在内核模式下运行整个进程(例如设备驱动程序代码)来克服这个问题。
一些操作系统,如Linux或BSD更好,但它们仍然无法保持精确到亚微秒的计时分辨率(例如,Linux 上的nanosleep()精度约为 1 毫秒,不低于 1 毫秒),除了你将内核修补到某些特定的调度程序,从而为您的应用程序带来好处。
So I think, it's better to adapt your application to follow those issues, such as by recalibrating your timing routine often, which is what your links provide. AFAIK, the highest timer resolution for Windows is still GetPerformanceCounter/Frequency() regardless of its accuracy. You can get better accuracy by running you timer pooling routine inside a separate thread, and set that thread affinity to one core processor, and set the thread priority the highest you can get.
所以我认为,最好使您的应用程序适应这些问题,例如经常重新校准您的计时例程,这是您的链接提供的。AFAIK,Windows 的最高计时器分辨率仍然是 GetPerformanceCounter/Frequency() 无论其准确性如何。您可以通过在单独的线程中运行计时器池例程来获得更高的准确性,并将该线程关联设置为一个核心处理器,并将线程优先级设置为您可以获得的最高。
回答by Suma
QueryPerformanceCounter is the correct solution to this. Contrary to what you and some people answering you wrote, this call gives the correct answer even with multiprocessor systems (unless the system in question is broken), and it handles even changing CPU frequency. On most modern systems it is derived from RDTSC, but handling all those multi-CPU and frequency changing details for you. (It is significantly slower than RDTSC, though).
QueryPerformanceCounter 是正确的解决方案。与您和一些回答您的人所写的相反,即使使用多处理器系统(除非相关系统损坏),此调用也能给出正确答案,并且它甚至可以处理 CPU 频率的变化。在大多数现代系统上,它源自RDTSC,但会为您处理所有这些多 CPU 和频率变化的细节。(不过,它比 RDTSC 慢得多)。
On a multiprocessor computer, it should not matter which processor is called. However, you can get different results on different processors due to bugs in the basic input/output system (BIOS) or the hardware abstraction layer (HAL).
在多处理器计算机上,调用哪个处理器无关紧要。但是,由于基本输入/输出系统 (BIOS) 或硬件抽象层 (HAL) 中的错误,您可能会在不同的处理器上获得不同的结果。
回答by Alan
I don't think you're going to find a solution better than QueryPerformanceCounter. The standard technique is to set up your code to catch and discard backward time jumps and massive outliers that might result from a thread switching CPUs. If you're measuring very small intervals (if not, then you don't need that precision), then it's not a common occurrence any way. Just make it a tolerable error rather than a critical error.
我认为您不会找到比 QueryPerformanceCounter 更好的解决方案。标准技术是设置您的代码以捕获和丢弃可能由线程切换CPU导致的向后时间跳跃和大量异常值。如果您测量的间隔非常小(如果不是,那么您不需要那种精度),那么无论如何这都不是普遍现象。只是让它成为一个可以容忍的错误而不是一个严重的错误。
In the rare cases where you absolutely need to be sure that it never happens, then locking your threads down by setting the processor affinity mask is the only option.
在您绝对需要确保它永远不会发生的极少数情况下,通过设置处理器关联掩码来锁定线程是唯一的选择。
回答by Chris Kline
There's a lot of good information in the answers so far.
到目前为止,答案中有很多很好的信息。
If what you're looking for is a straightforward way to get elapsed time since January 1, 1970 at millisecond or better resolution on Windows XP or later, there's a very simple cross-platform example of this in the CurrentTime.cpp of Apple's OSS release of JavaScriptCore for MacOS 10.7.5(I can't seem to find it in their 10.8+ releases). The code I'm referring to is in the CurrentTime()
function.
如果您正在寻找一种直接的方法来获取自 1970 年 1 月 1 日以来经过的时间,在 Windows XP 或更高版本上以毫秒或更好的分辨率计算,那么在Apple OSS 版本的 CurrentTime.cpp 中有一个非常简单的跨平台示例适用于 MacOS 10.7.5 的 JavaScriptCore(我似乎无法在他们的 10.8+ 版本中找到它)。我所指的代码在CurrentTime()
函数中。
It uses the standard technique of using QueryPerformanceCounter()
to calculate elapsed time differences at higher-than-millisecond resolution, and then periodically synchronizing it to the system clock to calculate a timestamp and account for clock drift. In order to get the higher resolution timestamps it requires that you are running Windows XP or later so that calls to QueryPeformanceFrequency()
are guaranteed to succeed.
它使用标准技术QueryPerformanceCounter()
以高于毫秒的分辨率计算经过的时间差,然后定期将其与系统时钟同步以计算时间戳并考虑时钟漂移。为了获得更高分辨率的时间戳,它要求您运行 Windows XP 或更高版本,以便保证调用QueryPeformanceFrequency()
成功。
It doesn't account for context switches throwing things off slightly (as "Implement a Continuously Updating, High-Resolution Time Provider for Windows"and "The Windows Timestamp Project"do), but it does continually re-synchronize. I wouldn't launch a rocket with it, but at around 50 lines of code it's simple to implement and good enough for many purposes.
它没有考虑到上下文切换会稍微改变一些事情(如“为 Windows 实现持续更新的高分辨率时间提供程序”和“Windows 时间戳项目”所做的那样),但它确实会不断地重新同步。我不会用它发射火箭,但大约 50 行代码实现起来很简单,并且足以满足多种用途。
Also, if you know that you are guaranteed to be running Windows 8 / Windows Server 2012, you should just use GetSystemTimePreciseAsFileTime()
, since it returns the system date and time at the highest possible precision (1 microsecond or better).
此外,如果您知道您肯定会运行 Windows 8 / Windows Server 2012,您应该只使用GetSystemTimePreciseAsFileTime()
,因为它以尽可能高的精度(1 微秒或更高)返回系统日期和时间。
回答by Arno
I discovered difficulties using PerformanceCounter
together with PerformanceCounterFrequency
, because the given PerformanceCounterFrequency
deviates from the actual frequency.
我发现PerformanceCounter
与 一起使用有困难PerformanceCounterFrequency
,因为给定PerformanceCounterFrequency
的频率偏离了实际频率。
It deviates by an offset, and it also shows thermal drift. Newer hardware seems to have less drift, but the drift and the offset are quite considerable. A drift of a few ppm will already damage the microsecond accuracy to a large extend since 1 ppm is 1 μs/s! Therefore a careful hardware-specific calibration is strongly recommended when using PerformanceCounter
with PerformanceCounterFrequency
. This may also be the reason why "crazy results" are observed when not calling certain functions frequently.
它偏离了一个偏移量,并且还显示出热漂移。较新的硬件似乎漂移较小,但漂移和偏移量相当可观。由于 1 ppm 是 1 μs/s,几 ppm 的漂移已经在很大程度上损害了微秒精度!因此,使用时,强烈建议认真硬件特定的校准PerformanceCounter
用PerformanceCounterFrequency
。这也可能是为什么在不频繁调用某些函数时会观察到“疯狂结果”的原因。
I did some more detailed investigations on this matter. A description can be found in Microsecond Resolution Time Services for Windows.
我对这个问题做了一些更详细的调查。可以在适用于 Windows 的微秒分辨率时间服务中找到描述。
回答by Joe H
I've used the DateTimePrecise classfrom The Code Project.
The only problem I had with it is that it would give crazy results if I didn't call it at least every 10 seconds -- I think there was some sort of integer overflow internally -- so I have a timer which executes DateTimePrecise.Now
every few seconds.
我遇到的唯一问题是,如果我不至少每 10 秒调用一次,它会给出疯狂的结果——我认为内部存在某种整数溢出——所以我有一个DateTimePrecise.Now
每隔几秒执行一次的计时器.
You should also run NTPon the machine if you want the times to be at all accurate.
如果您希望时间完全准确,您还应该在机器上运行NTP。
Good luck...
祝你好运...