Windows clock resolution
Imagine how precise timers could be today, on our super duper gigahertz hardware. But what do we get? We get broken, laggy, high-latency, late timer callbacks at some abominable minimum period. Aren't most modern CPUs tickless[1]? They effectively work the way you describe, the scheduler will sleep as long as possible instead of just "ticking" a NOP if nothing is scheduled. The problem is that what you describe is very hard to guarantee in a non-realtime OS. Modern CPUs are pretty damn fast, that's true, but they can't task switch on a dime.
The delay between an IRQ being triggered and task being scheduled can vary pretty wildly, especially if the CPU is already under a heavy load. You can still try your luck with nanosleep and see how that treats you. It might work. It probably won't always work.
In general if you need to react so fast on some event you probably want to avoid polling at all costs. That's why most OSs are fine relaxing timer constraints for better overall performance. If you can't react on an external interrupt and you really need to be reactive busy-polling is still probably your best bet. Linux has implemented hrtimer [1] a while ago and it can easily achieve sub-ms precision. You can just try some benchmark with nanosleep on your system.
It works in a similar way to the PIT you described, although I don't think it tries to offset the delay from interrupts. What I want to say is that we already have precise timers usable on modern hardware; as for why Windows doesn't use that properly, I have no idea, but I can guess that's some technical debt in the scheduler.
If you want to be really mad, consider that modern x86 chips can fire a timer interrupt from the timestamp counter TSC. Early TSCs weren't frequency stable, but most all? JoeAltmaier on Oct 5, root parent next [—]. I remember that! Worked at Intel's biggest chip customer very early on. They asked us what we wanted in the next generation. Nobody said much, so I made a manifesto - bus data breakpoint interrupts, jump history fifo, and a timestamp counter and count-match interrupt register!
It showed up in the next spec, but as a privileged instruction sadly. And at clock speed. Used the exact same method to schedule events in an OS-less embedded system. I feel your frustration. I once spent ages trying to determine why a Python unit test that sorted timestamps constantly failed on Windows.
In the test, we compared the timestamps of performed operations, and checked to confirm that the operations happened in sequence based on their timestamp I'm sure many of you see where this is going. On Windows, the timestamp for all the actions was exactly the same, so when sorted, the actions appeared out-of-order. That one was actually super fun to track down, but super disappointing to discover it's not something that's easily remedied.
For those about to suggest how it should have been done, the application also stored an atomic revision counter, so the unit test was switched to that instead of a timestamp. CodesInChaos on Oct 6, parent next [—]. BitterAmethyst on Oct 5, prev next [—].
The lack of information and response from Microsoft on this has been quite frustrating. Yeah, I just came to the same conclusion. Win10 timer changes are breaking. Timer frequency adjustments timeBeginPeriod don't seem to affect Windows timers in the same process like they used to do!
In Win10 , if you do timeBeginPeriod 1 , timers in the same process other than using the deprecated multimedia timer seem to only trigger every ms or so instead of 1 ms. This is bad. As a sidenote about Win10 , after timeBeginPeriod 1 , Sleep 1 seems to take about 2 ms per call. Or at least it seems to take about ms to call Sleep 1 times when I tested it.
BitterAmethyst on Oct 5, root parent next [—]. Ah yes, reminds me how on my previous project I was in charge of writing a server to mix audio for multiple clients in real time. The server worked well on my local Windows 10 machine, but when deployed to a cloud instance of Windows Server it ran very very poorly, just barely quickly enough to process data in time. That's when I discovered that doing a "process more data if there is any, if not - sleep 1 " loop is a very bad way of doing it, as on Windows Server "sleep 1 " means "sleep 16ms".
It all worked fine once the timer resolution was changed to 1ms, but yeah, the default value will screw you over if you have anything this time sensitive and are using sleeps or waits on windows. I don't even get why you would Sleep in such a scenario. If you want to fire every 1ms, wouldn't you use an actual timer?
Why would you rely on Sleep for periodicity? If you don't want two of the process running at once for any reason, a check-do-sleep loop can be easier to reason than debouncing an interrupt based approach. Less efficient, but often efficient enough especially if you are just throwing something together quickly with a view to if being PoC or a temporary utility. When you're talking about Windows timer accuracy, Sleep is the simplest way to do so. Same issues and resolution affect all of the other mechanisms you mention.
Talking about those separately would just introduce unnecessary complexity to the discussion without any advantage. So no one would rely on Sleep for periodicity. Getting reliable timing performance out of Windows is So ultimately it's just simpler to talk about Sleep.
Windows developers who have to deal with it understand that same mechanism which used to be determined by the global timer frequency, which you could adjust by calling timeBeginPeriod affects all of the different timers. On versions prior to 20H2? Which ultimately changes Windows timer interrupt frequency to the specified value. So, sure, if you change Windows timer interrupt frequency, that's what you get.
It'll of course also affect Sleep while active. Back to the square one. Pretty interesting. And very alarming. This could certainly break things! SetWaitableTimer documentation lets you understand timeBeginPeriod is expected to affect the resolution.
Of course, depending on hardware How precise you can change the resolution depends on which hardware clock the particular API uses. For more information, check your hardware documentation. Might be due to my use of APCs rather than waiting on the object. Not bothered enough to try it myself but I guess you can try WaitForSingleObject on the timer to see if it behaves similarly On , I tried timeBeginPeriod 1 and calling Sleep 1 times.
Perplexingly it took a bit under 2 seconds. On same took about 1. What if you want it in your local time? There is another consideration. Before Windows 8, the clock had a resolution of around 15ms. The only gotcha here is CPU scaling though, so do your research. Unfortunately you can't use that if you create software which must also run on older operating systems. My current solution is as follows, but be aware: The determined time is not exact, it is only near to the real time.
The result should always be smaller or equal to the real time, but with a fixed error unless the computer went to standby. The result has a millisecond resolution. For my purpose it is exact enough. It is the highest resolution timer that the system has to offer that you can use in your application code to identify performance bottlenecks.
I've written up some information about how to implement this quickly and easily, in a manner suitable for most purposes, in my answer to the "Microsecond resolution timestamps on Windows" question.
Stack Overflow for Teams — Collaborate and share knowledge with a private group. Create a free Team What is Teams? Collectives on Stack Overflow. Learn more. How can I get the Windows system time with millisecond resolution? Ask Question. Asked 11 years, 4 months ago. Active 3 years, 1 month ago. Viewed 51k times. Thank you in advance. Add a comment. Active Oldest Votes. It's actually quite complicated.
Kevin Gale Kevin Gale 4, 6 6 gold badges 29 29 silver badges 31 31 bronze badges. I do not want a timer, I want the system time with millisecond precision. Did you read the article? That what it is about! This guy did exactly what you are asking and shows how it is done including code. I up voted Even when the standard setting of ActualResolution corresponds to the MinimumResolution , the ActualResolution may have a setting different from MinimumResolution see table below.
In fact it may be configured to values in the range from MinimumResolution to MaximumResolution. The ActualResolution determines the interrupt period of the system. That is the period after which the timer generates an interrupt to let the system react.
Typical values are 1 ms for wPeriodMin and 1,, ms for wPeriodMax. The 1, s period for wPeriodMax is somewhat meaningless within the context of this description. However, the possibility of setting the timer resolution to 1 ms requires a more detailed investigation. When the multimedia timer interface is used to set the multimedia timer to wPeriodMin , the ActualResolution received by a call to NtQueryTimerResolution will show a new value.
For the two platform configurations discussed, the examples are as follows:. This list shows the supported interrupt periods for platforms of type A and B in ns units. Platform A only supports four different interrupt heartbeat frequencies, while platform B has a better approximation to the desired period. The specific numbers are relevant for the procedures described here and thus need a detailed interpretation. More modern platforms do not show "unsupported" values of uPeriod.
The timer intervals are given with ns accuracy in the last digit. Since the true ActualResolution cannot be expressed correctly, rather than reporting the true ActualResolution of 0. The other values are also rounded shall be 1. The Sleep will only return when n x ActualResolution exceeds the desired duration. The required accuracy for the interval specification would have to extend to 0. The number would be ,, for the MinimumResolution and 9,, for the MaximumResolution in ps or 10 s units.
Note: Sleep 1 measurements 10,, with ahead result in a mean delay of This is 2. An interrupt timer period of 1. A time change of At the 57th of such periods, the deviation has accumulated to 1.
This way the time is updated by The system time changes according to the described mechanisms after a certain period of time. Additional time changes do happen if time corrections are caused by periodic time changes, which are continuously applied to the system time over a longer period of time to adjust to an external time reference. The occurrence and the parameters of this adjustment can be gathered by a call to GetSystemTimeAdjustment. Sudden time changes, for example, introduced by using the clock GUI or SetSystemTime … , are not announced or predictable; they happen spontaneously.
Changes of the system time will have no influence on the expiration of Sleep periods or waitable timer periods. The actual change will be taken over by the routines here. Nevertheless, system time changes are discontinuities in time, whether they are sudden or spread over a longer period of time.
What is an accurate time stamp supposed to deliver when the system inserts several hundred seconds at an interval of 1. The system will assume that the seconds are that long elongated for the time being. This can be accomplished by the temporary adaptation of the performance counter frequency to the applied granular time correction.
Time services on windows have undergone changes with any new version of Windows. The synchronous progress in hardware and software development requires the software to stay compatible with a whole variety of hardware platforms.
On the other hand new hardware enables the software to conquer better performance. Windows 8. This seems the counterpart to the linux gettimeofday function.
Since Windows 7, the operating system runs tests on the underlying hardware to see which hardware is best used for timekeeping. The evolution of TSC shows a variety of capabilities:. Chapter This is the architectural behavior moving forward. TSC reads are much more efficient and do not incur the overhead associated with a ring transition or access to a platform resource.
Deviations, as described in 2. System time changes occurred at some regular base. This is not the case on Windows 8; a whole bunch of varying file time increments is observed when polling on file time transition. A truly periodic cycle can only be approximated by a "mean increment". However, this mean increment matches the result given by ActualResolution. Despite these little hiccups, resolution, granularity, and accuracy of GetSystemTimeAsFileTime are comparable to earlier Windows versions.
Consecutive calls may return the same result. The call time is less than the smallest increment of the system time. The granularity is in the sub-microsecond regime. The function may be used for time measurements but some care has to be taken: Time differences may be ZERO. The function shall also be used with care when a system time adjustment is active.
Current Windows versions treat the performance counter frequency as a constant. The high resolution of GetSystemTimePreciseAsFileTime is derived from the performance counter value at the time of the call and the performance counter frequency.
However, the performance counter frequency should be corrected during system time adjustments to adapt to the modified progress in time. Current Windows versions don't do this. The obtained microsecond part may be severely affected when system time adjustments are active. Seconds may consist of more or less than 1. Using the processors invariant time stamp counter for timekeeping requires a calibration of timer periods. The TSC is used as a measure for the progress in time. However, the periodic update of the system time is still done by timer hardware because the TSC does not produce periodic events.
Such periodic event may be generated by the HPET. Querying the timer resolutions on such a platform as described in section 2. The values of ActualResolution are accompanied by small offsets which may vary from boot to boot but they stay constant during operation. This clearly indicates that the timer periods are calibrated during boot time. Consequently, system time updates are done a those periods with a mean progress of ActualResolution.
The calibration of the performance counter frequency during boot is described in section 2. The tiny deviations seen in the list above are a result of the calibration accuracy. This is to be done in a reasonable short time to not extend the boot time too much.
The remaining deviations are small but noticeable e. This would indeed be a very useful function if it were doing what it is supposed to do. Unfortunately, a detailed view discloses some artifacts, some of which are helpful, and others that are not. The Sleep function is backed up by the system's interrupt services. As described in section 2. This has a direct impact on Sleep. The call to Sleep passes the parameter dwMilliseconds to the system and expects the function to return after dwMilliseconds.
In practice the Sleep only returns when two conditions are met: Firstly, the requested delay must be expired and secondly an interrupt has occurred the test to see if the requested delay has expired is only done with an interrupt.
A simple Sleep 1 call may therefore have a number of different results. The results also depend on the time at which the call was made with respect to the interrupt period phase. Say the ActualResolution is set to ,, the interrupt heartbeat of the system will run at The next interrupt will not confirm that the desired period of time has expired.
Only the following interrupt will cause the call to return. The next interrupt will force the call to return. The observed delay heavily depends on the time at which the call was made.
This matters particularly when the desired delay is shorter than the ActualResolution. However, when the ActualResolution is set to MaximumResolution , the system runs at its maximum interrupt frequency and the deviations are in the order of one interrupt period.
This behavior can be used to synchronize code with the interrupt period in an easy way by simply calling two or more consecutive sleeps. Consequently the following sleep call will start at the interrupt time or at least so close to it that the system will assume that it happened at the same time. Right after the return of a sleep, the system has just processed an interrupt.
A special case is the call Sleep 0. It looks meaningless, but it is a very powerful tool since it relinquishes the reminder of the thread's time slice. That means that other threads of equal priority level will take over when ready to run. When a number of threads are running at the same priority level and all of them are very responsive, all of them will make frequent calls to Sleep 0 whenever they can afford it.
Another important mechanism for performing timed operations is provided by the waitable timer interface:. This tool can be unsed in a variety of ways. Below are just a few things that need to be mentioned within the scope of this description:. Assuming the ActualResolution is set to MaximumResolution 10, ns units ; the TimeIncrement , ns units is not a multiple of the ActualResolution.
In order to setup a truly cyclic timer, the least common multiple of , and 10, has to be found. The value of 5,, suits this need here; it hosts 57 periods at MinimumResolution or periods at ActualResolution.
The first truly cyclic timer period is therefore It will be set up by a Period value of and will expire after interrupt periods. At the time of expiration the system will have done 57 system time updates. More truly cyclic timer setups can be created at any multiple of 5,, for this type of platform.
The expired signaled timer can be handled by means of an asynchronous procedure APC call or by means of a call to WaitForSingleObject , for example. According to the last point above, the former is useless when high accuracy is required.
The latter suits the needs of the mechanisms described here much better. Waitable timers synchronize to the rhythm of the systems interrupt period ActualResolution.
This has to be kept in mind because it has severe implications to the system's overall performance. All of the tasks waiting for a Sleep or a timer to reach a signaled state will continue after the interrupt has occurred.
The system's load tends to reach peaks at interrupts. This API is backed by a virtual counter running at a "fixed" frequency started at boot time. The following two basic calls are used to explore the microsecond regime: QueryPerformanceCounter and QueryPerformanceFrequency. The counter values are derived from some hardware counter, which is platform dependent. However, the Windows version also influences the results by handling the counter in a version specific manner. Windows 7, in particular has introduced a new way of supplying performance counter values.
The count value is initialized to zero at boot time. The frequency is treated by the system as a constant. This depends on the underlying hardware see 2. The following chapter describes deviations on systems on which the underlying hardware neither provides an invariant TSC nor provides a HPET for time services. Depending on the hardware platform the counter may be an Intel at 1,, Hz or an ACPI Power Management Timer chip with an update frequency of 3,, Hz or even another source. A number of Platforms do not have these timers at all; they mimic the timer by providing the CPU clock.
As a result of the latter, the frequency can get into the GHz range. QuadPart signed will change sign after 2 63 increments. At a frequency of say 1GHz 10 9 s -1 , such a system can run for about years without reaching the sign bit. Even for multi-GHz platforms, there does not seem to be a serious limit.
However, apart from the system's treatment, the frequency cannot be considered being constant. Firstly, the frequency generating hardware will deviate from the specified value by an offset and secondly the frequency may vary i. The impact of these deviations is not negligible.
If an accuracy of 0. Obviously, that value is not provided by the system and needs to be calibrated. A first estimate of the true frequency can be gathered by querying two counter values at a certain known time apart from each other.
The code snippet uses the API call. However, due to artifacts described in 2. An accuracy of 2 ppm would be achievable when the Sleep extends to 1,, ms or 1,s.
In order to obtain 0. This is obviously a hopeless approach. It also averages temporary changes of the frequency and it will not forgive frequency changes due to thermal drifts. The thermal drift of the performance counter frequency can be severe:. This graph shows an older system with heavy thermal drift. The system reports the performance counter frequency as 3,, Hz.
In fact, it is already at 3,, Hz when it is "cold". After many hours of doing nothing, the system seems to reach a thermal equilibration.
The load has increased the main board temperature by 5 deg. It rose to an offset of almost Hz or a true performance counter frequency of 3,, Hz. The calibration procedure used for the time stamp mechanism described here uses a repeated averaging period evaluation and reaches an accuracy of better than 0.
Thermal drifts can be captured reasonably well and can be applied without much delay. A value of 3,, The use of QueryPerformanceCounter on multi-processor platforms implies that the call is made on the same processor all the time. This rule only applies to systems using non invariant TSC hardware. The advent of multi processor platforms or muti-core processors highly recommends not using RDTSC calls. Newer processors also support adaptive CPU frequency adjustments.
However, the introduction of invariant Time Stamp Counters has changed the situation. Some of the resources discussed show a platform-specific behavior.
The precision time functions developed within the windows timestamp project mainly rely on four function suites provided by the operating system:. The complexity of the system time update with respect to the interrupt settings was explained and is understood. A complex automatic diagnosis of the system has to establish proper settings in order to obtain the desired accuracy. Not less than years from the most recent system boot, and potentially longer based on the underlying hardware timer used.
For most applications, rollover isn't a concern. What is the computational cost of calling QPC? The computational calling cost of QPC is determined primarily by the underlying hardware platform. If the TSC can't be used, the system will select a different hardware time basis. This cost is dominated by the time required to access the hardware device on the motherboard.
Does QPC require a kernel transition system call? Is the performance counter monotonic non-decreasing? Can the performance counter be used to order events in time? How accurate is the performance counter? The answer depends on a variety of factors. For more info, see Low-level hardware clock characteristics. I need to convert the QPC output to milliseconds.
How can I avoid loss of precision with converting to double or float? There are several things to keep in mind when performing calculations on integer performance counters:.
As a general principle, delay these computations and conversions as long as possible to avoid compounding the errors introduced. A file time is a bit value that represents the number of nanosecond intervals that have elapsed since A.
Conversion between the two requires calculating the ratio of the QPC interval and nanoseconds intervals. Be careful to avoid losing precision because the values might be small 0. Why is the time stamp that is returned from QPC a signed integer? Calculations that involve QPC time stamps might involve subtraction. By using a signed value, you can handle calculations that might yield negative values.
How can I obtain high resolution time stamps from managed code? Call the Stopwatch. GetTimeStamp method from the System. For an example about how to use Stopwatch. GetTimeStamp , see Acquiring high resolution time stamps from managed code. Do I need to set the thread affinity to a single core to use QPC? For more info, see Guidance for acquiring time stamps.
This scenario is neither necessary nor desirable. Performing this scenario might adversely affect your application's performance by restricting processing to one core or by creating a bottleneck on a single core if multiple threads set their affinity to the same core when calling QueryPerformanceCounter.
Absolute clocks provide accurate time-of-day readings. They are typically based on Coordinated Universal Time UTC and consequently their accuracy depends in part on how well they are synchronized to an external time reference.
Difference clocks measure time intervals and aren't typically based on an external time epoch. QPC is a difference clock and isn't synchronized to an external time epoch or reference. When you use QPC for time-interval measurements, you typically get better accuracy than you would get by using time stamps that are derived from an absolute clock.
This is because the process of synchronizing the time of an absolute clock can introduce phase and frequency shifts that increase the uncertainty of short term time-interval measurements. QPC uses a hardware counter as its basis. Hardware timers consist of three parts: a tick generator, a counter that counts the ticks, and a means of retrieving the counter value. The characteristics of these three components determine the resolution, precision, accuracy, and stability of QPC.
If a hardware generator provides ticks at a constant rate, time intervals can be measured by simply counting these ticks. The rate at which the ticks are generated is called the frequency and expressed in Hertz Hz.
The reciprocal of the frequency is called the period or tick interval and is expressed in an appropriate International System of Units SI time unit for example, second, millisecond, microsecond, or nanosecond. The resolution of the timer is equal to the period. Resolution determines the ability to distinguish between any two time stamps and places a lower bound on the smallest time intervals that can be measured.
This is sometimes called the tick resolution. This uncertainty is called a quantization error.
0コメント