How do I get microsecond resolution timestamps on 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.)
There is Implement a Continuously Updating, High-Resolution Time Provider for Windows, but it does not seem to be solid. When microseconds matter looks great, but it's not available for download any more.
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.
I also looked at the Wikipedia article Time Stamp Counter which is interesting, but not that useful.
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...
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.
QueryPerformanceCounter will 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 HPET on 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.
The same is true for earlier systems:
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.
It is easy from C# - without P/Invoke - to check for high-resolution timer support with
Stopwatch.IsHighResolution
and then peek atStopwatch.Frequency
. It will make the necessary QueryPerformanceCounter call internally.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.
... and contrary to popular belief,
QueryPerformanceFrequency()
"cannot change while the system is running".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.Game Timing and Multicore Processors is a recommendation on how to use them properly. Please consider that it is now five years 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.
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).
Anecdotes tell that 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. :-)