date_time high resolution clock for Win32

-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi, (This is a followup to this question of mine on boost-users http://lists.boost.org/MailArchives/boost-users/msg06618.php . Jeff Garland suggested comments on that thread should be posted here. I'm new to this list, and not entirely sure if messages with this sort of platform-specific detail are welcome here; if they aren't, let me know.) I've been examining possibilities for a high resolution clock in date_time for Win32 over the past few days. In particular, Windows, like many other platforms, has a system clock with only fair precision (usually about 10ms), but excellent 'counter' clocks with very high precision. It seemed reasonable to me that it should be possible to combine the accuracy of the system clock with the precision of a high-resolution counters, to create a Boost date_time clock that had both the system's maximum accuracy and maximum precision. So, after a few days of casual research and brainstorming, I came up with this simple, incomplete prototype clock. The idea is that it queries both the system clock and the high resolution counter, saves them in static memory. Future calls only use the high resolution counter, using the saved correspondence between the two clocks to calculate the real time. This sort of timer, if it can be implemented reasonably, might be useful on many platforms, including when only time() and clock() are availible. This implementation has these characteristics: THEORY (Wishful thinking) - -Should be the best general-purpose clock and timer on Win32, that would be very difficult to exceed in useful precision or accuracy in a reimplementation. - -Should gracefully handle user changes of system clock. PRACTICE - -It does in fact have the promised ten millisecond accuracy and sub-microsecond resolution. - -The Windows system clock is a lot more "jittery" than I had noticed before. This is a huge problem. The clock routine checks every call to ensure that the two clocks are not further apart than twice the reported precision of the system clock. If they are, the saved times are re-initialized, and the clock starts over from the system time. There is a small problem in my implementation that causes the clock to return subsequent decreasing times for only very small drifts, which should not happen. I have not yet decided how to fix this, but this is not the big problem. The big problem is that while the system clock and counter stay very well in synch under 'normal conditions,' the system clock jitters a whole lot when a lot of system resources are being used in the background, causing the clock to reset itself when it really should not. This in turn causes some strange precision characteristics which might be unacceptable for some applications. I'm going to let this sit for a few days while I think about it. I'd be very interested in hearing any comments in the meantime. Aaron W. LaFramboise #include "boost/date_time/c_time.hpp" #include <windows.h> namespace boost { namespace date_time { ~ template<class time_type> ~ class win32_clock ~ { ~ public: ~ typedef typename time_type::date_type date_type; ~ typedef typename time_type::time_duration_type time_duration_type; ~ typedef typename time_duration_type::rep_type resolution_traits_type; ~ //! Return the local time based on computer clock settings ~ static time_type local_time() { ~ SYSTEMTIME st; ~ ::GetSystemTime(&st); ~ LARGE_INTEGER pc; ~ ::QueryPerformanceCounter(&pc); ~ return create_time(st, pc); ~ } ~ private: ~ static time_type create_time(const SYSTEMTIME &system_time, ~ const LARGE_INTEGER &count) ~ { ~ // Suspicious: lock mutex. ~ static long mutex; ~ while(::InterlockedExchange(&mutex, 1)) ~ Sleep(1); ~ // System time and counter at a previous call. ~ static ULONGLONG saved_time; ~ static ULONGLONG saved_count; ~ // Decode system time and get system time precision ~ ULONGLONG now_time; ~ ::SystemTimeToFileTime(&system_time, ~ reinterpret_cast<FILETIME *>(&now_time)); ~ DWORD sysincrement; ~ { ~ DWORD sysadjust; ~ BOOL sysdisabled; ~ ::GetSystemTimeAdjustment(&sysadjust, &sysincrement, &sysdisabled); ~ } ~ // Convert counter, and get frequency. ~ ULONGLONG now_count = count.QuadPart; ~ LONGLONG frequency; ~ ::QueryPerformanceFrequency( ~ reinterpret_cast<LARGE_INTEGER *>(&frequency)); ~ if(frequency <= 0) { ~ frequency = 1; ~ now_count = 0; ~ } ~ // Release mutex. ~ ::InterlockedExchange(&mutex, 0); ~ // Calculate time now (in FILETIME style measurement) according ~ // to the counter, and calculate drift from system clock. ~ double now = static_cast<double>(now_count - saved_count) ~ * 10000000 / frequency + saved_time; ~ double drift = now - now_time; ~ if(drift < 0) ~ drift = -drift; ~ // Initialize static data on first call, or counter drift. ~ // Adjust time now if counter has drifted. ~ if(saved_count == 0 ~ || now_time < saved_time ~ || now_count < saved_count ~ || drift > sysincrement * 2) { ~ if(saved_count != 0) ~ std::cerr << "DRIFT " << now - now_time << std::endl; ~ saved_time = now_time; ~ saved_count = now_count; ~ now = saved_time; ~ } ~ // Now that we've decided what time it is, break it into time units. ~ ULONGLONG now_ull = static_cast<ULONGLONG>(now); ~ SYSTEMTIME now_systemtime; ~ ::FileTimeToSystemTime(reinterpret_cast<FILETIME *>(&now_ull), ~ &now_systemtime); ~ now_systemtime.wMilliseconds = 0; ~ ::SystemTimeToFileTime(&now_systemtime, ~ reinterpret_cast<FILETIME *>(&now_ull)); ~ double frac_seconds = (now - now_ull)/10000000; ~ // Create date_now and time_duration_now. ~ date_type date_now(now_systemtime.wYear, now_systemtime.wMonth, ~ now_systemtime.wDay); ~ time_duration_type time_duration_now(now_systemtime.wHour, ~ now_systemtime.wMinute, now_systemtime.wSecond, ~ static_cast<ULONGLONG>(frac_seconds ~ * resolution_traits_type::res_adjust())); ~ return time_type(date_now, time_duration_now); ~ } ~ }; } } //namespace date_time #include <iostream> // #include "clock.hpp" #include "boost/date_time/posix_time/posix_time.hpp" using boost::posix_time::ptime; ptime now() { ~ return boost::date_time::win32_clock<ptime>::local_time(); } int main() { ~ using boost::posix_time::seconds; ~ ptime start = now(); ~ ptime last = start; ~ ptime n = last; ~ do { ~ n = now(); ~ if(n == last) ~ std::cerr << "two times equal!\n"; ~ if(n < last) ~ std::cerr << "time went backwards: " << n - last << '\n'; ~ last = n; ~ } while(n < start + seconds(15)); ~ std::cout << n - start << '\n'; ~ return 0; } -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.4 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFAnX8tlp/lhnWsM8QRAjAdAJoDKMO0++1NeO4CMqaY9K+Q/VhvKgCdGS7x aOARRMWjmfr3KrMiDsNH7qk= =M9Kf -----END PGP SIGNATURE-----

On Sat, 08 May 2004 19:45:34 -0500, Aaron W. LaFramboise wrote
(This is a followup to this question of mine on boost-users http://lists.boost.org/MailArchives/boost-users/msg06618.php . Jeff Garland suggested comments on that thread should be posted here. I'm new to this list, and not entirely sure if messages with this sort of platform-specific detail are welcome here; if they aren't, let me know.)
Well, given that it is regarding a specific extension to a boost library it is quite welcome. A higher resolution clock is already available for Posix systems in date_time, so you are addressing a platform that isn't well supported by the library now. Finally, the entire issue of timers and timing has been a hot topic lately...
I've been examining possibilities for a high resolution clock in date_time for Win32 over the past few days.
In particular, Windows, like many other platforms, has a system clock with only fair precision (usually about 10ms), but excellent 'counter' clocks with very high precision. It seemed reasonable to me that it should be possible to combine the accuracy of the system clock with the precision of a high-resolution counters, to create a Boost date_time clock that had both the system's maximum accuracy and maximum precision.
So, after a few days of casual research and brainstorming, I came up with this simple, incomplete prototype clock. The idea is that it queries both the system clock and the high resolution counter, saves them in static memory. Future calls only use the high resolution counter, using the saved correspondence between the two clocks to calculate the real time. This sort of timer, if it can be implemented reasonably, might be useful on many platforms, including when only time() and clock() are availible.
Overall, sounds like a good idea.
This implementation has these characteristics:
THEORY (Wishful thinking) - -Should be the best general-purpose clock and timer on Win32, that would be very difficult to exceed in useful precision or accuracy in a reimplementation. - -Should gracefully handle user changes of system clock.
PRACTICE - -It does in fact have the promised ten millisecond accuracy and sub-microsecond resolution. - -The Windows system clock is a lot more "jittery" than I had noticed before. This is a huge problem.
The clock routine checks every call to ensure that the two clocks are not further apart than twice the reported precision of the system clock. If they are, the saved times are re-initialized, and the clock starts over from the system time. There is a small problem in my implementation that causes the clock to return subsequent decreasing times for only very small drifts, which should not happen. I have not yet decided how to fix this, but this is not the big problem.
The big problem is that while the system clock and counter stay very well in synch under 'normal conditions,' the system clock jitters a whole lot when a lot of system resources are being used in the background, causing the clock to reset itself when it really should not. This in turn causes some strange precision characteristics which might be unacceptable for some applications.
This isn't good. What it says to me is that this is a limitation of the OS and/or hardware. Basically, windows isn't a real-time OS so when it gets busy it doesn't get around handling the clock correctly. I suppose hardware could be involved as well, but it is suspicious that things only go wrong when the os is busy.
I'm going to let this sit for a few days while I think about it. I'd be very interested in hearing any comments in the meantime.
I'll have a look at your code in more detail later... Jeff

On Sat, 08 May 2004 19:45:34 -0500, Aaron W. LaFramboise wrote
(This is a followup to this question of mine on boost-users http://lists.boost.org/MailArchives/boost-users/msg06618.php . Jeff Garland suggested comments on that thread should be posted here. I'm new to this list, and not entirely sure if messages with this sort of platform-specific detail are welcome here; if they aren't, let me know.)
Well, given that it is regarding a specific extension to a boost library it is quite welcome. A higher resolution clock is already available for Posix systems in date_time, so you are addressing a platform that isn't well supported by the library now. Finally, the entire issue of timers and timing has been a hot topic lately...
I've been examining possibilities for a high resolution clock in date_time for Win32 over the past few days.
In particular, Windows, like many other platforms, has a system clock with only fair precision (usually about 10ms), but excellent 'counter' clocks with very high precision. It seemed reasonable to me that it should be possible to combine the accuracy of the system clock with the precision of a high-resolution counters, to create a Boost date_time clock that had both the system's maximum accuracy and maximum precision.
So, after a few days of casual research and brainstorming, I came up with this simple, incomplete prototype clock. The idea is that it queries both the system clock and the high resolution counter, saves them in static memory. Future calls only use the high resolution counter, using the saved correspondence between the two clocks to calculate the real time. This sort of timer, if it can be implemented reasonably, might be useful on many platforms, including when only time() and clock() are availible.
Overall, sounds like a good idea.
This implementation has these characteristics:
THEORY (Wishful thinking) - -Should be the best general-purpose clock and timer on Win32, that would be very difficult to exceed in useful precision or accuracy in a reimplementation. - -Should gracefully handle user changes of system clock.
PRACTICE - -It does in fact have the promised ten millisecond accuracy and sub-microsecond resolution. - -The Windows system clock is a lot more "jittery" than I had noticed before. This is a huge problem.
The clock routine checks every call to ensure that the two clocks are not further apart than twice the reported precision of the system clock. If they are, the saved times are re-initialized, and the clock starts over from the system time. There is a small problem in my implementation that causes the clock to return subsequent decreasing times for only very small drifts, which should not happen. I have not yet decided how to fix this, but this is not the big problem.
The big problem is that while the system clock and counter stay very well in synch under 'normal conditions,' the system clock jitters a whole lot when a lot of system resources are being used in the background, causing the clock to reset itself when it really should not. This in turn causes some strange precision characteristics which might be unacceptable for some applications.
This isn't good. What it says to me is that this is a limitation of the OS and/or hardware. Basically, windows isn't a real-time OS so when it gets busy it doesn't get around handling the clock correctly. I suppose hardware could be involved as well, but it is suspicious that things only go wrong when
[sort-of-a-shameless-plug but on-topic]: http://msdn.microsoft.com/msdnmag/issues/04/03/HighResolutionTimer/default.a... Questions are welcome. // Johan "Jeff Garland" <jeff@crystalclearsoftware.com> wrote in message news:20040509141926.M57409@crystalclearsoftware.com... the
os is busy.
I'm going to let this sit for a few days while I think about it. I'd be very interested in hearing any comments in the meantime.
I'll have a look at your code in more detail later...
Jeff
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Johan Nilsson wrote:
[sort-of-a-shameless-plug but on-topic]:
http://msdn.microsoft.com/msdnmag/issues/04/03/HighResolutionTimer/default.a...
Questions are welcome.
Thank you for the excellent and informative article. This is definitely the sort of thing I had in mind, and you seem to have explored it a lot further than I did. However, encorporating this functionality into Boost date_time may be, in some ways, more difficult than it was in time_provider, as Boost probably can't do things like creating a background thread to keep the time synchronized, and has some additional portability constraints. I'm also concerned by your remarks--as well as other information--that suggest that the performance counter may be unsuitable as a general time source. Without having a synchronization monitor thread, it seems like it might be a lot more difficult to attempt to synchronize the time, especially with regard to intermittant "spikes" caused by certain hardware activity. Perhaps it might be necessary to develop a much more substancial clock framework such as your time_provider template for Boost in order to accomidate the demands of getting accurate time on operating systems such as Windows. While it may add size, complexity, and weight to the library, it might be worth it; what good is a timer library that can't accurately tell time? I'm going to spend the next few days analyzing your code, in particular, synchronizer.hpp. Thanks again, Aaron W. LaFramboise

"Aaron W. LaFramboise" <aaronrabiddog51@aaronwl.com> wrote in message news:40A9F51C.5070205@aaronwl.com...
Johan Nilsson wrote:
[sort-of-a-shameless-plug but on-topic]:
http://msdn.microsoft.com/msdnmag/issues/04/03/HighResolutionTimer/default. aspx
Questions are welcome.
[snip]
I'm going to spend the next few days analyzing your code, in particular, synchronizer.hpp.
Aaron, please keep me informed of your progress (if you post to this list, please send a copy to my e-mail address as well - I tend not to read this forum too often). // Johan

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Johan Nilsson Sent: Tuesday, May 18, 2004 3:18 AM To: boost@lists.boost.org Subject: [boost] Re: date_time high resolution clock for Win32
[sort-of-a-shameless-plug but on-topic]:
http://msdn.microsoft.com/msdnmag/issues/04/03/HighResolutionT imer/default.aspx
Questions are welcome.
// Johan
On Sat, 08 May 2004 19:45:34 -0500, Aaron W. LaFramboise wrote
(This is a followup to this question of mine on boost-users
http://lists.boost.org/MailArchives/boost-users/msg06618.php . Jeff
Garland suggested comments on that thread should be
new to this list, and not entirely sure if messages with
platform-specific detail are welcome here; if they aren't, let me know.)
Well, given that it is regarding a specific extension to a boost library it is quite welcome. A higher resolution clock is already available for Posix systems in date_time, so you are addressing a platform that isn't well supported by the library now. Finally, the entire issue of timers and timing has been a hot topic lately...
I've been examining possibilities for a high resolution clock in date_time for Win32 over the past few days.
In particular, Windows, like many other platforms, has a system clock with only fair precision (usually about 10ms), but excellent 'counter' clocks with very high precision. It seemed reasonable to me that it should be possible to combine the accuracy of
clock with the precision of a high-resolution counters, to create a Boost date_time clock that had both the system's maximum accuracy and maximum precision.
So, after a few days of casual research and brainstorming, I came up with this simple, incomplete prototype clock. The idea is that it queries both the system clock and the high resolution counter, saves them in static memory. Future calls only use the high resolution counter, using the saved correspondence between the two clocks to calculate the real time. This sort of timer, if it can be implemented reasonably, might be useful on many
when only time() and clock() are availible.
Overall, sounds like a good idea.
This implementation has these characteristics:
THEORY (Wishful thinking) - -Should be the best general-purpose clock and timer on Win32, that would be very difficult to exceed in useful precision or accuracy in a reimplementation. - -Should gracefully handle user changes of system clock.
PRACTICE - -It does in fact have the promised ten millisecond accuracy and sub-microsecond resolution. - -The Windows system clock is a lot more "jittery" than I had noticed before. This is a huge problem.
The clock routine checks every call to ensure that the two clocks are not further apart than twice the reported precision of the system clock. If they are, the saved times are re-initialized, and the clock starts over from the system time. There is a small
my implementation that causes the clock to return subsequent decreasing times for only very small drifts, which should not happen. I have not yet decided how to fix this, but this is not the big problem.
The big problem is that while the system clock and counter stay very well in synch under 'normal conditions,' the system clock jitters a whole lot when a lot of system resources are being used in the background, causing the clock to reset itself when it really should not. This in turn causes some strange precision characteristics which might be unacceptable for some applications.
This isn't good. What it says to me is that this is a
and/or hardware. Basically, windows isn't a real-time OS so when it gets busy it doesn't get around handling the clock correctly. I suppose hardware could be involved as well, but it is suspicious that things only go wrong when
"Jeff Garland" <jeff@crystalclearsoftware.com> wrote in message news:20040509141926.M57409@crystalclearsoftware.com... posted here. I'm this sort of the system platforms, including problem in limitation of the OS the
os is busy.
I'm going to let this sit for a few days while I think about it. I'd be very interested in hearing any comments in the meantime.
I'll have a look at your code in more detail later...
Jeff
Hardware is definitely involved, and it makes any method based on the Time Stamp Counter not nearly as accurate as you might think. It's all been hashed out here before, so rather than repeat it all, I'll just give you the reference. Look back through the Boost Archives for 1999 for a thread called "timer classes" with my name and that of Andy Glew associated with it, and you'll find some very interesting information (mainly from Andy, who was involved with the silicon design). Reid Sweatman

Reid Sweatman wrote:
Hardware is definitely involved, and it makes any method based on the Time Stamp Counter not nearly as accurate as you might think. It's all been hashed out here before, so rather than repeat it all, I'll just give you the reference. Look back through the Boost Archives for 1999 for a thread called "timer classes" with my name and that of Andy Glew associated with it, and you'll find some very interesting information (mainly from Andy, who was involved with the silicon design).
Reid Sweatman
I found the thread at http://aspn.activestate.com/ASPN/Mail/Browse/Threaded/boost/1137286 . It is very informative; thank you for the information. I also found an interesting URL by someone who has done some similar research on timing in Windows, http://www.wideman-one.com/gw/tech/dataacq/wintiming.htm. Unfortunately, most of this is largely inapplicable in Boost. It still seems to me that, despite its flaws, Intel's RDTSC combined with a time source assumed to be relatively reliable, such as the system clock, could yield a hybrid clock no worse than the primary system clock The improvement in accuracy might benefit some applications, and probably wouldn't hurt. In any case, there should be no illusions that any timer setup on Windows will meet hard real-time constraints. In fact, even if there were some other timer available that did not share these problems, it is quite likely it would not offer realistically improved performance anyway due to Windows scheduling. With whatever might be implemented for Boost, this needs to be documented. Aaron W. LaFramboise

-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Aaron W. LaFramboise Sent: Tuesday, May 18, 2004 8:12 PM To: boost@lists.boost.org Subject: Re: [boost] Re: date_time high resolution clock for Win32
Reid Sweatman wrote:
Hardware is definitely involved, and it makes any method based on the Time Stamp Counter not nearly as accurate as you might think. It's all been hashed out here before, so rather than repeat it all, I'll just give you the reference. Look back through the Boost Archives for 1999 for a thread called "timer classes" with my name and that of Andy Glew associated with it, and you'll find some very interesting information (mainly from Andy, who was involved with the silicon design).
Reid Sweatman
I found the thread at http://aspn.activestate.com/ASPN/Mail/Browse/Threaded/boost/11 37286 . It is very informative; thank you for the information.
I also found an interesting URL by someone who has done some similar research on timing in Windows, http://www.wideman-one.com/gw/tech/dataacq/wintiming.htm. Unfortunately, most of this is largely inapplicable in Boost.
It still seems to me that, despite its flaws, Intel's RDTSC combined with a time source assumed to be relatively reliable, such as the system clock, could yield a hybrid clock no worse than the primary system clock The improvement in accuracy might benefit some applications, and probably wouldn't hurt.
In any case, there should be no illusions that any timer setup on Windows will meet hard real-time constraints. In fact, even if there were some other timer available that did not share these problems, it is quite likely it would not offer realistically improved performance anyway due to Windows scheduling. With whatever might be implemented for Boost, this needs to be documented.
I agree, it can, and I've used it for most of my applications, including two games. So long as you don't have unrealistic expectations, it's quite useful. Reid Sweatman

Reid Sweatman wrote:
Hardware is definitely involved, and it makes any method based on the Time Stamp Counter not nearly as accurate as you might think. It's all been hashed out here before, so rather than repeat it all, I'll just give you
"Aaron W. LaFramboise" <aaronrabiddog51@aaronwl.com> wrote in message news:40AAC274.1060707@aaronwl.com... the
reference. Look back through the Boost Archives for 1999 for a thread called "timer classes" with my name and that of Andy Glew associated with it, and you'll find some very interesting information (mainly from Andy, who was involved with the silicon design).
Interesting stuff, thanks!
Reid Sweatman
I found the thread at http://aspn.activestate.com/ASPN/Mail/Browse/Threaded/boost/1137286 . It is very informative; thank you for the information.
I also found an interesting URL by someone who has done some similar research on timing in Windows, http://www.wideman-one.com/gw/tech/dataacq/wintiming.htm. Unfortunately, most of this is largely inapplicable in Boost.
It still seems to me that, despite its flaws, Intel's RDTSC combined with a time source assumed to be relatively reliable, such as the system clock, could yield a hybrid clock no worse than the primary system clock The improvement in accuracy might benefit some applications, and probably wouldn't hurt.
I tend to think the same way. But, the user must be aware that there _is_ a background thread in the application _and_ that it could possibly preempt other threads in current or other applications in the system - thus interfering with the 'real' work (this is applicable for my implementation only though, which raises the priority of the synchronization thread autonomously if if is preempted all the time during synchronization - which could be solved by some better end-user control of the synch policy).
In any case, there should be no illusions that any timer setup on Windows will meet hard real-time constraints. In fact, even if there were some other timer available that did not share these problems, it is quite likely it would not offer realistically improved performance anyway due to Windows scheduling. With whatever might be implemented for Boost, this needs to be documented.
I'd just like to extend on that - no application-level timer on any of the more common *nix platforms would work better than on Windows (speaking NT flavour). Talking about scheduling - NT scheduling is in fact more real-time'ish than at least the Linux/BSD ones due to the more preemptive kernel and driver architecture (yes, I know that Linux 2.6 and FreeBSD 5.x supposedly have a finer granularity on the kernel locks than their predecessors - haven't tried them out yet though). IIRC the linux kernel used to grab the TSC (or perhaps the MB timer) at each clock interrupt to be able to provide the end user with microsecond time resolution. Writing a NT device driver to provide basically the same stuff should be possible, but I doubt it's recommendable. Implementing a user-mode time provider that always works no matter what the underlying hardware platform is seems virtually impossible, even if we would limit ourselves to NT/2000/XP/(Longhorn) only (most unices I know of have a working gettimeofday so they really don't need it). Question is - would this be acceptable for a general-purpose cross-platform library such as boost? The implementation that's downloadable with the article is not the exact way I would implement the time provider - that one evolved more like an experiment so see what you can get. Still I find my results have been almost surprisingly good using the time provider under both single CPU and SMP NT/2k/XP systems - the only problems I've noticed is when the you start a VMware virtual machine on the host - which adds a delay to the time it is possible to detect the system clock change (it seems to work fine _within_ the VM though). Despite this I wouldn't hand it out in it's current incarnation without more widespread testing and, if that works out fine, not without some serious warnings to the end users: "Don't rely on the time to perform mission-critical tasks. Don't use on systems that change their clock rate dynamically (even though some of the information in the referenced thread might contradict that concern). etc etc". // Johan
participants (4)
-
Aaron W. LaFramboise
-
Jeff Garland
-
Johan Nilsson
-
Reid Sweatman