Proposed boost timers library implementation concerns.

I have a few concerns at this point on the implementation of the proposed timers library. boost/timers.hpp assumes if you are not on windows you are on a posix system. I'm porting to a different platform which is neither windows nor posix compatible. WIN32_LEAN_AND_MEAN is defined in the windows device headers and then windows.h is included. This could lead to issues where depending on order of inclusion in a project WIN32_LEAN_AND_MEAN could be either defined or undefined when windows.h is included (and this is certainly imposing that define on the user). Include guards in all files begin with the reserved underscore capital letter combination. timeGetTime.hpp links against the winmm.lib and is included through a simple #include <boost/timers.hpp> even though I'm not planning to use the timeGetTime timer. Might not be a huge deal... I'll probably just have to avoid the convenience header and do preprocessor platform switching in my own application. I don't find the everything and the kitchen sink convenience header to be very useful for this library. Perhaps providing other convenience headers and typedefs for platform independent timers like for instance hires_timer, general_purpose_timer, or slow_polling_timer would be useful so ugly preprocessor switching logic can be kept out of user applications. Thanks, Michael Marcin

Michael Marcin wrote:
I have a few concerns at this point on the implementation of the proposed timers library.
boost/timers.hpp assumes if you are not on windows you are on a posix system. I'm porting to a different platform which is neither windows nor posix compatible.
WIN32_LEAN_AND_MEAN is defined in the windows device headers and then windows.h is included. This could lead to issues where depending on order of inclusion in a project WIN32_LEAN_AND_MEAN could be either defined or undefined when windows.h is included (and this is certainly imposing that define on the user).
Further more AFAICT WIN32_LEAN_AND_MEAN removes the timeGetTime function declaration. Also the QueryPerformanceCounter device uses millisecond resolution internally. I've adjusted it for microsecond resolution locally. The qpc_device also does not address http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323& but maybe this is asking too much? Thanks, Michael Marcin

Further more AFAICT WIN32_LEAN_AND_MEAN removes the timeGetTime function declaration.
I'll check it. Also the QueryPerformanceCounter device uses millisecond resolution
internally. I've adjusted it for microsecond resolution locally.
Hum I didn't understand what you meant by that. The qpc_device also does not address
http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323& but maybe this is asking too much?
I don't know... the resolution would be : " Programs should watch for an unexpected jump by comparing the change in time as determined by successive calls to *QueryPerformanceCounter* with the change in time as determined by successive calls to the *GetTickCount*function. If there is a significant jump that is based on *QueryPerformanceCounter*(), but no similar increase that is based on * GetTickCount*, then it can be assumed that the performance counter just jumped forward. The code sample at the end of this article demonstrates how to do this." It looks a bit overkill because when you use QPC you usually want high precision... all those other calls would be a pretty huge overhead not to mention that without threading we'd require the user to type tmr.update() periodically. I suggest we let the user find the appropriate fix, but I'll add this issue in the documentation. Thanks again. Philippe

It looks a bit overkill because when you use QPC you usually want high precision... all those other calls would be a pretty huge overhead not to mention that without threading we'd require the user to type tmr.update() periodically. I suggest we let the user find the appropriate fix, but I'll add this issue in the documentation.
Actually I realised I could simply check that the values are correct by checking with GetTickCount() each time I call QueryPerformanceCounter()... now the question is what would happen... should I throw an exception ? unlikely... should I set some flag to LEAP_DETECTED ? should I just take GetTickCount()'s time silently ? Philippe

Doh! I realize now I was working from an older version of the library (I was working with http://www.unitedsoft.ch/boost/boost_timer_2007_30_4.tgz Now I'm working with http://unitedsoft.ch/boost/boost_timer_2007_05_01.zip Is this still the latest? I see the timeGetTime implementation has been improved with timeBeginPeriod and timeEndPeriod. And I see that best_timer had been added which is in line with my previous requests. Thanks. The header for gpt_device has a small documentation bug. //! The gtt_device class is based on GetThreadTimes() to compute the time class gpt_device Philippe Vaucher wrote:
Also the QueryPerformanceCounter device uses millisecond resolution internally. I've adjusted it for microsecond resolution locally.
Hum I didn't understand what you meant by that.
Sorry I'll be more specific. QueryPerformanceCounter has around 10 microsecond accuracy on most systems IIRC. I'm personally using it to time code where the total code must take less than 23 ms so to narrow things down it helps to have microsecond resolution. The qpc_device currently does m_frequency.QuadPart /= 1000 in its constructor and adds to elapsed by doing: m_elapsed += posix_time::milliseconds(milliseconds); I changed it to do m_frequency.QuadPart /= 1000000 in its constructor and add to elapsed by doing: m_elapsed += posix_time::microseconds(microseconds); In terms of what to do when QueryPerformanceCounter leaps I would probably use the GetTickCount value silently so the class just works (tm). I'd probably edit the file locally to assert in debug in that case just for personal curiosity. There was one more problem with QueryPerformanceCounter on some laptops including my old one. When the cpu lowered its clock speed to save battery power the frequency of the timer changed despite the documentation for QueryPerformanceFrequency explicitly saying the frequency cannot change while the system is running. I don't have the laptop anymore so I doubt we'll be able to make and test a fix. Hopefully this isn't common. Thanks, Michael Marcin

I changed it to do m_frequency.QuadPart /= 1000000 in its constructor and add to elapsed by doing: m_elapsed += posix_time::microseconds(microseconds);
Sounds fair enough, I'll do the same. In terms of what to do when QueryPerformanceCounter leaps I would
probably use the GetTickCount value silently so the class just works (tm). I'd probably edit the file locally to assert in debug in that case just for personal curiosity.
I'll probably do some kind of macro enabling this behavior, like QPC_SET_AFFINITY which solves the multicore problem. There was one more problem with QueryPerformanceCounter on some laptops
including my old one. When the cpu lowered its clock speed to save battery power the frequency of the timer changed despite the documentation for QueryPerformanceFrequency explicitly saying the frequency cannot change while the system is running. I don't have the laptop anymore so I doubt we'll be able to make and test a fix. Hopefully this isn't common.
Unfortunately I don't see a fix for the speedsteping problem... I think we can only document it. About the next versions, I always do a message on the mailing list and I post it there http://www.unitedsoft.ch/boost/, sometimes I also upload it to the vault... Cheers for your insights. Btw as you seem to work on non-posix and non-windows system, can you tell me what timeing API there is on those platforms ? Would it make sense to add a "others" namespace where non-posix and non-win devices would be ? Philippe

Philippe Vaucher wrote:
Cheers for your insights. Btw as you seem to work on non-posix and non-windows system, can you tell me what timeing API there is on those platforms ? Would it make sense to add a "others" namespace where non-posix and non-win devices would be ?
I don't think it's necessary. If new platforms are supported such as BREW or Symbian they probably deserve their own folders rather than being lumped into other since they cannot use each other's timing devices but they each have several devices. Personally all I would do is change the "timers_local_include.hpp" to <boost/timers/local_include.hpp> (I've done this locally as well). Then I have a shadow copy of the boost directory in my include path before the clean copy of boost. mini-boost/clean/boost then mini-boost/{platform}/boost This allows me to add files and folders and override behavior without confusing my changes with the original code. If boost ever wants to officially support Windows Mobile, Symbian, BREW, etc. then I'll have to rethink how to merge my changes into the mainline. P.S. What are the requirements on devices? Do they need to be copyable? Do they need to start stopped? Do they need to be cheap to pass-by-value? etc. P.P.S. Interestingly a typo in my code led me to a timer that used another timer as its device... funny that timer appears to satisfy the requirements of the TimingDevice concept. Thanks, Michael Marcin

Perhaps this is out-of-scope with respect to the design goals of this class but its useful to have timing that is synchronized across multiple systems. This is essential for doing things like latency testing as well as for many real-time applications. The typical approach is to use a GPS time signal and an interface board in each system. This results in system-to-system timing offsets of 10-20 uSec out-of-the-box. An a lot better with a bit of tuning. The interface to these timing boards is typically via a vendor supplied driver so it would be nice if there was a spot in the timing class where an adapter could be written to handle special cases like this. Glenn Schrader - MIT Lincoln Lab Michael Marcin wrote:
Philippe Vaucher wrote:
Cheers for your insights. Btw as you seem to work on non-posix and non-windows system, can you tell me what timeing API there is on those platforms ? Would it make sense to add a "others" namespace where non-posix and non-win devices would be ?
I don't think it's necessary. If new platforms are supported such as BREW or Symbian they probably deserve their own folders rather than being lumped into other since they cannot use each other's timing devices but they each have several devices.
Personally all I would do is change the "timers_local_include.hpp" to <boost/timers/local_include.hpp> (I've done this locally as well).
Then I have a shadow copy of the boost directory in my include path before the clean copy of boost.
mini-boost/clean/boost
then
mini-boost/{platform}/boost
This allows me to add files and folders and override behavior without confusing my changes with the original code.
If boost ever wants to officially support Windows Mobile, Symbian, BREW, etc. then I'll have to rethink how to merge my changes into the mainline.
P.S.
What are the requirements on devices? Do they need to be copyable? Do they need to start stopped? Do they need to be cheap to pass-by-value? etc.
P.P.S.
Interestingly a typo in my code led me to a timer that used another timer as its device... funny that timer appears to satisfy the requirements of the TimingDevice concept.
Thanks,
Michael Marcin
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

class but its useful to have timing that is synchronized across multiple
systems. This is essential for doing things like latency testing as well as for many real-time applications. The typical approach is to use a GPS time signal and an interface board in each system. This results in system-to-system timing offsets of 10-20 uSec out-of-the-box. An a lot better with a bit of tuning. The interface to these timing boards is typically via a vendor supplied driver so it would be nice if there was a spot in the timing class where an adapter could be written to handle special cases like this.
It's interesting but shouldn't be addressed by things like boost::ipc or boost::channel (which could use boost::timers for the implementation) ? Philippe

Philippe Vaucher wrote:
class but its useful to have timing that is synchronized across multiple
systems. This is essential for doing things like latency testing as well as for many real-time applications. The typical approach is to use a GPS time signal and an interface board in each system. This results in system-to-system timing offsets of 10-20 uSec out-of-the-box. An a lot better with a bit of tuning. The interface to these timing boards is typically via a vendor supplied driver so it would be nice if there was a spot in the timing class where an adapter could be written to handle special cases like this.
It's interesting but shouldn't be addressed by things like boost::ipc or boost::channel (which could use boost::timers for the implementation) ?
Not really. The fundamental problem that neither of these can address is how to obtain time values that are synchronous across different machines on a network. IPC just communicates between processes or threads on the same machine so they are by definition using the same clock hardware and can get accurate relative timings. IPC works fine for a single machine but doesn't extend to multiple machines. The problem with boost::channel is that even though messages can be sent between machines they can't be used to accurately synchronize the clocks since their latency is both unknown and varies with network load. Its better to get the time values from clocks that have hardware allowing them synchronize to a common super-accurate time reference. It would just be nice if boost::timers could use such clocks if they are available. Glenn Schrader - MIT Lincoln Lab

Personally all I would do is change the "timers_local_include.hpp" to <boost/timers/local_include.hpp> (I've done this locally as well).
I'm not quite usre what you meant by that... I don't have an header named "timers_local_include.hpp" at the moment... I guess you mean use <> inclusion rather than "" inclusion, and yes I agree with that. As at the moment the library is more to be used for testing I made it so you don't need to put in in /boost for it to work. What are the requirements on devices? Do they need to be copyable? Do
they need to start stopped? Do they need to be cheap to pass-by-value? etc.
That's something to be defined... There are other questions like should be able to change the timeing device at runtime ? At the moment I focus my efforts on collecting informations the available apis so I know about their portability and I'm writing tests so I can measure their overhead & resolution and categorize them... but it's quite more work than I expected :) Interestingly a typo in my code led me to a timer that used another
timer as its device... funny that timer appears to satisfy the requirements of the TimingDevice concept.
Hehe interesting, there are still open questions about what exactly a timeing device should be (what members it'd provide, what support it'd offer etc). At the moment I'm a bit working too much and I barely have time to work on the library which is a shame. I expect to have more free time in august and I hope I'd be able to submit it around september for a review. Thank you for your input it's really appreciated. Philippe

boost/timers.hpp assumes if you are not on windows you are on a posix system. I'm porting to a different platform which is neither windows nor posix compatible.
Well what's in the vault is more a draft than anything finished. What's planed is having a tons of boost::config macros in order to have better control of the whole thing... like ability to simulate windows 95 mode even on a windows XP or stuffs like that. Another idea could be to provide a set of tags representing the apis and their properties and then some kind of mpl-get_timer() function where you'd pass the wanted properties and it's return the best one available. Tho it looks a bit like overengineering. WIN32_LEAN_AND_MEAN is defined in the windows device headers and then
windows.h is included. This could lead to issues where depending on order of inclusion in a project WIN32_LEAN_AND_MEAN could be either defined or undefined when windows.h is included (and this is certainly imposing that define on the user).
Oh good point I'll add checks and undefine it after the header if it wasn't defined. Include guards in all files begin with the reserved underscore capital
letter combination.
I thought underscores were reserved for compiler implementers & libraries writers ? timeGetTime.hpp links against the winmm.lib and is included through a
simple #include <boost/timers.hpp> even though I'm not planning to use the timeGetTime timer. Might not be a huge deal... I'll probably just have to avoid the convenience header and do preprocessor platform switching in my own application.
Well that was to follow the dynamic linking already present in other boost libraries but I'll look if I can kind of make it happen only when you do use the tgt_timer. I don't find the everything and the kitchen sink convenience header to
be very useful for this library. Perhaps providing other convenience headers and typedefs for platform independent timers like for instance hires_timer, general_purpose_timer, or slow_polling_timer would be useful so ugly preprocessor switching logic can be kept out of user applications.
Yeah that's planned as well, make typedefs based on timers usage. Thank you for your input! Philippe
participants (3)
-
Glenn Schrader
-
Michael Marcin
-
Philippe Vaucher