Low-level precision timer proposal

Hello, Currently there's boost::timer which is a timer based on std::clock(). While this might be sufficient for many people, some want low-level resolution timers. I made a QueryPerformanceCounter() / gettimeofday() wrapper that allows portable millisecond resolution. You'll find attached a basic sample of my trivial work. I tried to make it so inclusion in boost is straight-forward. To see it in action : -Copy the precise_timer* hpp files into the boost directory. -Compile main.cpp & execute it. Would boost be interested by including this class in boost::timer ? I'm all ear for your suggestions / bugs / whatever fits it :) This is the 1st time I propose something to boost so there's probably things to be said on the implementation details (files structure, #ifdef strategy etc) so don't hesitate to tell what should be changed. I also can make that if on windows QueryPerformanceCounter() fails because there's no low-level resolution timer available it uses timeGetTime() instead. But that'd require linking to winmm.lib which could be a problem ( and I never saw a win32 machine where QueryPerformanceCounter() didn't work ). I just thought that I could also rename it to lowres_timer instead of precise_timer, it's more accurate, what do you think ? Regards, Philippe Vaucher

Silex wrote:
Hello,
Currently there's boost::timer which is a timer based on std::clock(). While this might be sufficient for many people, some want low-level resolution timers.
I made a QueryPerformanceCounter() / gettimeofday() wrapper that allows portable millisecond resolution.
You'll find attached a basic sample of my trivial work. I tried to make it so inclusion in boost is straight-forward.
To see it in action :
-Copy the precise_timer* hpp files into the boost directory. -Compile main.cpp & execute it.
Would boost be interested by including this class in boost::timer ? I'm all ear for your suggestions / bugs / whatever fits it :) This is the 1st time I propose something to boost so there's probably things to be said on the implementation details (files structure, #ifdef strategy etc) so don't hesitate to tell what should be changed.
Definitely interested, in fact it's one of those things that keeps getting proposed but no ones seen to completion yet. John.

On Sun, May 14, 2006 at 05:09:28PM +0200, Silex wrote:
Would boost be interested by including this class in boost::timer ?
Even more so when it had microsecond precision.
I'm all ear for your suggestions / bugs / whatever fits it :)
It would be better when the object itself can be handled as variable (independent of it's internal structure). For that to work best, there shouldn't be any 'double's in the internal structure. Two int's, one for seconds and one for microseconds, would be best, imho. There could be an accessor to get a rounded double in seconds, ie 'rseconds()' (I'd reserve 'seconds()' for returning the integer number of seconds. Now, there is a problem imho with it's type: An absolute time is different from a relative time. The fact that an absolute time is relative to 1 Jan 1970 0:00:00 would make one confused- thinking that the two are the same thing, but I'd argue that it would be better to make TWO types. You could use boost::Time for a real time (in UTC), and boost::TimeDiff to represent time intervals. For example, boost::Time start; // Uninitialized object. assert(!start); // Not initialized. start.set(); // Set to current time. assert(start); // Initialized. // Do work... boost::TimeDiff elapsed = boost::Time() - start; // Time is automatically initialized when used. There would be a Time::set(time_t seconds), Time::set(time_t seconds, suseconds_t microseconds), and Time::set(double seconds); And of course, we'd have: Time + Time // error Time - Time = TimeDiff Time +/- TimeDiff = Time TimeDiff + Time = Time TimeDiff - Time // error TimeDiff +/- TimeDiff = TimeDiff Both classes, or just TimeDiff(?), could have accessors for seconds and microseconds. It should be possible to compare TimeDiff with an integer (seconds), assuming 0 for the microseconds part, ie: TimeDiff elapsed = stop - start; if (elapsed > 2) std::cout << "More than 2 seconds have passed.\n"; I'm inclined to think that operator== should NOT be defined for TimeDiff == int, and certainly not for TimeDiff == double (I'm afraid that TimeDiff == TimeDiff has to exist). But operator> and operator< should. For example, if (elapsed >= 0.1) // 100 ms or more elapsed? ...
I just thought that I could also rename it to lowres_timer instead of precise_timer, it's more accurate, what do you think ?
Low resolution would mean it is less precise. As you might have seen, I'd propose to use Time and TimeDiff. The reason that I think that a 'Time' and 'TimeDiff' approach is more useful than a 'HiResTimer', is that you can implement the latter with the first, but not the other way around. Boost should provide a portable interface for the lowest level. Carlo Wood

Carlo Wood wrote:
On Sun, May 14, 2006 at 05:09:28PM +0200, Silex wrote:
Would boost be interested by including this class in boost::timer ?
Even more so when it had microsecond precision.
I'm all ear for your suggestions / bugs / whatever fits it :)
It would be better when the object itself can be handled as variable (independent of it's internal structure).
For that to work best, there shouldn't be any 'double's in the internal structure. Two int's, one for seconds and one for microseconds, would be best, imho. There could be an accessor to get a rounded double in seconds, ie 'rseconds()' (I'd reserve 'seconds()' for returning the integer number of seconds.
I agree with this and it's been discussed before. Note I haven't looked at the new proposals, and can't till later, but I would like everyone interested in this topic to please look at: http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?GDTL/Timer This is a proposal for the current timer to be replaced with a core template that can use date_time types (including the microsecond clock type) and time durations. Please edit and update this page with additional thoughts. Thx, Jeff

I found out that there's already <boost/date_time/microsec_time_clock.hpp>, but on windows it uses GetSystemTimeAsFileTime(). This raises a potential issue: I don't know if GetSystemTimeAsFileTime() works at millisecond resolution like QueryPerformanceCounter() does, and I don't know if QueryPerformanceCounter() returns some kind of epoch.. the docs are rather lowly-documented on this. I also noticed that getimeofday() wasn't checked for failure in the current boost headers. I also fell on a page which stated that "On Windows, clock() returns the nearest approximation to wall-clock time since the first call to this function, based on the Win32 function QueryPerformanceCounter(). The resolution is typically better than one microsecond.". While I doubt it it might be interesting for our problem if it happen to be true. After the suggestions & having read the wiki I think we should indeed modifiy parts of date_time and template the timer class like mentionned. Should I try to give it a go ? Philippe On 5/15/06, Jeff Garland <jeff@crystalclearsoftware.com> wrote:
Carlo Wood wrote:
On Sun, May 14, 2006 at 05:09:28PM +0200, Silex wrote:
Would boost be interested by including this class in boost::timer ?
Even more so when it had microsecond precision.
I'm all ear for your suggestions / bugs / whatever fits it :)
It would be better when the object itself can be handled as variable (independent of it's internal structure).
For that to work best, there shouldn't be any 'double's in the internal structure. Two int's, one for seconds and one for microseconds, would be best, imho. There could be an accessor to get a rounded double in seconds, ie 'rseconds()' (I'd reserve 'seconds()' for returning the integer number of seconds.
I agree with this and it's been discussed before. Note I haven't looked at the new proposals, and can't till later, but I would like everyone interested in this topic to please look at:
http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?GDTL/Timer
This is a proposal for the current timer to be replaced with a core template that can use date_time types (including the microsecond clock type) and time durations. Please edit and update this page with additional thoughts.
Thx,
Jeff _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Silex wrote:
I found out that there's already <boost/date_time/microsec_time_clock.hpp>, but on windows it uses GetSystemTimeAsFileTime().
This raises a potential issue: I don't know if GetSystemTimeAsFileTime() works at millisecond resolution like QueryPerformanceCounter() does, and I don't know if QueryPerformanceCounter() returns some kind of epoch.. the docs are rather lowly-documented on this.
I also noticed that getimeofday() wasn't checked for failure in the current boost headers.
I also fell on a page which stated that "On Windows, clock() returns the nearest approximation to wall-clock time since the first call to this function, based on the Win32 function QueryPerformanceCounter(). The resolution is typically better than one microsecond.". While I doubt it it might be interesting for our problem if it happen to be true.
Clocks are highly variable depending on the hardware, OS, etc. QPC clocks have been discussed before, but honestly I think you'll get 90% of the what you can get with the current date-time clock.
After the suggestions & having read the wiki I think we should indeed modifiy parts of date_time and template the timer class like mentionned. Should I try to give it a go ?
Sure -- I've uploaded some prototype code to that vault under date_time/new_timer.zip that I worked on at some point in the past. It should get you going. Please evolve it and send me issues. Jeff

Silex wrote:
I found out that there's already <boost/date_time/microsec_time_clock.hpp>, but on windows it uses GetSystemTimeAsFileTime().
This raises a potential issue: I don't know if GetSystemTimeAsFileTime() works at millisecond resolution like QueryPerformanceCounter() does, and I don't know if QueryPerformanceCounter() returns some kind of epoch.. the docs are rather lowly-documented on this.
Ah, I suspect there may be problems with the CPU clock changing speed with some of these timers, I'm not sure though...
I also noticed that getimeofday() wasn't checked for failure in the current boost headers.
I also fell on a page which stated that "On Windows, clock() returns the nearest approximation to wall-clock time since the first call to this function, based on the Win32 function QueryPerformanceCounter(). The resolution is typically better than one microsecond.". While I doubt it it might be interesting for our problem if it happen to be true.
After the suggestions & having read the wiki I think we should indeed modifiy parts of date_time and template the timer class like mentionned. Should I try to give it a go ?
I guess it depends what the class is supposed to do: whether it measures real-world time, or some performance metric that isn't really time related. John.

John Maddock wrote:
Silex wrote:
I found out that there's already <boost/date_time/microsec_time_clock.hpp>, but on windows it uses GetSystemTimeAsFileTime().
This raises a potential issue: I don't know if GetSystemTimeAsFileTime() works at millisecond resolution like QueryPerformanceCounter() does, and I don't know if QueryPerformanceCounter() returns some kind of epoch.. the docs are rather lowly-documented on this.
Ah, I suspect there may be problems with the CPU clock changing speed with some of these timers, I'm not sure though...
The problem with GetSystemTimeAsFileTime is that it can jump an hour forward/backward as DST kicks in/out. The problem with QueryPerformanceCounter is that QueryPerformanceFrequency is not (AFAIK) required to return the same value every time. It may be CPU clock based, and a low power CPU can vary its frequency depending on load. We don't have a good TIME_MONOTONIC solution, and we really do need one for the threading library. FWIW, I have found timeGetTime pretty reliable on Windows as a monotonic time provider. It only has 1ms resolution, though.

The problem with QueryPerformanceCounter is that QueryPerformanceFrequency is not (AFAIK) required to return the same value every time. It may be CPU clock based, and a low power CPU can vary its frequency depending on load.
No, "the frequency cannot change while the system is running." (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui...)
FWIW, I have found timeGetTime pretty reliable on Windows as a monotonic time provider. It only has 1ms resolution, though.
timeGetTime() is good but QueryPerformanceCounter() has lower overhead. Their resolution is similar tho. Philippe

Silex wrote:
The problem with QueryPerformanceCounter is that QueryPerformanceFrequency is not (AFAIK) required to return the same value every time. It may be CPU clock based, and a low power CPU can vary its frequency depending on load.
No, "the frequency cannot change while the system is running." (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui...)
You are right, a variable frequency is explicitly disallowed in the documentation now. Most chipset bugs that affected QPC also don't seem to be an issue nowadays.

On 5/15/06, Peter Dimov <pdimov@mmltd.net> wrote:
Silex wrote:
The problem with QueryPerformanceCounter is that QueryPerformanceFrequency is not (AFAIK) required to return the same value every time. It may be CPU clock based, and a low power CPU can vary its frequency depending on load.
No, "the frequency cannot change while the system is running." (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui...)
You are right, a variable frequency is explicitly disallowed in the documentation now. Most chipset bugs that affected QPC also don't seem to be an issue nowadays.
Does anyone know if the issue mentioned in this KB article is still relevant? http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323& --Michael Fawcett

Does anyone know if the issue mentioned in this KB article is still relevant?
http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323&
If I read correctly, it's an hardware problem, and those are the fabricants involved: PCI ID Hardware Vendor 1039:0530 Silicon Integrated Systems (SiS) 1039:0620 Silicon Integrated Systems (SiS) 10B9:0533 Acer Labs, Inc. (ALi) 10B9:1533 Acer Labs, Inc. (ALi) 1106:0596 VIA Technologies, Inc. (VIA) 1106:0686 VIA Technologies, Inc. (VIA) 1166:004F Serverworks Corporation 1166:0050 Serverworks Corporation 8086:7110 Intel Corporation Philippe

On 5/15/06, Silex <silex0r@gmail.com> wrote:
Does anyone know if the issue mentioned in this KB article is still relevant?
http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323&
If I read correctly, it's an hardware problem, and those are the fabricants involved:
PCI ID Hardware Vendor 1039:0530 Silicon Integrated Systems (SiS) 1039:0620 Silicon Integrated Systems (SiS) 10B9:0533 Acer Labs, Inc. (ALi) 10B9:1533 Acer Labs, Inc. (ALi) 1106:0596 VIA Technologies, Inc. (VIA) 1106:0686 VIA Technologies, Inc. (VIA) 1166:004F Serverworks Corporation 1166:0050 Serverworks Corporation 8086:7110 Intel Corporation
Ah, I see that now. It also looks like those IDs are stored in the registry, so one could theoretically check to see if QPC/QPF performed correctly for the system, and then fall back on a lower precision but correct implementation. --Michael Fawcett

On 5/15/06, Silex <silex0r@gmail.com> wrote:
The problem with QueryPerformanceCounter is that QueryPerformanceFrequency is not (AFAIK) required to return the same value every time. It may be CPU clock based, and a low power CPU can vary its frequency depending on load.
No, "the frequency cannot change while the system is running."
Correct, but that's the problem IIUC. The CPU's clock speed got cut by 50% during the thermal throttling, and then increased after the CPU cooled down, however QPF kept happily returning the same value the entire time. Google on SpeedStep and QPF. There is also a problem with using QPC/QPF on SMP systems, but I am not knowledgeable about the specifics. --Michael Fawcett

Michael Fawcett wrote:
There is also a problem with using QPC/QPF on SMP systems, but I am not knowledgeable about the specifics.
Actually I now recall hearing about QPC returning different results on the two cores of an Athlon x2, but I haven't verified it personally. A friend of mine claimed that he did, though.

Correct, but that's the problem IIUC. The CPU's clock speed got cut by 50% during the thermal throttling, and then increased after the CPU cooled down, however QPF kept happily returning the same value the entire time. Google on SpeedStep and QPF.
Right, ok so we have different problems here : QueryPerformanceCounter: - pros: no need to link to additional libs, lower overhead - cons: might bug with CPU's clock speed changes timeGetTime: -pros: should always have the same accuracy -cons: requires linking to winmm.lib I think I'll try to do two windows implementation for the template parameter of the timer class, one with QueryPerformanceCounter and one with timeGetTime which would try to #pragram comment(lib,etc) it. The question that comes is that the design proposed until now poses a logical problem when it comes to the implementation: If the template param is a clock class, then using QueryPerformanceCounter/timeGetTime etc is a problem as it's not really related to the current time. I'll think more about it and propose something. Philippe

I did some tests with the current boost::posix_time::microsec_clock and it *looks* like GetSystemTimeAsFileTime() has low level resolution, BUT I read somewhere that it's overhead is huge compared to QueryPerformanceCounter. I'll try to see if there's a way to get the epoch from QueryPerformanceCounter or timeGetTime, so I could make a usable microsec_clock based on it. Philippe

Silex wrote:
I'll try to see if there's a way to get the epoch from QueryPerformanceCounter or timeGetTime, so I could make a usable microsec_clock based on it.
QPC and timeGetTime are usable monotonic clocks (time providers). A monotonic clock has the nice property that when you call it twice the difference of the two values is (a) never negative (b) an approximation of the elapsed time between the two calls. You don't need an epoch for that, and in fact having an epoch destroys this property because of leap seconds, daylight saving and changing time zones.

Silex wrote:
I did some tests with the current boost::posix_time::microsec_clock and it *looks* like GetSystemTimeAsFileTime() has low level resolution,
The resolution is good, but the time isn't updated any more often than the system clock (usually some 10-15 milliseconds).
BUT I read somewhere that it's overhead is huge compared to QueryPerformanceCounter.
I'd say it's usually the opposite way around, unless somethings changed due to some later WinXP service pack or hot fix. QPC can be a real performance killer on single CPU systems. It's been a while since I tested thought, so I can't speak for certain for how the performance counter is implemented on HT and/or dual-core platforms.
I'll try to see if there's a way to get the epoch from QueryPerformanceCounter or timeGetTime, so I could make a usable microsec_clock based on it.
Are you really talking about getting an absolute time with milli-/microsecond resolution? Be prepare to put down some work - there's no supported way of getting a correlation between the monotonic counters and calendar time. // Johan

"Silex" wrote
I think I'll try to do two windows implementation for the template parameter of the timer class, one with QueryPerformanceCounter and one with timeGetTime which would try to #pragram comment(lib,etc) it.
I'll think more about it and propose something.
It may be interesting to take a look how Cygwin emulates gettimeofday() functionality. /Pavel

Pavel Vozenilek wrote:
"Silex" wrote
I think I'll try to do two windows implementation for the template parameter of the timer class, one with QueryPerformanceCounter and one with timeGetTime which would try to #pragram comment(lib,etc) it.
I'll think more about it and propose something.
It may be interesting to take a look how Cygwin emulates gettimeofday() functionality.
IIRC, the last time I checked the time returned isn't updated any more often than the underlying (Windows) system time. It's been a while since that, though. // Johan

Peter Dimov wrote:
John Maddock wrote:
Silex wrote:
I found out that there's already <boost/date_time/microsec_time_clock.hpp>, but on windows it uses GetSystemTimeAsFileTime().
This raises a potential issue: I don't know if GetSystemTimeAsFileTime() works at millisecond resolution like QueryPerformanceCounter() does, and I don't know if QueryPerformanceCounter() returns some kind of epoch.. the docs are rather lowly-documented on this.
Ah, I suspect there may be problems with the CPU clock changing speed with some of these timers, I'm not sure though...
The problem with GetSystemTimeAsFileTime is that it can jump an hour forward/backward as DST kicks in/out.
The problem with QueryPerformanceCounter is that QueryPerformanceFrequency is not (AFAIK) required to return the same value every time. It may be CPU clock based, and a low power CPU can vary its frequency depending on load.
I guess that's true. However I seem to recall that the Linux 2.4 kernel based gettimeofday on rdtsc, so I wonder how reliable gettimeofday really is on portable computers. Perhaps some other implementation is selected for certain platforms. The QPF docs state that the frequency never change while the system is running, which is rather ambiguous. The word "frequency" could simply refer the value returned by QPF and not the actual hardware counter; "while the system is running" might, or might not include going back and forth to/from sleep mode/hibernation. For uniprocessor systems QPC is most often not rdtsc-based, so those should pose lesser problems. My guess is that a monotonic timer solution based on QPC/QPF should be good enough for at least 90% of all applications. It's not the ultimate, but a library could provide a class parameterized on the actual implementation (boost could provide the QPC / gettimeofday implementations out-of-the-box as the default values under the different platforms). This, in combination with providing a disclaimer that explains the limitations under Windows, should be sufficient. People needing better than this could roll their own implementation. As for implementing a high-res calendar time provider under Windows - I frankly think that it's next to impossible to implement a general-purpose implementation that works for the all the different possible hardware configurations. Perhaps a custom driver would make it possible. For specific hardware configurations I _do_ think it's possible - but I still wouldn't leave any guarantees until after doing some system-specific testing and verification. Perhaps not even then - it is hard to test whether the results are actually correct or not.
We don't have a good TIME_MONOTONIC solution, and we really do need one for the threading library.
I guess the TIME_MONOTONIC stuff would mostly be used for sleep(). As there is no way to explicitly make a thread sleep less than the clock tick under Windows[*] - why do we need a high-res monotonic counter solution for the thread library? Or did I misunderstand you (probably)?
FWIW, I have found timeGetTime pretty reliable on Windows as a monotonic time provider. It only has 1ms resolution, though.
That might very well be a good solution. OTOH, I've never had any problems with using QPC myself. Just my 0.02EUR. // Johan [*] Ok, not strictly true: - Sleep(0) causes a yield which _could_ return within a clock tick if no other threads are in the ready state. But that's not strictly a sleep. - A thread waiting for I/O will be activated whenever the I/O is completed (normal restrictions apply with regards to priorities etc).

Ok, here's the new templated timer class from the suggestions. It's basically the code from Jeff with extensions and some slight corrections. Jeff, can you validate/correct the header text about copyrights ? I'm really not used to this so I did how I thought it should be done. I added two templates for the time type and time_duration type to make it more generic : template<class clock_type, class time_type = boost::posix_time::ptime, class time_duration_type = boost::posix_time::time_duration> class timer {}; I also added two typedefs for convenience: typedef boost::timer<boost::posix_time::second_clock> second_timer; typedef boost::timer<boost::posix_time::microsec_clock> microsec_timer; To see it in action do as usual, copy timer_new.hpp to the boost folder and compile main.cpp. This code seems to works fine on both windows & unixes and seems to do microsecond resolution as provided by boost::posix_time::microsec_clock. Now the question is, how should I do another microsec_clock class based on QPC or timeGetTime ? It's obvious that if I do one, it should not be used by the user as localtime() would not have a real meaning. As the initial goal is somewhat attained, do we want to make a QPC implementation at all ? At the moment the pros here are that we only change timer.hpp and the cons is a possible overhead on windows. Waiting of hearing from you :) Philippe

Johan Nilsson wrote:
My guess is that a monotonic timer solution based on QPC/QPF should be good enough for at least 90% of all applications.
People (game programmers) have been repeatedly running into problems with QPC in practice. It may be good enough for 90% of the _cases_, but if your _application_ depends on QPC for accurate timing, it can break and you may get a baffling bug report.
We don't have a good TIME_MONOTONIC solution, and we really do need one for the threading library.
I guess the TIME_MONOTONIC stuff would mostly be used for sleep(). As there is no way to explicitly make a thread sleep less than the clock tick under Windows[*] - why do we need a high-res monotonic counter solution for the thread library? Or did I misunderstand you (probably)?
We need a monotonic time for condition::wait. It may not be high resolution (depending on your definition of high), it just needs to work reliably, which the current xtime implementation does not. I'm not sure which clock do you mean when you say that a thread can't sleep for less than a clock tick. If you mean the CPU clock, then yes, a no-op Sleep function that returns immediately would probably consume more than one clock tick, so it is impossible to make a thread sleep for less.

Peter Dimov wrote:
Johan Nilsson wrote:
My guess is that a monotonic timer solution based on QPC/QPF should be good enough for at least 90% of all applications.
People (game programmers) have been repeatedly running into problems with QPC in practice. It may be good enough for 90% of the _cases_, but if your _application_ depends on QPC for accurate timing, it can break and you may get a baffling bug report.
Of course. If someone needs accurate timing under Windows that should work everywhere, QPC is probably not the way to go. So don't use e.g. boost::timer<performance_counter> in this case - roll your own. A performance counter based implementation should still be usable for a large audience. If milliseconds is enough - perhaps the mmlib functionality is good enough (I have too little experience with that). Just out of curiousity - do you know if the performance counter was tsc-based, PIT-based, or whatever in the mentioned problem cases above?
We don't have a good TIME_MONOTONIC solution, and we really do need one for the threading library.
I guess the TIME_MONOTONIC stuff would mostly be used for sleep(). As there is no way to explicitly make a thread sleep less than the clock tick under Windows[*] - why do we need a high-res monotonic counter solution for the thread library? Or did I misunderstand you (probably)?
We need a monotonic time for condition::wait. It may not be high resolution (depending on your definition of high), it just needs to work reliably, which the current xtime implementation does not.
Sorry for being vague. I didn't see much of a point being able to specify a condition wait time with a microsecond resolution, when systems generally aren't capable to wake up the waiting thread in a shorter time than decided by the tick rate of the system. OTOH, if you can't specify a microsecond wait time you'll never be able to use this on platforms that provide this functionality (haven't seen one myself though).
I'm not sure which clock do you mean when you say that a thread can't sleep for less than a clock tick. If you mean the CPU clock, then yes, a no-op Sleep function that returns immediately would probably consume more than one clock tick, so it is impossible to make a thread sleep for less.
I referred to the timer tick period (~10-15 ms for the NT family). // Johan

Of course. If someone needs accurate timing under Windows that should work everywhere, QPC is probably not the way to go. So don't use e.g. boost::timer<performance_counter> in this case - roll your own.
Ok, for now I'll take for granted that the last implementation I just proposed will be sufficient and that it'll use boost::posix_time::microsec_clock for now. I'd like someone to confirm this and possibly review the code so I can change whatever is necessary. Philippe

Johan Nilsson wrote:
I'm not sure which clock do you mean when you say that a thread can't sleep for less than a clock tick. If you mean the CPU clock, then yes, a no-op Sleep function that returns immediately would probably consume more than one clock tick, so it is impossible to make a thread sleep for less.
I referred to the timer tick period (~10-15 ms for the NT family).
It used to be the case that you can't get better than 10ms precision on NT without calling timeBeginPeriod, but that was years ago, I think (NT 3.5, not sure about 4). I'm getting ms-precise timing (not hard realtime, obviously, but correct most of the time) on Windows XP.

Peter Dimov wrote:
Johan Nilsson wrote:
I'm not sure which clock do you mean when you say that a thread can't sleep for less than a clock tick. If you mean the CPU clock, then yes, a no-op Sleep function that returns immediately would probably consume more than one clock tick, so it is impossible to make a thread sleep for less.
I referred to the timer tick period (~10-15 ms for the NT family).
It used to be the case that you can't get better than 10ms precision on NT without calling timeBeginPeriod, but that was years ago, I think (NT 3.5, not sure about 4). I'm getting ms-precise timing (not hard realtime, obviously, but correct most of the time) on Windows XP.
I'm not so sure. Try out the following (VC compiler) _straight_ after a clean boot: --- #include <windows.h> #include <iostream> #pragma comment(lib, "winmm") int main(int argc, char* argv[]) { for (int i = 0; i != 1000; ++i) { std::cout << "MMTime: " << timeGetTime() << '\n'; Sleep(1); } return 0; } --- The minimum interval between the output will be the default timer tick period (10-15ms). Calling timeBeginPeriod(1) before entering the loop will "fix" this. This will not affect the updating of the system time, though. Note that the timer resolution is set "globally" - if one process requests a time period of 1 milliseconds it will also affect other processes' wake-up times. // Johan

Peter Dimov wrote:
We need a monotonic time for condition::wait. It may not be high resolution (depending on your definition of high), it just needs to work reliably, which the current xtime implementation does not.
Perhaps I am misunderstandig you, but how would a separate implementation of "monotonic time" help with condition::wait ? The key issue of (I assume you mean) timed_wait is, that the scheduler wakes up the thread in question. So no provision of any means capable of measuring time differences would be of help here. Any implementation will need to rely on the underlying threading API's notion of timed_wait, be it pthread_cond_timedwait or WaitForMultipleObject's timeout parameter. What do you think are xtime's pitfalls in this respect? Roland

Roland Schwarz wrote:
What do you think are xtime's pitfalls in this [condition::timed_wait] respect?
The problem is that xtime uses UTC time. The current system UTC time can jump forward or backward as the system clock is adjusted manually or automatically via NTP. So if the clock jumps backward two minutes at exactly the wrong moment, a timed_wait that was supposed to wait one second will now wait two minutes and one second. On the other hand, if one is writing an event scheduler of some sort, it would be natural to use UTC time even when monotonic time is available and the above behavior might actually be desirable.

Hello, As I didn't receive the answers I was looking for, here is my last proposal. My imlpementation does the templating of the timer class as suggested. By using boost::posix_time::microsec_clock as the template parameter, we are able to do microsec timing. This works fine, at least in the environnements I tested it (windows 2000 and gentoo). I added two typedefs: typedef boost::timer<boost::posix_time::second_clock> second_timer; typedef boost::timer<boost::posix_time::microsec_clock> microsec_timer; Now one can simply use boost::microsec_timer and time his code at microsecond level. Because of the long discussion about QueryPerformanceCounter that didn't came to a real conclusion, I decided to implement two additionnal timers: - boost::qpc_timer, which use QueryPerformanceCounter() for its resolution. - boost::tgt_timer, which use timeGetTime() for its resolution. As using those timers would make no sense on another platform than windows, those are not defined by default. One must #define BOOST_QPC_TIMER to get boost::qpc_timer and must #define BOOST_TGT_TIMER to get boost::tgt_timer. Trying to do those defines on another platform than windows results in an #error. Please tell me what do you think of the code (review ?) and tell me if this is ok for boost. To test it simply put timer_new.hpp into the boost folder and compile main.cpp, uncommenting the macros at top to test the second/qpc/tgt timers if wanted. The goal is that timer_new.hpp is then renamed to timer.hpp and replaces the current header. Thank you Philippe

"Silex" <silex0r@gmail.com> wrote in message news:bfc703c0605210356v38a23f9haccc359223fb7a20@mail.gmail.com...
The goal is that timer_new.hpp is then renamed to timer.hpp and replaces the current header.
That's fine with me, assuming documentation is updated as needed. The other timing related issue that I've procrastinated about for years is boost/progress.hpp. Class progress_timer suffers from two problems: 1) Inconsistent results depending on operating system. 2) Doesn't always give enough information for its intended use - timing program execution. Problem (1) will be fixed by your changes to timer, IIUC. As we speak I'm working on a solution to (2). The intent is to leave progress_timer as is, since it does meet some needs, and since there is some small amount of existing code that depends on its output format, and add a new header, perhaps called process_times.hpp. It will contain functions and/or classes that reports process wall-clock time, kernel-time, and user-time, using Windows GetProcessTimes and POSIX times(), etc. --Beman

Silex wrote:
That's fine with me, assuming documentation is updated as needed.
I can do it if nobody wants to do it, but someone have to explain me where are the files/how to submit them etc.
Well, I thought that the ultimate plan was to deprecate timer and move it into date_time -- my fault this hasn't happened -- although maybe it would be better to leave it stand-alone and let it depend on some date-time core. Regardless I would highly suggest looking at Quickbook to do new documentation. Jeff

Well, I thought that the ultimate plan was to deprecate timer and move it into date_time -- my fault this hasn't happened -- although maybe it would be better to leave it stand-alone and let it depend on some date-time core. Regardless I would highly suggest looking at Quickbook to do new documentation.
Jeff
I have nothing against moving it into date_time. I'll take a look at Quickbook to see how it works... While I'm doing that, can you tell me if the header copyright text suits you ? I asked you a while ago if it was ok because I'm not experienced in writing those so I did how I thought it'd be. Philippe

If anybody cares, here's the QPC counter overload I've been using. It has the same functionality as the timer class. I could do a similar one using gettimeofday on Linux if somebody is interested. class usecTimer : public timer{ #ifdef WIN32 public: usecTimer() { QueryPerformanceFrequency(&_pc_freq); _start_time = HFClock(); } // postcondition: elapsed()==0 void restart() { _start_time = HFClock(); } // post: elapsed()==0 double elapsed() // return elapsed time in seconds { return HFClock() - _start_time; } double elapsed_max() const // return estimated maximum value for elapsed() { return double((std::numeric_limits<LONGLONG>::max)()) / double(_pc_freq.QuadPart); } double elapsed_min() const // return minimum value for elapsed() { return (1.0 / double(_pc_freq.QuadPart)); } private: LARGE_INTEGER _pc_freq, _now_tic; double _start_time; double HFClock(void) { assert(_pc_freq.QuadPart != 0); // Query current clock tick QueryPerformanceCounter(&_now_tic); return double(_now_tic.QuadPart) / double(_pc_freq.QuadPart); } #endif };
Because of the long discussion about QueryPerformanceCounter that didn't came to a real conclusion, I decided to implement two additionnal timers:
- boost::qpc_timer, which use QueryPerformanceCounter() for its resolution. - boost::tgt_timer, which use timeGetTime() for its resolution.
As using those timers would make no sense on another platform than windows, those are not defined by default. One must #define BOOST_QPC_TIMER to get boost::qpc_timer and must #define BOOST_TGT_TIMER to get boost::tgt_timer.
Trying to do those defines on another platform than windows results in an #error.

Silex wrote:
Hello,
As I didn't receive the answers I was looking for, here is my last proposal.
[snip]
Because of the long discussion about QueryPerformanceCounter that didn't came to a real conclusion, I decided to implement two additionnal timers:
- boost::qpc_timer, which use QueryPerformanceCounter() for its resolution. - boost::tgt_timer, which use timeGetTime() for its resolution.
As using those timers would make no sense on another platform than windows, those are not defined by default. One must #define BOOST_QPC_TIMER to get boost::qpc_timer and must #define BOOST_TGT_TIMER to get boost::tgt_timer.
I've always found it really awkward having to define global macros to get features. Why not simply: (in "main" timer include file) ------- #if defined (BOOST_WINDOWS) # include <boost/.../qpc_timer.hpp> # include <boost/.../tgt_timer.hpp> #endif ------- and/or (in specific implementations - qpc/time_get_time_timer) ------- #if defined (BOOST_WINDOWS) namespace boost { class <windows_specific_timer> { ... }; } #endif // BOOST_WINDOWS ------- // Johan

I've always found it really awkward having to define global macros to get features.
Well I agree with you but timeGetTime requires a #pragma lib(comment, "winmm.lib") and I thought this was a bit ackward to force it for people not wanting that extra library. I also thought 99% of the people would be happy of the timer implementation with boost::posix_time::microsec_clock, the qpc/tgt timers being "extra". But alright, I reckon most people will think like you. I'll do the suggested changes and post again during the day. Philippe

Here attached is my last work on the timer, the qpc_timer/tgt_timer are in a file of their own now. This made me remove the time_type template argument, as on my last imlpementation the qpc / tgt timers where only template specializations of the timer class. They are now class on their own, and it's probably better this way. Can someone review ? Thank you. Philippe

On Mon, May 15, 2006 at 04:55:27PM +0200, Carlo Wood wrote:
Now, there is a problem imho with it's type: An absolute time is different from a relative time. The fact that an absolute time is
Yes and no. Your "absolute time" is still relative to whatever definition you have of January 1, 1970. Which is relative to whichever definition you have of the birth of a well-known religious leader, which in turn is relative to certain properties of the earth spinning around the sun, etc. Einstein was confused by this mess and postulated that there's no such thing as "absolute time". A couple of years later physical experiments showed that his theory is more than plausible. Having implemented several major frameworks in C++ in which time played a crucial rule, I have a pretty firm view on the subject: No time type should include information about relative to which point it is measured. This is the job of the spec of the function that hands out a time value, but *not* of the type. Physics gives quite clear directions as to which operations a time type must support: - Addidtion, subtraction, comparison with other time's. - Division by other time's to give a dimensionless type. - Conversion to/from whatever is useful, maybe stream operators. Note that any builtin arithmetic types support those operations, but they're not "typesafe" in the sense that you might end up e.g. adding time and length. A user-defined type can protect you from those accidents by only defining the above mentioned operations. *If* we want a user-defined type to represent time, it may well be part of a general framework for physical quantities. See e.g. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1451.html, section 6 for ideas on how this can be done.
that the two are the same thing, but I'd argue that it would be better to make TWO types.
I strongly disagree, for the above reasoning. Regards -Gerhard -- Gerhard Wesp ZRH office voice: +41 (0)44 668 1878 ZRH office fax: +41 (0)44 200 1818 For the rest I claim that raw pointers must be abolished.

On Mon, May 15, 2006 at 06:02:34PM +0200, Gerhard Wesp wrote:
Having implemented several major frameworks in C++ in which time played a crucial rule, I have a pretty firm view on the subject: No time type should include information about relative to which point it is measured.
This doesn't give arguments.
that the two are the same thing, but I'd argue that it would be better to make TWO types.
I strongly disagree, for the above reasoning.
Though you are theoretically correct to say that also the time as returned by -whatever- (ie, gettimeofday) is relative to some point, it isn't very practical to consider it's value relative. The concept of "NOW" seems clear to me. And "NOW" is an absolute time, not a relative one. The fact that one HAS to store/represent it as a relative time is exactly what is so confusing, and THEREFORE calls for a separate type. It makes no sense to code, Time t1 = now(); Time t2 = now(); Time t3 = t1 + t2; as the result of the addition would be dependent on the time that the *implementation* of Time is relative to (ie, 1970). But the coder in general will not care if 'now' is relative stored relative to 1970 or to 2005: he should be shielded from that. Therefore, adding Time + Time should not compile. I think these are sound argument FOR two types, and AGAINST just a single type for relative time. -- Carlo Wood <carlo@alinoe.com>

On Tue, May 16, 2006 at 01:20:46AM +0200, Carlo Wood wrote:
The concept of "NOW" seems clear to me. And "NOW" is an absolute time, not a relative one. The fact that one HAS to
Maybe Einstein would disagree... :) Another poster pointed out that t1 + t2 is a perfectly valid expression, and I have to add scalar multiplication to the requirements a time type should support. -Gerhard -- Gerhard Wesp ZRH office voice: +41 (0)44 668 1878 ZRH office fax: +41 (0)44 200 1818 For the rest I claim that raw pointers must be abolished.

"Gerhard Wesp" wrote
Physics gives quite clear directions as to which operations a time type must support: - Addidtion, subtraction, comparison with other time's. - Division by other time's to give a dimensionless type. - Conversion to/from whatever is useful, maybe stream operators.
Note that any builtin arithmetic types support those operations, but they're not "typesafe" in the sense that you might end up e.g. adding time and length. A user-defined type can protect you from those accidents by only defining the above mentioned operations.
*If* we want a user-defined type to represent time, it may well be part of a general framework for physical quantities. See e.g. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1451.html, section 6 for ideas on how this can be done.
BTW It might be useful to point out that my Physical Quantities library 'pqs' , which provides the above operations, is up for Formal Review by Boost at some time in the near future: http://tinyurl.com/7m5l8 (I hope that 'pqs_3_1_0' in that directory will be the review version, but that will be subject to my Review Managers approval. If all is in order then I hope that the review dates for pqs will be confirmed soon). regards Andy Little

Hello Here attached is the latest version of the boost::timer modification. About doing the documentation I must say that QuickBook & BoostBook confused me. I understand QuickBook generates BoostBook's documentation but how to use it ? At the moment I'm only doing the documentation in a plain text file waiting for your answers... I *think* I understood that I'm supposed to write a .qbk file, but how to then make Spirit generate the xml for BoostBook is beyond me, I'm not used to Spirit yet. Thank you for your help Philippe

For whatever datatype the "elapsed" function returns, I think we had better have istream/ostream overloads for it. The current one returns "double", which works fine with istream/ostream. The overload should return or parse secs.fracsecs in all various forms. Silex wrote:
Hello
Here attached is the latest version of the boost::timer modification.
About doing the documentation I must say that QuickBook & BoostBook confused me. I understand QuickBook generates BoostBook's documentation but how to use it ?
At the moment I'm only doing the documentation in a plain text file waiting for your answers... I *think* I understood that I'm supposed to write a .qbk file, but how to then make Spirit generate the xml for BoostBook is beyond me, I'm not used to Spirit yet.
Thank you for your help Philippe ------------------------------------------------------------------------
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

For whatever datatype the "elapsed" function returns, I think we had better have istream/ostream overloads for it. The current one returns "double", which works fine with istream/ostream. The overload should return or parse secs.fracsecs in all various forms.
Interesting, but this is a change request for the date_time lib then ? Maybe there's already an ostream& operator<< for the boost::posix_time::ptime etc types, I'll have a look. Philippe

Silex wrote:
For whatever datatype the "elapsed" function returns, I think we had better have istream/ostream overloads for it. The current one returns "double", which works fine with istream/ostream. The overload should return or parse secs.fracsecs in all various forms.
Interesting, but this is a change request for the date_time lib then ? Maybe there's already an ostream& operator<< for the boost::posix_time::ptime etc types, I'll have a look.
There is and it does what you would expect with fractional seconds, etc. (eg: 00:00:01.1234567). With a facet you can control the format of the output. http://www.boost.org/doc/html/date_time/date_time_io.html Jeff

Silex wrote:
Hello
Here attached is the latest version of the boost::timer modification.
About doing the documentation I must say that QuickBook & BoostBook confused me. I understand QuickBook generates BoostBook's documentation but how to use it ?
At the moment I'm only doing the documentation in a plain text file waiting for your answers... I *think* I understood that I'm supposed to write a .qbk file, but how to then make Spirit generate the xml for BoostBook is beyond me, I'm not used to Spirit yet.
Hi Philippe - Sorry I haven't got a chance to look at this till now. First, it might be nice if you could upload a version to the vault so other people can try it out. http://boost-consulting.com/vault/index.php?&direction=0&order=&directory=date_time Now a couple questions on the code. What is the time_duration_type elapsed() const { if(m_start.QuadPart) { LARGE_INTEGER current; if(!QueryPerformanceCounter(¤t)) throw std::runtime_error("qpc: QueryPerformanceCounter() failed"); boost::uint64_t milliseconds = (current.QuadPart - m_start.QuadPart) / m_frequency.QuadPart; boost::uint32_t seconds = milliseconds / 1000; boost::uint32_t minutes = seconds / 60; boost::uint32_t hours = minutes / 60; milliseconds = milliseconds % 1000; m_elapsed += time_duration_type(hours, minutes, seconds, milliseconds); m_start = current; } return m_elapsed; } I think this code is both inefficient and likely non-portable. As I understand it, QueryPerformanceCounter has a hardware defined resolution that can be queried by calling QueryPerformanceFrequency. QPF provides the counts per second. You should be able to use this to more simply construct the time_duration. So, for example, if QPF returned 1000 you could simply say m_elapsed += boost::posix_time::milliseconds(current-previous); I'm guessing nanoseconds might be the best duration type to use in the calculation. Thx for your effort in this area. Jeff

Sorry I haven't got a chance to look at this till now. First, it might be nice if you could upload a version to the vault so other people can try it out.
Ok will do so with the next version that should come very soon. I think this code is both inefficient and likely non-portable. Hum, by definition QueryPerformanceCounter is non-portable ? As I understand it, QueryPerformanceCounter has a hardware defined
resolution that can be queried by calling QueryPerformanceFrequency. QPF provides the counts per second. You should be able to use this to more simply construct the time_duration. So, for example, if QPF returned 1000 you could simply say
m_elapsed += boost::posix_time::milliseconds(current-previous);
I'm guessing nanoseconds might be the best duration type to use in the calculation.
Hum you are probably right, I'm not that much used to date_time so I thought I had to construct using the constructor but what you just showed is indeed much simpler. Thank you Philippe

"Philippe Vaucher" wrote:
As I understand it, QueryPerformanceCounter has a hardware defined
resolution that can be queried by calling QueryPerformanceFrequency. QPF provides the counts per second. You should be able to use this to more simply construct the time_duration.
The measurement will be exact if the execution runs on single processor. On multiprocessor there's always chance that the thread moves elsewhere and the measured value will be slightly different. /Pavel

Pavel Vozenilek wrote:
"Philippe Vaucher" wrote:
As I understand it, QueryPerformanceCounter has a hardware defined
resolution that can be queried by calling QueryPerformanceFrequency. QPF provides the counts per second. You should be able to use this to more simply construct the time_duration.
The measurement will be exact if the execution runs on single processor. On multiprocessor there's always chance that the thread moves elsewhere and the measured value will be slightly different.
Yeah, isn't there something I read in the MSDN pages about giving QPC thread affinity to solve this issue? Given the number of dual core chips making their way into the world now this is certain to be a serious problem. Jeff

"Jeff Garland" wrote: [ QueryPerformanceCounter ]
The measurement will be exact if the execution runs on single processor. On multiprocessor there's always chance that the thread moves elsewhere and the measured value will be slightly different.
Yeah, isn't there something I read in the MSDN pages about giving QPC thread affinity to solve this issue? Given the number of dual core chips making their way into the world now this is certain to be a serious problem.
SetThreadAffinityMask() The tool likely needs to check presence of multiple processors, temporarily fix the affinity and then return it back to original state. If the timer will measure time on several levels of call tree only the top timer should do this to avoid expensive system calls. Another problem may be CPU that changes its frequency (Transmeta did this and some CPUs for notebooks may do as well). I think handling this would be over the top for simple timer, though. /Pavel

Hello, Here's the latest version: http://boost-consulting.com/vault/index.php?action=downloadfile&filename=new_timer_2006-06-28.zip&directory=date_time& I did the different correction people suggested... I'm now struggling with trying to set up QuickBook but it really lacks documentation :) Philippe

"Philippe Vaucher" wrote
Hello,
Here's the latest version:
I did the different correction people suggested... I'm now struggling with trying to set up QuickBook but it really lacks documentation :)
Try the Boostbook documentation for setting up the toolchain. Its quite comprehensive. (Thanks Doug Gregor). I put Quickbook.exe in my path ( actually in Boosts <dist/bin/> directory, from wherever bjam puts it when it does the boost build (or just run Bjam in the Quickbook source directory). Finally you need a Jamfile.v2 in the same directory as the timer.qbk or whatever its called. Look at similar jamfiles for Quickbook source docs for other libarries. I basically copied mine over and substituted the names from them. Invoke Bjam in that directory and you should be 'cooking with gas' as they say. Anyway its definitely worth persevering with. The whole Quickbook, Boostbook , DocBook thing is very powerful. HTH regards Andy Little

Andy wrote
I did the different correction people suggested... I'm now struggling with trying to set up QuickBook but it really lacks documentation :)
Try the Boostbook documentation for setting up the toolchain. Its quite comprehensive.
I have wrote some docs about quickbook installation. You can read it here: http://h1.ripway.com/mcape/boost/libs/misc/misc/developed_tools_during_the_p... Hope it helps you... Best Regards Matias Capeletto

Hello, I have quickbook up and running and I'm currently doing the documentation, it goes quite well except I lose most of my time learning the quickbook format instead and sometimes I'm tempted to just screw it and write plain html instead :) But I'll resist and it seems indeed quite powerfull. My question is about where to place this new timer class, there were suggestion to remove boost::timer entirely and move it into boost::date_time, if so, where ? as it uses boost::posix_time::ptime as default argument I guessed boost::posix_timer::timer ? If it stays as boost::timer standalone lib, what do I do of the "old" boost::timer ? plain replacement ? I'll post my current documentation in a few days. Thank you for your input, Philippe

My question is about where to place this new timer class, there were suggestion to remove boost::timer entirely and move it into boost::date_time, if so, where ? as it uses boost::posix_time::ptime as default argument I guessed boost::posix_timer::timer ?
boost::posix_timer::timer should read boost::posix_time::timer of course. Philippe

On Thu, 13 Jul 2006 23:56:08 +0200, "Philippe Vaucher" <philippe.vaucher@gmail.com> wrote:
My question is about where to place this new timer class, there were suggestion to remove boost::timer entirely and move it into boost::date_time, if so, where ? as it uses boost::posix_time::ptime as default argument I guessed boost::posix_timer::timer ?
I guess the whole component has to go through a fast track review, at least <http://www.boost.org/more/formal_review_process.htm#Fast-Track> At a first glance there are a couple of points which perplex me, for instance the auto_start/manual_start option. Also, wouldn't an std::clock() based Clock be worth having anyway? AFAICS, only a Win32 Clock is provided. What I've found with some experiments (I was writing a timer template myself) is that though std::clock() has obvious limitations, and though we are probably all waiting for this <http://david.tribble.com/text/c0xtimet.htm> the biggest problem is with those implementations (guess which one(s)? :)) that think it has to yield wall-clock time rather than process time. However for those implementation(s) one might use (guess what?) qpc_clock. It would also be useful to make a quick comparison with an implementation based on GetProcessTimes(), if this hasn't already been discussed. Don't be too formal, just a couple of sentences for us to understand :) -- [ Gennaro Prota, C++ developer for hire ] [ resume: available on request ]

I guess the whole component has to go through a fast track review, at least
Hum, ok. At a first glance there are a couple of points which perplex me, for
instance the auto_start/manual_start option.
Well it thought it was pretty obvious, if you want the timer to start immediatly when it is created of if you want to manually start it with tmr.start(). To be honest I just took the draft design that was on the wiki and on vault (from Jeff iirc). Also, wouldn't an std::clock() based Clock be worth having anyway? Why not, will try to add one. AFAICS, only a Win32 Clock is provided. No no no, this new timer class is meant to be used along with boost::posix_time::microsec_clock or boost::posix_time::second_clock. The QueryPerformanecCounter or timeGetTime() implementations are just to give the user more choices. However for those implementation(s) one might use (guess what?)
qpc_clock.
I think 99% of the people will use boost::microsec_timer which is just a typedef for boost::timer<boost::posix_time::microsec_clock, boost::posix_time::ptime>. Maybe there's something I didn't understand there :) It would also be useful to make a quick comparison with an
implementation based on GetProcessTimes(), if this hasn't already been discussed.
This wasn't discussed but I think it's mainly because this api never seems to be used for timing stuffs, it's usually GetTickCount(), QueryPerformanceCounter() or timeGetTime(). IIRC, boost::posix_time:microsec_clock uses GetSystemTime()... Anyway, I'll try to do a clock() based timer and give a go at GetProcessTimes(). I'll propose the whole for a fast track review once I'm done with the documentation and everything, so you think I'd not care about where this timer class should be now (date_time or timer) and let the review decide it ? Philippe

if you want the timer to start immediatly when it is created of if you want to manually start it with tmr.start ().
That isn't very clear : If you want the timer to start immediatly when the object is created you use auto_start, if you want to manually start it you use manual_start and then tmr.start(). A code makes it more clear : // Timer will start automagically microsec_timer tmr; // Timer won't start microsec_timer tmr2(microsec_timer::time_duration_type(0, 0, 0), manual_start); // Start timer now ! tmr2.start(); Philippe

On Fri, 14 Jul 2006 09:58:40 +0200, "Philippe Vaucher" <philippe.vaucher@gmail.com> wrote:
I guess the whole component has to go through a fast track review, at least
Hum, ok.
I restate that this was just a guess on my part. The point is, I'm under the impression this has grown a bit beyond the (arbitrary) limit under which we consider additions as sort of "patches" which can go into the code without discussion.
At a first glance there are a couple of points which perplex me, for
instance the auto_start/manual_start option.
Well it thought it was pretty obvious, if you want the timer to start immediatly when it is created of if you want to manually start it with tmr.start().
Yes, I understood what the effect was :) I just wasn't sure it was a good design choice, as the manual_start mode leaves to the user's responsibility to correctly couple start/stop calls.
To be honest I just took the draft design that was on the wiki and on vault (from Jeff iirc).
Also, wouldn't an std::clock() based Clock be worth having anyway?
Why not, will try to add one.
If you give me a day or two I can try and cleanup the code I already have. I guess we could "merge" the two solutions in some way.
AFAICS, only a Win32 Clock is provided.
No no no, this new timer class is meant to be used along with boost::posix_time::microsec_clock or boost::posix_time::second_clock.
Ok :)
It would also be useful to make a quick comparison with an
implementation based on GetProcessTimes(), if this hasn't already been discussed.
This wasn't discussed but I think it's mainly because this api never seems to be used for timing stuffs, it's usually GetTickCount(), QueryPerformanceCounter() or timeGetTime(). IIRC, boost::posix_time:microsec_clock uses GetSystemTime()...
Anyway, I'll try to do a clock() based timer and give a go at GetProcessTimes().
My code, like Beman's, is based on GetProcessTimes(), because that isn't affect by other running processes. AFAIK, the only particular advantage of GetTickCount() among Windows-specific options is that it is available everywhere, including Windows CE, IIRC.
I'll propose the whole for a fast track review once I'm done with the documentation and everything, so you think I'd not care about where this timer class should be now (date_time or timer) and let the review decide it ?
Yes, that was my idea. -- [ Gennaro Prota, C++ developer for hire ] [ resume: available on request ]

Well it thought it was pretty obvious, if you want the timer to start immediatly when it is created of if you want to manually start it with tmr.start().
Yes, I understood what the effect was :) I just wasn't sure it was a good design choice, as the manual_start mode leaves to the user's responsibility to correctly couple start/stop calls.
Hum, manual_start simply has the effect that the timer doesn't starts automatically when the object is created, nothing more. I dont really understand what's bad in that as the defaut parameter is auto_start... care to explain a bit more ? If you give me a day or two I can try and cleanup the code I already
have. I guess we could "merge" the two solutions in some way.
Sure ! Philippe

On Fri, 14 Jul 2006 17:28:46 +0200, "Philippe Vaucher" <philippe.vaucher@gmail.com> wrote:
Hum, manual_start simply has the effect that the timer doesn't starts automatically when the object is created, nothing more. I dont really understand what's bad in that as the defaut parameter is auto_start... care to explain a bit more ?
Sorry Philippe, I thought there was a stop() function as well, but it was just my assumption when seeing "start" :-/ I'm adding some more comments to my sources and cleaning them up: nothing to make them ready for prime time but the purpose should be to collect as many ideas as possible in the form of real code, rather than textual posts or sentences in a wiki page. I'd like Beman to join the discussion as well, and John Maddock, who is interested in these classes. The more eyes at it the better (and I have called some good eyes :)). My impression so far is that my code and yours can integrate and be a part of Date.Time, while Beman's variation can be the replacement for the current boost::timer and go in the proposed Boost.System library. But who can say... -- [ Gennaro Prota, C++ developer for hire ] [ resume: available on request ]

Hi guys, The thread "Low-level precision timer proposal" has raised and collected a lot of good ideas and sketchy implementations. I think we can't do any better than that without commenting on real code. That's basically the purpose of this "Part II" (it follows up on the original thread, so those of you who use the NNTP interface might see this message there, depending on news client settings). NOTE: All relevant comments have been inserted in the source files (attached). I would have never remembered all points to bring attention to if I had to write them down when composing this message. Some code could perhaps be factored out and shared between different components. -- [ Gennaro Prota, C++ developer for hire ] [ resume: available on request ] begin 644 low_level_timers.hpp M+R\@+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM M+2TM+2TM+2TM+0T*+R\@;&]W+6QE=F5L('1I;65R<PT*+R\-"B\O("A#*2!' M96YN87)O(%!R;W1A(#(P,#8-"B\O#0HO+R!-86YY('1H86YK<R!T;R!0879E M;"!6;WIE;FEL96L@9F]R(&-O;G-T<G5C=&EV90T*+R\@92UM86EL(&1I<V-U M<W-I;VXL('=H96X@=&AE<V4@=V5R92!J=7-T('9A9W5E#0HO+R!I;G1E;G1S M(&EN(&UY(&UI;F0@.BD-"B\O#0HO+R!0<F5L:6UI;F%R>2!V97)S:6]N+"!F M;W(@8F]O<W0@9&5V96QO<&5R<R!L:7-T(&]N;'DN#0HO+R`M+2TM+2TM+2TM M+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM M+2TM#0H-"B\O('1I;65R(&-L87-S97,-"B\O#0HO+R!->2!I;FET:6%L(&=O M86QS('=E<F4Z#0HO+PT*+R\@,2X@4')O=FED93H-"B\O("`M('=A;&P@8VQO M8VL@=&EM97(@*'5S97(O<WES=&5M*0T*+R\@("T@<')O8V5S<R!T:6UE<B`H M=7-E<B]S>7-T96TI#0HO+R`@+2!T:')E860@=&EM97(@("AU<V5R+W-Y<W1E M;2D-"B\O#0HO+R`R+B!!;&QO=R!S96QE8W1A8FQE('!R96-I<VEO;@T*+R\- M"B\O(#,N($ED96YT:69Y('-U:71A8FEL92!P;VQI8VEE<PT*+R\-"B\O($$@ M<75I8VL@:6YT<F]D=6-T:6]N.@T*+R\-"B\O(%1H:7,@:7,@86X@871T96UP M="!T;R!B=6EL9"!T:6UE<B!F86-I;&ET:65S('=H:6-H(&-A;@T*+R\@96%S M:6QY(&EN=&5R;W!E<F%T92!W:71H(&)O=&@@=&AE('-T86YD87)D(&QI8G)A M<GD@86YD#0HO+R!W:71H($)O;W-T($1A=&4M5&EM92X@5&AE('1E<FUI;F]L M;V=Y('5S960@:&5R92!C;&]S96QY#0HO+R!F;VQL;W=S('1H92!O;F4@;V8@ M1&%T92U4:6UE(&ET<V5L9BX@2V5Y(&1E<VEG;B!G;V%L<PT*+R\@=V5R93H- M"B\O#0HO+R`@+2!N;R!C;W5P;&EN9R!W:71H(&5X=&5R;F%L(&-O;7!O;F5N M=',L('5N;&5S<R!N965E9&5D#0HO+R`@+2!E>'1E;G-I8FEL:71Y(`T*+R\- M"B\O($-H;VEC97,Z#0HO+PT*+R\@57!O;B!E>&%M:6YA=&EO;B!O9B!T:&4@ M=F%R:6]U<R!T:6UI;F<@9F%C:6QI=&EE<PT*+R\@;V9F97)E9"!B>2!E>&ES M=&EN9R!P;&%T9F]R;7,L(&ET(&%P<&5A<F5D(&-L96%R('1H870@=&AE#0HO M+R!M;W-T(&1I9F9I8W5L="!P87)T(&]F(&1E<VEG;FEN9R!A('!O<G1A8FQE M(&QI8G)A<GD@=V%S#0HO+R!T:&4@8F5H879I;W(@<W!E8VEF:6-A=&EO;BX@ M4&%R=&EC=6QA<FQY('1R:6-K>2!A<W!E8W1S(&%R90T*+R\@/'!R96-I<VEO M;CXL(#QL:6YE87)I='D^(&%N9"`\;6]N;W1O;FEC:71Y/BX@26X@<VAO<G0@ M22=V90T*+R\@8F5E;BP@<V\@9F%R+"!O;FQY(&%B;&4@=&\@;65E="!G;V%L M("@Q*0T*+R\-"B\O($QE="=S(&=O(&)Y('-T97!S.@T*+R\-"B\O("`M($UO M9&5R;B!#4%5S("AE+F<N(%!E;G1I=6TI(&UA>2!O9F9E<B!A(")T:6UE('-T M86UP(&-O=6YT97(B#0HO+R`@=VAI8V@@<V5E;7,@=&\@<&5R9F5C=&QY(&9I M="!T:&4@;F5E9',@;V8@82!H:6=H+7!R96-I<VEO;@T*+R\@(&QI8G)A<GD[ M("II="!H87!P96YS(&AO=V5V97(J('1H870@=&AO<V4@0U!5<R!A;'-O(&UA M>2!H879E#0HO+R`@9F5A='5R97,@<W5C:"!A<R`B<W!E960@<W1E<'!I;F<B M+"!O<B!P;W=E<BUS879I;F<@;6]D97,L#0HO+R`@=VAI8V@@;6%Y('5N<')E M9&EC=&EB;'D@86QT97(@=&AE(&-O=6YT97(@=F%L=64@86YD('5P9&%T90T* M+R\@(&9R97%U96YC>2X@06YD('-O;65T:6UE<R!T:&4@3U,@;6%Y(&1I<V%B M;&4@<W5C:"!C;W5N=&5R<RX-"@T*+R\@($UO<F4@:6YF;SH-"B\O("`@/&AT M='`Z+R]A<W!N+F%C=&EV97-T871E+F-O;2]!4U!.+TUA:6PO365S<V%G92]B M;V]S="\Q,3,W,C@S/@T*#0HO+R`@3F]T92!T:&%T('1H:7,@87!P;&EE<R!E M=F5N(&EF(&=O:6YG(&1O=VX@=&\@=&AE(&%S<V5M8FQY#0HO+R`@;&5V96PN M($EF(&%N($%022!C86QL(&ES('5S960L(&EN<W1E860L(&]T:&5R(&9A8W1O M<G,@861D#0HO+R`@=&\@=&AE(&UI>"P@87,@97AP;&%I;F5D(&)E;&]W+@T* M+R\-"B\O("`M(%1I;64@<V]U<F-E<R!W:&EC:"!A<F4@:&%N9&QE9"!B>2!S M;V9T=V%R92!A<F4@:6YH97)E;G1L>0T*+R\@("`@=6YR96QI86)L92P@97-P M96-I86QL>2!I;B!M=6QT:7!R;V-E<W-O<B!A;F0O;W(@<')E+65M<'1I=F4- M"B\O("`@(&UU;'1I+71A<VMI;F<@;W!E<F%T:6YG('-Y<W1E;7,N#0H-"B\O M("TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM M+2TM+2TM+2TM+2TM+2TM+2TM+2TM#0H-"B\O(%1H92!C;V1E(&)U:6QD<R!A M<F]U;F0@=&AE(&9O;&QO=VEN9R!A8G-T<F%C=&EO;CH-"B\O#0HO+R`@*&$I M(&%N(&5L87!S961?=&EM97(@8V%N('5S92!A;GET:&EN9R!W:&EC:"!M;V1E M;',@=&AE#0HO+R`@("`@(&-O;F-E<'0@;V8@(F-L;V-K(&1E=FEC92(@87,@ M:71S('-O=7)C93L@=&AI<R!C86X@8F4-"B\O("`@("`@82!H87)D=V%R92!D M979I8V4L(&$@;F5T=V]R:R!T:6UE('!R;W9I9&5R+"!A($=04R!S>7-T96TN M+BX-"B\O#0HO+R`@("`@($D@<&QA;B!T;R!H879E(&$@8VQO<V5R(&QO;VLL M(&)U="!A<VEO(&]F9F5R<R`B8V]U;G1D;W=N#0HO+R`@("`@('1I;65R<R([ M($D@=&AI;FL@:70G<R!W;W)T:"!S96EN9R!I9B!T:&5Y(&-A;B!B92!E>'1R M87!O;&%T960-"B\O("`@("`@9G)O;2!T:&5R92P@97-P96-I86QL>2!I9B!T M:&5Y(&%L<F5A9'D@<F5L>2!O;B!";V]S="Y$871E+51I;64N#0HO+PT*#0HO M+PT*+R\@3U!%3B!)4U-515,Z#0HO+PT*+R\@(&-O=6QD(&$@;FEC92`B=&EM M92!R97!O<G1E<B(L(&QI:V4@=&AE(&]N92!"96UA;B!P<F]P;W-E9"P-"B\O M("!B92!I;G1R;V1U8V5D(&AE<F4_#0H-"B-I;F-L=61E(#QS=&1E>&-E<'0^ M#0H-"B\O(&=P<R`M('1E;7!O<F%R>2!H96QP97(-"G9O:60@9VQO8F%L7W1H M<F]W7VAE;'!E<BAC;VYS="!C:&%R*B!M<V<I#0I[#0H@("`@=&AR;W<@<W1D M.CIR=6YT:6UE7V5R<F]R*&US9RD[#0I]#0H-"B\O("TM+2TM+2TM+2TM+2TM M+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+0T* M#0HC:6YC;'5D92`B8F]O<W0O9&%T95]T:6UE+W!O<VEX7W1I;64O<&]S:7A? M=&EM92YH<'`B#0H-"@T*=&5M<&QA=&4@/'1Y<&5N86UE(%0^#0IS=')U8W0@ M8VQO8VM?9&5V:6-E7W1R86ET<PT*>PT*("`@("\O(&=P<R!43T1/#0H@("`@ M+R]H87-?<WEN8VA?<W1A<G0_#0I].PT*#0H-"G1E;7!L871E(#QT>7!E;F%M M92!$979I8V4^("\O(")C;&]C:R!D979I8V4B#0IC;&%S<R!E;&%P<V5D7W1I M;65R("\O(&%S(&1I<W1I;F-T(&9R;VT@82`B8V]U;G1D;W=N('1I;65R(@T* M>PT*<'5B;&EC.@T*("`@("\O(&=P<R`M(&1O('=E(&YE960@=&AE<V4@='=O M('1Y<&5D969S/PT*("`@("\O('1Y<&5D968@5&EM95!O:6YT('1I;65?='EP M93L-"B`@("`O+W1Y<&5D968@='EP96YA;64@1&5V:6-E.CIT:6UE7W!O:6YT M7W1Y<&4@=&EM95]P;VEN=%]T>7!E.PT*#0H@("`@='EP961E9B!T>7!E;F%M M92!$979I8V4Z.G1I;65?9'5R871I;VY?='EP92!D=7)A=&EO;E]T>7!E.PT* M#0H@("`@96YU;2!S=&%R=%]M;V1E('L@875T;U]S=&%R="P@;6%N=6%L7W-T M87)T('T[#0H@("`@+RIE>'!L:6-I="HO(&5L87!S961?=&EM97(H<W1A<G1? M;6]D92`](&%U=&]?<W1A<G0I.PT*#0H@("`@=F]I9"!S=&%R="@I.PT*("`@ M('9O:60@<F5S=&%R="@I.PT*#0H@("`@9'5R871I;VY?='EP92!E;&%P<V5D M*"D@8V]N<W0[#0H-"B`@("!V;VED('!A=7-E*"D[#0H@("`@=F]I9"!R97-U M;64H*3L@+R\@9W!S("T@=VAA="!I9B!Y;W4@8V%L;"!T=VEC92!P875S92P@ M='=I8V4@<F5S=6UE(&-O;G-E8W5T:79E;'D_/PT*#0H@("`@+R\@8F]O;"!I M<U]R=6YN:6YG*"D@8V]N<W0@+R\@9W!S("T@861D('1H:7,_/PT*#0H@("`@ M+R\@9W!S.B!)('-E92!N;R!P;VEN="!I;B!H879I;F<@8VQE87)?96QA<'-E M9"@I#0H-"G!R:79A=&4Z#0H@("`@8F]O;"`@("`@("`@("`@(&ES7W)U;FYI M;F<[("\O(&=P<R!N96-E<W-A<GD_#0H@("`@1&5V:6-E("`@("`@("`@(&1E M=FEC93L-"B`@("`O+W1I;65?<&]I;G1?='EP92!L87-T7W-T87)T.PT*("`@ M(&1U<F%T:6]N7W1Y<&4@("!D=7)A=&EO;CL-"@T*?3L-"@T*=&5M<&QA=&4\ M='EP96YA;64@1#X-"F5L87!S961?=&EM97(\1#XZ.F5L87!S961?=&EM97(H M<W1A<G1?;6]D92!M;V1E*0T*("`Z(&ES7W)U;FYI;F<H9F%L<V4I+"!D979I M8V4H*2P@+RH@;&%S=%]S=&%R="@I+"HO(&1U<F%T:6]N*"D-"GL-"B`@("!I M9BAM;V1E(#T](&%U=&]?<W1A<G0I#0H@("`@("`@('-T87)T*"D[#0I]#0H- M"G1E;7!L871E(#QT>7!E;F%M92!$/@T*=F]I9"!E;&%P<V5D7W1I;65R/$0^ M.CIS=&%R="@I("\O(&UA>2!T:')O=PT*>PT*("`@(')E<W1A<G0H*3L@+R\@ M=&AI<R!I<R!J=7-T('1H92!S86UE(&%S(')E<W1A<G0H*3L-"B`@("`@("`@ M("`@("`@("\O(&UA>6)E('=E(&-A;B!C;VUE('5P('=I=&@@82!C;VUM;VX@ M;F%M92`M9W!S#0I]#0H-"@T*+R\@=&AI<R!I<R!J=7-T(&$@8V]N=F5N:65N M8V4@<WEN;VYY;2!F;W(@<W1A<G0H*3L-"G1E;7!L871E(#QT>7!E;F%M92!$ M/@T*=F]I9"!E;&%P<V5D7W1I;65R/$0^.CIR97-T87)T*"D@+R\@;6%Y('1H M<F]W#0I[#0H@("`@9&5V:6-E+G-T87)T*"D[#0H@("`@:7-?<G5N;FEN9R`] M('1R=64[#0I]#0H-"@T*=&5M<&QA=&4@/'1Y<&5N86UE($0^#0IT>7!E;F%M M92!E;&%P<V5D7W1I;65R/$0^.CID=7)A=&EO;E]T>7!E#0IE;&%P<V5D7W1I M;65R/$0^.CIE;&%P<V5D*"D@8V]N<W0-"GL-"B`@("!R971U<FX@:7-?<G5N M;FEN9PT*("`@("`@("`_(&1E=FEC92YE;&%P<V5D*"D@+2!D=7)A=&EO;@T* M("`@("`@("`Z(&1U<F%T:6]N.PT*?0T*#0H-"G1E;7!L871E(#QT>7!E;F%M M92!$/@T*=F]I9"!E;&%P<V5D7W1I;65R/$0^.CIP875S92@I#0I[#0H@("`@ M+R\@=&AR;W<@:68H(6ES7W)U;FYI;F<I(#\_("T@9W!S#0H@("`@9'5R871I M;VX@*ST@9&5V:6-E+F5L87!S960H*3L-"B`@("!I<U]R=6YN:6YG(#T@9F%L M<V4[#0H-"GT-"@T*=&5M<&QA=&4@/'1Y<&5N86UE($0^#0IV;VED(&5L87!S M961?=&EM97(\1#XZ.G)E<W5M92@I#0I[#0H@("`@+R\@:68@*"%I<U]R=6YN M:6YG*2`_/R`M(&=P<PT*("`@(')E<W1A<G0H*3L@+R\@9W!S("T@<W1I;&P@ M=&AE('-A;64A(2$-"GT-"@T*#0HO+R`M+2TM+2TM+2TM+2TM+2TM+2TM+2TM M+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2T-"@T* M+R\@<W1D.CIC;&]C:U]T('1I;64@<F5S;VQU=&EO;B!T<F%I=',-"B\O(%MG M<'-=#0H-"@T*+R\@+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM M+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM#0H-"B\O(%-P96-I9FEC M($-L;V-K($1E=FEC97,-"@T*+R\@9W!S("T@<VAO=6QD('1H:7,@8F4@8V]P M>6%B;&4_#0HO+PT*+R\@3F]T92!T:&%T(&]N;'D@='=O('!U8FQI8R!F=6YC M=&EO;G,@87)E(')E<75I<F5D(&9O<B!A($-L;V-K($1E=FEC93H-"B\O#0HO M+R`@=&EM95]P;VEN=%]T>7!E+W9O:60@<W1A<G0H*2!;=&AR;W<H(%]?7R`I M72`O+R!G<',-"B\O("!T:6UE7V1U<F%T:6]N7W1Y<&4@96QA<'-E9"@I(%MT M:')O=R`H(%]?7RE=#0HO+PT*+R\@6U)%35T@02!N:6-E(&9E871U<F4@;V8@ M8U]C;&]C:U]D979I8V4@:7,@=&AA="P@8F5I;F<@:70@8F%S960-"B\O("`@ M("`@(&]N('-T9#HZ8VQO8VLH*2P@:70@9&]E<VXG="!R96%L;'D@;F5E9"!A M;GD@(G1I;64@<&]I;G0B#0HO+R`@("`@("!A;F0@:7,@=&AU<R!N;W0@869F M96-T960@8GD@<WES=&5M('1I;64@;W(@1%-4(&-H86YG97,[#0HO+R`@("`@ M("!F=7)T:&5R;6]R92!W92!A8W1U86QL>2!D;VXG="!U<V4@96ET:&5R('1I M;64@<&]I;G1S(&]R#0HO+R`@("`@("!T:6UE(&1U<F%T:6]N<R!I;G1E<FYA M;&QY+"!J=7-T(&-L;V-K7W0L(&%N9"!O;FQY(&-O;G9E<G0-"B\O("`@("`@ M(&ET(&%T('1H92!I;G1E<F9A8V4@8F]U;F1A<GD@*"TM<V5E(%M)72D[(&1O M:6YG(&]T:&5R=VES90T*+R\@("`@("`@=V]U;&0@<F5Q=6ER92!A(&1I9F9E M<F5N="!D97-I9VXL($D@9W5E<W,L(&%S('1H92!A8W1U86P-"B\O("`@("`@ M('!R96-I<VEO;B!I<R!N;W0@:VYO=VX@=6YT:6P@<G5N+71I;64@*$IE9F8_ M*2X@270@8V]U;&0@8F4-"B\O("`@("`@(&5S=&EM871E9"!B>2!T:&ES(&9U M;F-T:6]N#0H-"F1O=6)L92!C7V-L;V-K7W!R96-I<VEO;B@I#0I[#0H@("`@ M<W1D.CIC;&]C:U]T(',L(',R.PT*("`@(&-O;G-T('-T9#HZ8VQO8VM?="!K M(#T@<W1D.CIC;&]C:R@I.PT*("`@(&1O('M]('=H:6QE("AK(#T]("AS/7-T M9#HZ8VQO8VLH*2DI.PT*("`@(&1O('M]('=H:6QE("AS(#T]("AS,CUS=&0Z M.F-L;V-K*"DI*3L-"@T*("`@(&1O=6)L92!S96,@/2`H<S(M<RD@*B`Q+C`@ M+R!#3$]#2U-?4$527U-%0SL-"B`@("!R971U<FX@<V5C.PT*?0T*#0HO+R`M M+2TM#0HO+PT*(VEN8VQU9&4@/&-T:6UE/@T*8VQA<W,@8U]C;&]C:U]D979I M8V4@+R\@8F%S960@;VX@<W1D.CIC;&]C:R@I#0I[#0IP=6)L:6,Z#0H@("`@ M+R\@='EP961E9B!T:6UE7W1Y<&4Z.F1A=&5?='EP92`@("`@("`@("!T:6UE M7W!O:6YT7W1Y<&4[("\O(&=P<R`M(&YE961E9#\-"B`@("!T>7!E9&5F(&)O M;W-T.CIP;W-I>%]T:6UE.CIT:6UE7V1U<F%T:6]N('1I;65?9'5R871I;VY? M='EP93L-"@T*("`@(&-?8VQO8VM?9&5V:6-E*"D@.B!S=&%R=%]T:6-K*#`I M('M]#0H-"B`@("`O*G1I;65?<&]I;G1?='EP92HO('9O:60@<W1A<G0H*2`O M+R!G<',@+2!T:')O=W,@;VX@9F%I;'5R92`O+R!;25T-"B`@("T7W1I8VL@/2!S.R`O+R!G<',@ M*ST_#0H@("`@?0T*#0H-"B`@("`O+R!S:&]U;&0@=&AI<R!B92!N86UE9"!C M=7)R96YT*"D_("\O(&=P<PT*("`@('1I;65?9'5R871I;VY?='EP92!E;&%P M<V5D*"D@8V]N<W0@("`@("`@("`@("`@("\O(%M)70T*("`@('L-"B`@("`@ M("`@+R\@9W!S("AI9B!T:&ES(&ES(#P@,"!W92!S:&]U;&0@=&AR;W<I#0H@ M("`@("`@("\O(&%N9"!P<F]B86)L>2!R971U<FX@82`B;F]T(')E;&EA8FQE M(@T*("`@("`@("`O+R!I;F1I8V%T:6]N('=H96X@96QA<'-E9"`]/2`P#0H@ M("`@("`@("\O#0H@("`@("`@("\O(&%L<V\L('=I=&@@=&AE('-A;64@=&5C M;FEQ=64@=7-E9"!F;W(-"B`@("`@("`@+R\@(G-Y;F-H;VYI>F5D('-T87)T M(B!W92!C;W5L9"!M86ME(&$@<F%W#0H@("`@("`@("\O(&5S=&EM871E(&]F M('1H92!M96%S=7)E;65N="!E<G)O<@T*#0H@("`@("`@(&-O;G-T('-T9#HZ M8VQO8VM?="!E;&%P<V5D(#T@8VAE8VME9%]R971R:65V92@I("T@<W1A<G1? M=&EC:SL-"@T*("`@("`@("!R971U<FX@96QA<'-E9"`^/2`P#0H@("`@("`@ M("`@("`_('1O7W1I;65?9'5R871I;VXH96QA<'-E9"D-"B`@("`@("`@("`@ M(#H@*&1O7W1H<F]W*"DL('1I;65?9'5R871I;VY?='EP92@I*3L-"B`@("!] M#0H-"G!R:79A=&4Z#0H@("`@+R\@=V4@=7-E('-T9#HZ8VQO8VM?="!D:7)E M8W1L>2!H97)E(&%T('1H90T*("`@("\O('!R:79A=&4@;&%Y97(L('1O(&%V M;VED(&%N>2!A9&1I=&EO;F%L(&]V97)H96%D#0H@("`@+R\-"B`@("!S=&%T M:6,@<W1D.CIC;&]C:U]T(&-H96-K961?<F5T<FEE=F4H*0T*("`@('L-"B`@ M("`@("`@8V]N<W0@<W1D.CIC;&]C:U]T(&9A:6P@/2`H8VQO8VM?="DM,3L- M"@T*("`@("`@("!S=&0Z.F-L;V-K7W0@8W5R<F5N=#L-"B`@("`@("`@:68@ M*&9A:6P@(3T@*&-U<G)E;G0]<W1D.CIC;&]C:R@I*2D-"B`@("`@("`@("`@ M(')E='5R;B!C=7)R96YT.PT*("`@("`@("!E;'-E#0H@("`@("`@("`@("!D M;U]T:')O=R@I.PT*#0H@("`@("`@(')E='5R;B`P.R`O+R!G<',@<VEL96YC M92!C;VUP:6QE<B!W87)N:6YG<PT*("`@('T-"@T*("`@('-T871I8R!T:6UE M7V1U<F%T:6]N7W1Y<&4-"B`@("!T;U]T:6UE7V1U<F%T:6]N("\J('-O<G0@ M;V8@82!C<F5A=&5?=&EM92@I*B\H<W1D.CIC;&]C:U]T(&5L87!S960I#0H@ M("`@>PT*("`@("`@("`@('5S:6YG(&)O;W-T.CIP;W-I>%]T:6UE.CIS96-O M;F1S.PT*("`@("`@("`@('5S:6YG(&)O;W-T.CIP;W-I>%]T:6UE.CIM:6QL M:7-E8V]N9',[("\O(#$P=&@@;V8@<V5C;VYD<S\@+2UG<',-"@T*("`@("`@ M("`@("\O(&YO=&4@=&AA="!#3$]#2U-?4$527U-%0R!H87,@='EP92!C;&]C M:U]T+`T*("`@("`@("`@("\O('=H:6-H(&ES;B=T(&YE8V5S<V%R:6QY(&EN M=&5G<F%L#0H@("`@("`@("`@='EP961E9B!B;V]S=#HZ:6YT-C1?="!M<U]T M>7!E.R`O+R!A;GD@=V%Y('1O(&=E="!T:&5S92!T=V\-"B`@("`@("`@("`@ M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("\O('1Y<&5S(&9R;VT@ M0F]O<W0N1&%T92U4:6UE/PT*("`@("`@("`@('1Y<&5D968@;&]N9R`@("`@ M("`@("!S96-?='EP93L-"@T*("`@("`@("`@(&-O;G-T(&1O=6)L92!E(#T@ M*#$N("H@96QA<'-E9"D@+R!#3$]#2U-?4$527U-%0SL-"@T*("`@("`@("`@ M(&-O;G-T('-E8U]T>7!E('-E8R`]('-T871I8U]C87-T/'-E8U]T>7!E/BAE M*3L-"B`@("`@("`@("!C;VYS="!M<U]T>7!E("`@;7,@/2!S=&%T:6-?8V%S M=#QM<U]T>7!E/B@H92`M('-E8RD@*B`Q,#`P*3L-"@T*("`@("`@("`@(')E M='5R;B!M:6QL:7-E8V]N9',H;7,I("L@<V5C;VYD<RAS96,I.PT*("`@('T- M"@T*("`@('-T871I8R!V;VED(&1O7W1H<F]W*"D-"B`@("![#0H@("`@("`@ M(&=L;V)A;%]T:')O=U]H96QP97(H(G-T9#HZ8VQO8VL@;F]T(&%V86EL86)L M92(I.PT*("`@("`@("`O+R!G<',@8W5S=&]M(&5X8V5P=&EO;B!T>7!E/R!O M<B!P97)H87!S#0H@("`@("`@("\O($1A=&4M5&EM92!L:6)R87)Y(&%L<F5A M9'D@:&%S(&ET/PT*("`@('T-"G!R:79A=&4Z#0H@("`@+RIT:6UE7V1U<F%T M:6]N7W1Y<&4J+R!S=&0Z.F-L;V-K7W0@<W1A<G1?=&EC:SL-"GT[#0H-"@T* M+R\@+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM M+2TM+2TM+2TM+2TM+2TM+2TM+2TM#0H-"B-I;F-L=61E(#QW:6YD;W=S+F@^ M#0HC:6YC;'5D92`B8F]O<W0O8W-T9&EN="YH<'`B#0H-"F-L87-S(&=P=%]C M;&]C:U]D979I8V4@+R\@8F%S960@;VX@5VEN,S(G<R!'9710<F]C97-S5&EM M97,H*0T*>PT*<'5B;&EC.@T*("`@("\O('1Y<&5D968@=&EM95]T>7!E.CID M871E7W1Y<&4@("`@("`@("`@=&EM95]P;VEN=%]T>7!E.R`O+R!G<',@+2!N M965D960_#0H@("`@='EP961E9B!B;V]S=#HZ<&]S:7A?=&EM93HZ=&EM95]D M=7)A=&EO;B!T:6UE7V1U<F%T:6]N7W1Y<&4[#0H-"B`@("`O+R!C=&]R#0H- M"B`@("!V;VED('-T87)T*"D[("\O(&=P<R`M('1H<F]W<R!O;B!F86EL=7)E M(#\-"B`@("!T:6UE7V1U<F%T:6]N7W1Y<&4@96QA<'-E9"@I(&-O;G-T.PT* M#0IP<FEV871E.@T*#0H@("`@='EP961E9B!B;V]S=#HZ=6EN=#8T7W0@86UO M=6YT7W1Y<&4[#0H-"B`@("!S=&%T:6,@=F]I9"!R971R:65V92AA;6]U;G1? M='EP92`F(&ME<FYE;"P@86UO=6YT7W1Y<&4@)B!U<V5R*0T*("`@("`@("`O M+R!D969I;F4@(FEN;&EN92(@9F]R(&)R979I='D-"B`@("344_/R`M9W!S#0H-"B`@("`@("`@:68@*&9A M:6P@/3T@1V5T4')O8V5S<U1I;65S*$=E=$-U<G)E;G10<F]C97-S*"D-"B`@ M("`@("`@("`@("`@+"`F(&-R96%T:6]N+"`F(&5X:70-"B`@("`@("`@("`@ M("`@+"`F(')E:6YT97)P<F5T7V-A<W0\1DE,151)344F/BAK97)N96PI#0H@ M("`@("`@("`@("`@("P@)B!R96EN=&5R<')E=%]C87-T/$9)3$5424U%)CXH M=7-E<BDI#0H@("`@("`@("`@("`I#0H@("`@("`@("`@("!G;&]B86Q?=&AR M;W=?:&5L<&5R*")'9710<F]C97-S5&EM97,H*2!F86EL=7)E(BD[#0H@("`@ M?0T*#0H@("`@+RIM=71A8FQE*B\@86UO=6YT7W1Y<&4@:V5R;F5L7W1I;64[ M#0H@("`@+RIM=71A8FQE*B\@86UO=6YT7W1Y<&4@=7-E<E]T:6UE.PT*?3L- M"@T*=F]I9"!G<'1?8VQO8VM?9&5V:6-E.CIS=&%R="@I("\O('-T<F]N9RUG M=6%R86YT964-"GL-"B`@("`O+R!-:6-R;W-O9G0@9&]C<R!D;VXG="!S87D@ M=VAA="!H87!P96YS('=H96X@1V5T4')O8V5S<U1I;65S*"D-"B`@("`O+R!F M86EL<SH@:7,@:70@9W5A<F%N=&5E9"!T:&%T(&ET(&1O97,@;F]T('=R:71E M('1O(&ET<PT*("`@("\O(&]U='!U="!P87)A;65T97)S/R!4;R!A=F]I9"!I M;7!A8W1I;F<@=&AE('-T871E(&]F('1H92!T=V\-"B`@("`O+R!D871A(&UE M;6)E<G,L(&%N9"!T:'5S('!O<W-I8FQY(&QE879I;F<@=&AE(&]B:F5C="!I M;B!A;@T*("`@("\O('5N:VYO=VX@<W1A=&4L('=E('5S92!T;R!I;G1E<FUE M9&EA=&4@=F%R:6%B;&5S+B`M+6=P<PT*("`@("\O#0H@("`@86UO=6YT7W1Y M<&4@:RP@=3L-"B`@("!R971R:65V92AK+"!U*3L-"B`@("!T:&ES+3YK97)N M96Q?=&EM92`](&LL('1H:7,M/G5S97)?=&EM92`]('4[#0I]#0H-"F=P=%]C M;&]C:U]D979I8V4Z.G1I;65?9'5R871I;VY?='EP90T*9W!T7V-L;V-K7V1E M=FEC93HZ96QA<'-E9"@I(&-O;G-T#0I[#0H@("`@=7-I;F<@8F]O<W0Z.G!O M<VEX7W1I;64Z.FUI8W)O<V5C;VYD<SL-"@T*("`@(&%M;W5N=%]T>7!E(&L[ M#0H@("`@86UO=6YT7W1Y<&4@=3L-"@T*("`@(')E=')I979E*&LL('4I.PT* M("`@(`T*("`@("\O(&=P<R!I9VYO<F4@:V5R;F5L('1I;64_#0H@("`@8V]N M<W0@:6YT(&8@/2`Q,#L@+R\@8V]N=F5R<VEO;B!F86-T;W(Z(%=I;C,R('5S M97,@,3`P(&YS('1I8VMS#0H@("`@<F5T=7)N(&UI8W)O<V5C;VYD<R@H=2`M M('1H:7,M/G5S97)?=&EM92D@+R!F*0T*("`@("`@("`K(&UI8W)O<V5C;VYD F<R@H:R`M('1H:7,M/FME<FYE;%]T:6UE*2`O(&8I.PT*?0T*#0IO ` end begin 644 example.cpp M+R\@;&]W+6QE=F5L('1I;65R<R!E>&%M<&QE#0H-"@T*(VEN8VQU9&4@/&]S M=')E86T^#0HC:6YC;'5D92`\:6]S=')E86T^#0H-"B-I;F-L=61E(")B;V]S M="]D>6YA;6EC7V)I='-E="]D>6YA;6EC7V)I='-E="YH<'`B#0H-"B-I;F-L M=61E(")L;W=?;&5V96Q?=&EM97)S+FAP<"(-"B-I;F-L=61E(")B;V]S="]C M;VYF:6<N:'!P(@T*#0H-"B`@("\O(&=P<R`M('=O<G1H(&EN8VQU9&EN9R!T M:&ES/PT*("`@+R\@("`@("`@97AP;W-I;F<@<&%U<V4H*2]R97-U;64H*2!I M<R!E<G)O<BUP<F]N92!T;R!M90T*("`@('1E;7!L871E(#QT>7!E;F%M92!4 M/@T*("`@(&-L87-S('!A=7-E<B![#0H@("`@("`@(%0@)B!R968[#0H@("`@ M<'5B;&EC.@T*("`@("`@("!P875S97(H5"8@<BD@.B!R968H<BD@>R!R968N M<&%U<V4H*3L@?0T*("`@("`@("!^<&%U<V5R*"D@>R!R968N<F5S=6UE*"D[ M('T-"B`@("!].PT*#0IT96UP;&%T92`\='EP96YA;64@5&EM97(^#0IC;&%S M<R!%>&%M<&QE#0I[#0H-"B`@("!S=&%T:6,@=F]I9"!M>5]S;&5E<"AI;G0@ M;6EL;&ES96-O;F1S*0T*("`@('L-"B`@("`@("`@<W1D.CIC;W5T(#P\(")3 M;&5E<&EN9R!F;W(@(B`\/"`H;6EL;&ES96-O;F1S("\@,3`P,"XP*2`\/"`B M('-E8V]N9',N+BY<;B([#0H-"B,@("`@("`@:69D968@0D]/4U1?5TE.1$]7 M4PT*("`@("`@("!3;&5E<"AM:6QL:7-E8V]N9',I.PT*("`@("`@("`C(&5L M<V4-"B`@("`@("`@=7-L965P*&UI;&QI<V5C;VYD<R`J(#$P,#`I.PT*(R`@ M("`@("!E;F1I9@T*#0H@("`@?0T*#0H@("`@<W1A=&EC('9O:60@;W5T<'5T M7W9A;'5E*%1I;65R('0L('5N<VEG;F5D(&5X<&5C=&5D7VUI;&QI<V5C;VYD M<R`](#`I#0H@("`@>PT*("`@("`@("!P875S97(\5&EM97(^('`H="D[#0H- M"B`@("`@("`@<W1D.CIC;W5T(#P\("(M+2TM+2TM+2TM+2TM+2TM+2TM+2TM M+2TM+2TM+2TM+2TM7&XB.PT*("`@("`@("!S=&0Z.F-O=70@/#P@(D5L87!S M960Z("(@/#P@="YE;&%P<V5D*"DN<V5C;VYD<R@I#0H@("`@("`@("`@("`\ M/"`G+B<@/#P@="YE;&%P<V5D*"DN9G)A8W1I;VYA;%]S96-O;F1S*"D[#0H- M"B`@("`@("`@:68@*&5X<&5C=&5D7VUI;&QI<V5C;VYD<RD-"B`@("`@("`@ M("`@('-T9#HZ8V]U="`\/"`B("A^("(@/#P@*&5X<&5C=&5D7VUI;&QI<V5C M;VYD<R`O(#$P,#`N,"D@/#P@(B!E>'!E8W1E9"DN(CL-"@T*("`@("`@("!S M=&0Z.F-O=70@/#P@)UQN)SL-"@T*("`@('T-"@T*("`@("\O($$@<75I8VLM M86YD+61I<G1Y(&EM<&QE;65N=&%T:6]N#0H@("`@+R\@;V8@=&AE(%-I979E M(&]F($5R871O<W1H96YE<R!A;&=O#0H@("`@+R\-"B`@("!S=&%T:6,@=F]I M9"!M>5]L96YG=&AY7V9U;F-T:6]N*"D-"B`@("![#0H@("`@("`@('5S:6YG M(&)O;W-T.CID>6YA;6EC7V)I='-E=#L-"@T*("`@("`@("`O+R!C:&%N9V4@ M=&AI<R!V86QU97,@86-C;W)D:6YG('1O('EO=7(@;6%C:&EN92]E>&4@<W!E M960-"B-I9F1E9B!.1$5"54<-"B`@("`@("`@8V]N<W0@:6YT(&)I=',@/2`R M-SL-"B-E;'-E#0H@("`@("`@(&-O;G-T(&EN="!B:71S(#T@,C0[#0HC96YD M:68-"B`@("`@("`@8V]N<W0@<W1D.CIS:7IE7W0@;B`](#%U(#P\(&)I=',[ M#0H-"B`@("`@("`@9'EN86UI8U]B:71S970\/B!P<FEM97,H;B`K(#$I.PT* M("`@("`@("!P<FEM97,N9FQI<"@I.R`O+R!Y97`-"@T*("`@("`@("!P<FEM M97-;,%T@/2!P<FEM97-;,5T@/2!F86QS93L@+R\@86-T=6%L;'D@:6YD971E M<FUI;F%T90T*#0H@("`@("`@(&-O;G-T('-T9#HZ<VEZ95]T(',@/2!S=&%T M:6-?8V%S=#QS=&0Z.G-I>F5?=#XH<W1D.CIS<7)T*&X@*B`Q+C`I*3L-"@T* M("`@("`@("!F;W(H<W1D.CIS:7IE7W0@:2`](#$[(&D@/#T@<SL@*RMI*0T* M("`@("`@("`@("`@:68@*'!R:6UE<UMI72D-"B`@("`@("`@("`@("`@("!F M;W(H<W1D.CIS:7IE7W0@:B`](#(@*B!I.R!J(#P](&X[(&HK/2!I*0T*("`@ M("`@("`@("`@("`@("`@("!P<FEM97-;:ET@/2!F86QS93L-"@T*("`@("`@ M("!S=&0Z.F-O=70@/#P@)UQN)SL-"B`@("`@("`@<W1D.CIS:7IE7W0@8V]U M;G0@/2!P<FEM97,N8V]U;G0H*3L-"B`@("`@("`@<W1D.CIC;W5T(#P\(")4 M;W1A;"!P<FEM97,@:6X@6S(L("(@/#P@;@T*("`@("`@("`@("`@("`@("`@ M/#P@(ETZ("(@/#P@8V]U;G0@/#P@)UQN)SL-"B`@("`@("`@<W1D.CIC;W5T M(#P\(")2871I;SH@("`@("`@("(@/#P@8V]U;G0@+R`H,2XP*FXI(#P\("=< M;B<[#0H@("`@?0T*#0IP=6)L:6,Z#0H@("`@<W1A=&EC('9O:60@<G5N*"D- M"B`@("![#0H@("`@("`@(%1I;65R('1I;65R.PT*#0H@("`@("`@(&UY7VQE M;F=T:'E?9G5N8W1I;VXH*3L-"@T*("`@("`@("!O=71P=71?=F%L=64H=&EM M97(I.PT*("`@('T-"@T*?3L-"@T*(VEN8VQU9&4@/'=I;F1O=W,N:#X-"FEN M="!M86EN*"D-"GL-"B`@("!S=&0Z.F-L;V-K7W0@:S$@/2!S=&0Z.F-L;V-K M*"D[#0H-"B`@("`O*G-T9#HZ8V]U="`\/"`B5&5S=&EN9R!C7V-L;V-K(&1E M=FEC92XN+EQN(CL-"B`@("!%>&%M<&QE/&5L87!S961?=&EM97(\8U]C;&]C M:U]D979I8V4^(#XZ.G)U;B@I.RHO#0H@("`@<W1D.CIC;W5T(#P\(")497-T M:6YG($=E=%!R;V-E<W-4:6UE<R@I(&1E=FEC92XN+EQN(CL-"B`@("!%>&%M M<&QE/&5L87!S961?=&EM97(\9W!T7V-L;V-K7V1E=FEC93X@/CHZ<G5N*"D[ M#0H-"@T*#0H@("`@9&]U8FQE(&4@/2`H<W1D.CIC;&]C:R@I("T@:S$I("\@ M*$-,3T-+4U]015)?4T5#("H@,2XP*3L-"@T*("`@('-T9#HZ8V]U="`\/"`B M+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM+2TM7&XB.PT* M("`@('-T9#HZ8V]U="`\/"`B<W1D.CIC;&]C:R@I('1I;64Z("(@/#P@92`\ M/"`B('-E8V]N9',N7&XB.PT*("`@('-T9#HZ8V]U="`\/"`B7&YS=&0Z.F-L M;V-K*"D@<')E8VES:6]N.B`B(#P\(&-?8VQO8VM?<')E8VES:6]N*"D@/#P@ 2)UQN)SL-"@T*?0T*#0H-"@T* ` end

We don't get the file as an attachment, at least on gmail. Upload to vault. Philippe

On Sun, 16 Jul 2006 14:37:18 +0200, "Philippe Vaucher" <philippe.vaucher@gmail.com> wrote:
We don't get the file as an attachment, at least on gmail. Upload to vault.
Did I say I hate the vault? :) That's why I attached unzipped text files (zip archives don't easily go through mail firewalls). They also are in the vault now, in Home/System -- [ Gennaro Prota, C++ developer for hire ] [ resume: available on request ]

They also are in the vault now, in Home/System
Hum there's something I need to understand, what you uploaded is what needs to be merged with the code I did ? There's nice ideas in your interface which will make me modify my code so qpc_clock or tgt_clock are actually modelled like your device_clock and probably write adapters for boost::posix_time::microsec_clock etc so it can be used with teh same interface. Philippe

On Sun, 16 Jul 2006 16:41:41 +0200, "Philippe Vaucher" <philippe.vaucher@gmail.com> wrote:
They also are in the vault now, in Home/System
Hum there's something I need to understand, what you uploaded is what needs to be merged with the code I did ?
Er, no. I didn't use the word "merge" in that sense. It was meant as "we can combine the best of the two approaches" in a new design. I started working on the timers after noticing some flaws in the current boost::timer, particularly the fact that it doesn't take into account that std::clock() can fail. In the first draft of my code no boost::date_time facility was used, partly because I wanted to come up with an autonomous solution and partly because I'm a billy goat with the date-time library in general (I wanted my code to be interoperable with date-time, but not depending on it; just like you can often make a template mpl-compatible by just providing a nested "type" typedef). Well, so far with history :) The main idea in my code is that "elapsed timers" are all about *durations*, and do not need to involve *time points*. A duration is not affected by what your system time is, whether you switched to DST or things like that. That's a key point. The code I provided added the interface that Jeff Garland proposes on the wiki page to the code I had already written (secondary point: there are some comments about the interface itself in the code). Basically: * it separates the "elapsed timer" notion from the notion of "clock device" (the "source"); the advantage is that you can plug-in any source you want. The only requirement on the source class is that it provides: - a time_duration_type typedef - void start(); - time_duration_type elapsed() As you see, just a typedef and two functions. Note that the source doesn't need to know about "pauses" and "resumes"; I find that very close to the actual logic of any involved physical devices: you don't want to really pause, say, a NTP server, even if you could. Pauses, etc., are handled by the elapsed timer template class, which offers Jeff's interface. Other two ideas which are IMHO worth considering are: * [std::clock() specific ] when you first invoke std::clock() you could actually be between two ticks. Since the time between two consecutive ticks can be as long as one second or more, that's not negligible, and here's the point of the synchronized start: it waits until the clock really ticks. Secondly, elapsed_min() is actually what c_clock_precision() computes, at run-time, and cannot be inferred from CLOCKS_PER_SEC, which is a mere conversion factor (posix requires it to be fixed at 1,000,000 but that doesn't mean you can measure millionth of seconds) * use of exceptions: clock device classes, and thus elapsed_timer<T> can provide strong exception guarantees; and, yes, std::clock(), GetProcessTimes, etc. can all actually fail in practice. That should cover the basics and make the code comments more understandable. In short, we are still at the drawing board, but once the design is in place, it really takes a little time to write down the code. -- [ Gennaro Prota, C++ developer for hire ] [ resume: available on request ]

I started working on the timers after noticing some flaws in the current boost::timer, particularly the fact that it doesn't take into account that std::clock() can fail. In the first draft of my code no boost::date_time facility was used, partly because I wanted to come up with an autonomous solution and partly because I'm a billy goat with the date-time library in general (I wanted my code to be interoperable with date-time, but not depending on it; just like you can often make a template mpl-compatible by just providing a nested "type" typedef).
What I don't understand is why you didn't talk earlier in this thread ? You seem to have missed a lot of discussion where your input would have been interesting. * it separates the "elapsed timer" notion from the notion of "clock
device" (the "source"); the advantage is that you can plug-in any source you want.The only requirement on the source class is that it provides:
- a time_duration_type typedef - void start(); - time_duration_type elapsed()
It's basically the same design than Jeff proposed (about it being templated on the clock) except it's not tied to the boost::date_time interface which makes it suitable for timers like QueryPerformanceCounter, that's why I think I'll refactor it a bit to follow your design so we can have one generic template class instead of template specializations. That should cover the basics and make the code comments more
understandable. In short, we are still at the drawing board, but once the design is in place, it really takes a little time to write down the code.
Right so you are actually proposing whole new round of discussions... ok, I thought we had this behind :) I'm not used to the boost mailing list enough I guess. Philippe

On Sun, 16 Jul 2006 23:09:29 +0200, "Philippe Vaucher" <philippe.vaucher@gmail.com> wrote:
What I don't understand is why you didn't talk earlier in this thread ? You seem to have missed a lot of discussion where your input would have been interesting.
I haven't followed this thread closely. But precisely where I should have spoken?
* it separates the "elapsed timer" notion from the notion of "clock
device" (the "source"); the advantage is that you can plug-in any source you want.The only requirement on the source class is that it provides:
- a time_duration_type typedef - void start(); - time_duration_type elapsed()
It's basically the same design than Jeff proposed (about it being templated on the clock) except it's not tied to the boost::date_time interface
I don't know. What I noticed in your code is that you have to call clock_type::local_time() in some places. And I didn't think this was the case when seeing the interface specification. That's certainly due to my ignorance on boost::date_time; but, admittedly, you don't need any time point from a logical point of view (or you can go with an irrelevant "instant zero" time point reference which doesn't affect results).
which makes it suitable for timers like QueryPerformanceCounter, that's why I think I'll refactor it a bit to follow your design so we can have one generic template class instead of template specializations.
BTW, those were partial template specializations, which rule out VC6 and other compilers.
That should cover the basics and make the code comments more
understandable. In short, we are still at the drawing board, but once the design is in place, it really takes a little time to write down the code.
Right so you are actually proposing whole new round of discussions... ok, I thought we had this behind :) I'm not used to the boost mailing list enough I guess.
Sorry, but, if that may comfort you, it's a good thing. The more it will be at the drawing board, the less in the debugger and in the feature request list ;) PS: I'm also experimenting a bit in assembly with time stamp counters; I've tried them on an Intel P4 and the results are impressive. The way to insert assembly code vary with the compiler but that can be easily be managed. Probably other CPU brands could be supported. For now I haven't considered AMDs (the Intel documentation is quite long already :) But it's a joy to read) and SMP systems. Furthermore, cache misses during frequency measurements are taken into account, but dynamic frequency adjustments, such as performed via SpeedStep, are not. But it's just a first cut. And then, I don't think one would want to use these facilities with SpeedStep in the way. -- [ Gennaro Prota, C++ developer for hire ] [ resume: available on request ]

frequency adjustments, such as performed via SpeedStep, are not. But it's just a first cut. And then, I don't think one would want to use these facilities with SpeedStep in the way.
I think it should at least detect SpeedStep and fail or fall back to a possibly lower precision but stable timer. IMO without this its unusable except for very basic performance tests. my 2c Martin -- No virus found in this outgoing message. Checked by AVG Free Edition. Version: 7.1.394 / Virus Database: 268.10.1/389 - Release Date: 14/07/2006

On Mon, 17 Jul 2006 13:08:28 +1000, Martin Slater <mslater@hellinc.net> wrote:
frequency adjustments, such as performed via SpeedStep, are not. But it's just a first cut. And then, I don't think one would want to use these facilities with SpeedStep in the way.
I think it should at least detect SpeedStep and fail or fall back to a possibly lower precision but stable timer. IMO without this its unusable except for very basic performance tests.
Actually there are some usages where one wants the cycle count, rather than the elapsed time, so I was thinking to provide a cpu_cycle_timer (that's not a "timer" in the strict sense but seems to fit in the framework) anyway. Of course the elapsed time is just the cycle count divided by the frequency, if the frequency is fixed. I'll see in the Intel docs if it is possible to detect SpeedStep activation (you won't believe what the processor is actually able to tell you :)) or if other solutions exist. -- [ Gennaro Prota, C++ developer for hire ] [ resume: available on request ]

Actually there are some usages where one wants the cycle count, rather than the elapsed time, so I was thinking to provide a cpu_cycle_timer (that's not a "timer" in the strict sense but seems to fit in the framework) anyway. Of course the elapsed time is just the cycle count divided by the frequency, if the frequency is fixed. I'll see in the
Yep sounds good, for profiling real small functions you really dont want to lose the precision by dividing in the frequency.
Intel docs if it is possible to detect SpeedStep activation (you won't believe what the processor is actually able to tell you :)) or if other solutions exist.
I hope your successful ;) A good guide to pc timers you may not have seen is here http://www.mindcontrol.org/~hplus/pc-timers.html which has some good ideas for a stable timer on windows x86 hth Martin -- No virus found in this outgoing message. Checked by AVG Free Edition. Version: 7.1.394 / Virus Database: 268.10.1/390 - Release Date: 17/07/2006

On Tue, 18 Jul 2006 23:54:11 +1000, Martin Slater <mslater@hellinc.net> wrote:
[I'll see in the]
Intel docs if it is possible to detect SpeedStep activation (you won't believe what the processor is actually able to tell you :)) or if other solutions exist.
I hope your successful ;)
Thanks. It's actually not difficult, and fascinating, so I'm well willing to do it. I just hope there's no drop of interest here, as that will likely make me move on to something else.
A good guide to pc timers you may not have seen is here http://www.mindcontrol.org/~hplus/pc-timers.html which has some good ideas for a stable timer on windows x86
Thanks, I'll have a look later. I've to say the Bible is quite good too (I mean the Intel document :)). Basically the processor does everything for you, you just need to ask and take some extra care for cache misses and other issues. The basic idea (sorry for any typos) is: __forceinline __int64 cpu_cycle_count() { __int64 prelim; __int64 actual; // pentium or above required asm { cpuid rdtsc lea ebx,prelim mov [ebx],eax mov [ebx+4],edx <repeat the above a few times...> cpuid rdtsc lea ebx,actual mov [ebx],eax mov [ebx+4],edx } // basic cache miss protection, but // something better can be done return prelim < actual? prelim : actual; } -- [ Gennaro Prota, C++ developer for hire ] [ resume: available on request ]

Hi there, Here attached is a small example of the new design the timer library is more or less likely to follow, however while doing it it raised a number of concern to me : About the device class, the original drafts says it contains only two member functions, start() and elapsed(). I think it lacks obvious others like reset(), or something that tells it to stop and start again. Should the device be allowed to start with an duration offset ? Should it be allowed to be started automatically ? Why doesn't boost::date_time::microsec_clock and similar class typedef the time_type ? Because of this I'm forced to do a ptime_device when I could have done a date_time_device. I'm able to get around this but I think it'd require partial template specialization or worse two device classes for things that have the same interface. I think we'd agree on the device class member functions first, and once done we can then move on about how the timer class member functions should be :) Philippe

I think it should at least detect SpeedStep and fail or fall back to a possibly lower precision but stable timer. IMO without this its unusable except for very basic performance tests.
How many are affected by Speedstepping exactly ? Isn't that only for laptops ? Doesn't mean we shouldn't take care of it, but I'd like to know the practical implications :) Philippe

How many are affected by Speedstepping exactly ? Isn't that only for laptops ? Doesn't mean we shouldn't take care of it, but I'd like to know the practical implications :)
A practical implications is that a customer runs your app on a computer with speedstep processor and all of a sudden it completely fails to work correctly. I've been bitten hard by this kind of thing in the past and it hurts;) cheers Martin -- No virus found in this outgoing message. Checked by AVG Free Edition. Version: 7.1.394 / Virus Database: 268.10.1/390 - Release Date: 17/07/2006

What I don't understand is why you didn't talk earlier in this thread ? You seem to have missed a lot of discussion where your input would have been interesting.
I haven't followed this thread closely. But precisely where I should have spoken?
Hum, where we spoke about the available timers on windows (QueryPerformanceCounter, etc) where no one mentionned GetProcessTimes or when we spoke about the design problem of timers that aren't based on time, but nevermind :) What counts is that I now can modify my code with a better design. I'll post code change in some days. Philippe

On Mon, 17 Jul 2006 10:16:32 +0200, "Philippe Vaucher" <philippe.vaucher@gmail.com> wrote:
What counts is that I now can modify my code with a better design.
Glad to hear that.
I'll post code change in some days.
I'd also like you and other participants to try answering to points marked with "gps" in the source code. -- [ Gennaro Prota, C++ developer for hire ] [ resume: available on request ]

I'd also like you and other participants to try answering to points marked with "gps" in the source code.
------------------------------------------------------------------------------ // gps - temporary helper void global_throw_helper(const char* msg) { throw std::runtime_error(msg); } We'd just use boost::throw_exception here. ------------------------------------------------------------------------------ template <typename T> struct clock_device_traits { // gps TODO //has_synch_start? }; I think maybe we'd have a clock_device_base that is inherited by every clock_devices, that would be templated on the time type and typedefs time_duration_type, so the elapsed timer that accepts a clock_device can also typedef those. ------------------------------------------------------------------------------ // gps - do we need these two typedefs? // typedef TimePoint time_type; // typedef typename Device::time_point_type time_point_type; I think it's convenient, I even propose we do : typedef ClockDevice clock_type; typedef typename ClockDevice::time_type time_type; typedef typename time_type::time_duration_type time_duration_type; So the user can know the clock_type for when he uses a convenience typedef like "typedef timer<microsec_device> microsec_timer;" which is likely to be declared in the library. ------------------------------------------------------------------------------ void resume(); // gps - what if you call twice pause, twice resume consecutively?? // bool is_running() const // gps - add this?? // gps: I see no point in having clear_elapsed() I think calling twice pause or resume should have no effect. Not doing so is too error prone imho. is_running() sounds like good idea tho I can't really think of a use for it so maybe not if that means having to add a data member to implement it. I think reset() was good, why don't you see a point for it ? If you want to time two consequent things individually and use the same object ? ------------------------------------------------------------------------------ template <typename D> void elapsed_timer<D>::start() // may throw { restart(); // this is just the same as restart(); // maybe we can come up with a common name -gps } I think calling start() twice should not reset it, I think restart should call reset() then start(). ------------------------------------------------------------------------------ template <typename D> void elapsed_timer<D>::pause() { // throw if(!is_running) ?? - gps duration += device.elapsed(); is_running = false; } Again, I think pause should pause if not already paused, otherwise do nothing, like the implementation I uploaded based on Jeff's design. ------------------------------------------------------------------------------ // Specific Clock Devices // gps - should this be copyable? Why not ? Anyway, I'll skip the other points as it's more implementation detail it seems, but I'll explain more how I think the timer should behave : - Calling start() should start if not already started, subsequents calls to start() do nothing. - Calling pause() should pause if not already paused, subsequents calls to pause() do nothing. - Calling resume() should start the timer again at the time duration the timer was if not already start, subsequents calls to resume() do nothing. - Calling reset() should reset the current elapsed time to 0. - Calling restart() should call reset() then start(). - Calling elapsed() should return the current timer value. I also think your interface lacks the hability to set the initial time offset, which could be usefull in some situations. Ok, it's a start ! I'll see if I can comment on the other gps points in a near future. Philippe

On Tue, 18 Jul 2006 12:10:56 +0200, "Philippe Vaucher" <philippe.vaucher@gmail.com> wrote:
I'd also like you and other participants to try answering to points marked with "gps" in the source code.
------------------------------------------------------------------------------ // gps - temporary helper void global_throw_helper(const char* msg) { throw std::runtime_error(msg); }
We'd just use boost::throw_exception here.
I'm afraid I didn't make my point clear. It wasn't about supporting BOOST_NO_EXCEPTIONS (which I'd like not to --it would require in any case a re-examination of the code, as I didn't design it with that in mind). It was to discuss what type of exception(s) we want to throw and what additional info, if any, we want to add to exception objects. Maybe Boost.Date-Time already has a well thought-out solution.
------------------------------------------------------------------------------ template <typename T> struct clock_device_traits { // gps TODO //has_synch_start? };
I think maybe we'd have a clock_device_base that is inherited by every clock_devices, that would be templated on the time type and typedefs time_duration_type, so the elapsed timer that accepts a clock_device can also typedef those.
------------------------------------------------------------------------------ // gps - do we need these two typedefs? // typedef TimePoint time_type; // typedef typename Device::time_point_type time_point_type;
I think it's convenient, I even propose we do :
typedef ClockDevice clock_type; typedef typename ClockDevice::time_type time_type; typedef typename time_type::time_duration_type time_duration_type;
So the user can know the clock_type for when he uses a convenience typedef like "typedef timer<microsec_device> microsec_timer;" which is likely to be declared in the library.
I'm not sure we are understanding each other. The main advantage of my solution is that it doesn't logically imply/require any usage of a "time point". That means: if you measure while someone (or some program/service) adjusts the system clock, or a DST switch happens, you are *not* affected. Example: you begin measuring at 2am of your local time, in the day when DST is switched off. Your test takes 1h 30m. With your calculation you get: start = 2am, elapsed = 0 end = *2:30am*, elapsed = 30 min Your approach would work if date_time offered a concept of time-zero point: a special time point value which would only be used to calculate differences, so to elide it automatically: (stop-t0) - (start - t0) = stop-start Such a value could be used as implementation detail. But frankly I don't see a reason for it from a logical point of view. We only care about durations and durations are addable; that's all we need.
------------------------------------------------------------------------------ void resume(); // gps - what if you call twice pause, twice resume consecutively?? // bool is_running() const // gps - add this?? // gps: I see no point in having clear_elapsed()
I think calling twice pause or resume should have no effect.
Maybe.
Not doing so is too error prone imho. is_running() sounds like good idea tho I can't really think of a use for it so maybe not if that means having to add a data member to implement it.
Basically you are saying you are in doubt. I was too, hence my question (incidentally: what's your concern with an additional data member??).
I think reset() was good, why don't you see a point for it ? If you want to time two consequent things individually and use the same object ?
restart()?
------------------------------------------------------------------------------ template <typename D> void elapsed_timer<D>::start() // may throw { restart(); // this is just the same as restart(); // maybe we can come up with a common name -gps }
I think calling start() twice should not reset it, I think restart should call reset() then start().
Honestly, did you really look at my code? Looks like you keep thinking in terms of yours. I had no concept of reset() at all.
------------------------------------------------------------------------------ template <typename D> void elapsed_timer<D>::pause() { // throw if(!is_running) ?? - gps duration += device.elapsed(); is_running = false; }
Again, I think pause should pause if not already paused, otherwise do nothing, like the implementation I uploaded based on Jeff's design.
I see. But the point is: if the user code happens to call pause() twice without intervening restarts, is that a sign of a logical error? It's similar to set a pointer to null after a delete, to ensure a double deletion is harmless. It may make you feel safer, but in practice it hides programming errors by eating their immediate ill effects. I may see a use for is_running at least in debug mode here.
------------------------------------------------------------------------------ // Specific Clock Devices // gps - should this be copyable?
Why not ?
It's a choice, and I annotated it to make sure I gave it another thought at the end of the work.
Anyway, I'll skip the other points as it's more implementation detail it seems, but I'll explain more how I think the timer should behave :
- Calling start() should start if not already started, subsequents calls to start() do nothing.
Same comment as above.
- Calling pause() should pause if not already paused, subsequents calls to pause() do nothing.
Again.
[...]
I also think your interface lacks the hability to set the initial time offset, which could be usefull in some situations.
Care to explain?
Ok, it's a start !
Yes, thanks. At least it should clear some manifest misunderstanding. -- [ Gennaro Prota, C++ developer for hire ] [ resume: available on request ]

I'm afraid I didn't make my point clear. It wasn't about supporting BOOST_NO_EXCEPTIONS (which I'd like not to --it would require in any case a re-examination of the code, as I didn't design it with that in mind). It was to discuss what type of exception(s) we want to throw and what additional info, if any, we want to add to exception objects. Maybe Boost.Date-Time already has a well thought-out solution.
Then I have no clue for this :) I'm not sure we are understanding each other. The main advantage of my
solution is that it doesn't logically imply/require any usage of a "time point". That means: if you measure while someone (or some program/service) adjusts the system clock, or a DST switch happens, you are *not* affected.
We are, it's just I copy pasted too much for my example. My point was mostly for the clock_device and the time_duration_type that should be able as typedefs.
------------------------------------------------------------------------------
void resume(); // gps - what if you call twice pause, twice resume consecutively?? // bool is_running() const // gps - add this?? // gps: I see no point in having clear_elapsed()
I think calling twice pause or resume should have no effect.
Maybe.
It's not a media player where the interface tries to be friendly and pressing pause toggles play/pause, it's a timer where pause means pause no ?
Not doing so is
too error prone imho. is_running() sounds like good idea tho I can't really think of a use for it so maybe not if that means having to add a data member to implement it.
Basically you are saying you are in doubt. I was too, hence my question (incidentally: what's your concern with an additional data member??).
I'm just explaining why it's a doubt yes. The concern about an additional data member is silly but it's something about if the feature is never used and the object gets bigger then it's just lose-lose. But after more thinking is_running also helps the implementation clarity so I think we'd add it.
I think reset() was good, why don't you see a point for it ? If you want to
time two consequent things individually and use the same object ?
restart()?
Restarts resets and starts again, it's two actions. You don't provide the 1st one.
------------------------------------------------------------------------------
template <typename D> void elapsed_timer<D>::start() // may throw { restart(); // this is just the same as restart(); // maybe we can come up with a common name -gps }
I think calling start() twice should not reset it, I think restart should call reset() then start().
Honestly, did you really look at my code? Looks like you keep thinking in terms of yours. I had no concept of reset() at all.
Maybe I wasn't clear: I said your interface lacks the reset() concept, and that restart() should be reset() then start().
Again, I think pause should pause if not already paused, otherwise do
nothing, like the implementation I uploaded based on Jeff's design.
I see. But the point is: if the user code happens to call pause() twice without intervening restarts, is that a sign of a logical error? It's similar to set a pointer to null after a delete, to ensure a double deletion is harmless. It may make you feel safer, but in practice it hides programming errors by eating their immediate ill effects.
For me it's not an error. If the user wants to do cout.set_precision(23); cout.set_precision(23); it's his problem :) What we could do is return a bool that'd tell pause() success tho.
------------------------------------------------------------------------------
// Specific Clock Devices // gps - should this be copyable?
Why not ?
It's a choice, and I annotated it to make sure I gave it another thought at the end of the work.
It's usually a choice driven by the fact that copying it might be harfmul or imply extra design decisions (resources etc) but here I don't see why it wouldn't be.
I also think your interface lacks the hability to set the initial time
offset, which could be usefull in some situations.
Care to explain?
For the "I want to create a timer that starts with 100 second elapsed already" kindof requests. Philippe

We are, it's just I copy pasted too much for my example. My point was mostly for the clock_device and the time_duration_type that should be able as typedefs.
s/able/available/ My point was it's likely there'll be convenience typedefs for the timers and if you want to know what clock_device was used from user code you'd be able to. Philippe
participants (17)
-
Andy Little
-
Beman Dawes
-
Brannon King
-
Carlo Wood
-
Gennaro Prota
-
Gerhard Wesp
-
Jeff Garland
-
Johan Nilsson
-
John Maddock
-
Martin Slater
-
Matias Capeletto
-
Michael Fawcett
-
Pavel Vozenilek
-
Peter Dimov
-
Philippe Vaucher
-
Roland Schwarz
-
Silex