date_time microsec_clock::univeral_time() implementation

We have an application that was using our own custom functions for getting the OS time. We were basically representing time as the number of milliseconds since the UNIX epoch in an unsigned long, or as the number of nanoseconds since the epoch in a 64-bit type. We later discovered boost, and cut everything over to boost::date_time. This has worked out very, very well and has uncovered several time related bugs in our old code. However, we do have a small percentage of code that is time critical, and we have noticed that calling microsec_clock::univeral_time() is 2.6 times slower than our old function, and for this one bit of code that is significant. Looking at the implementation for UNIX like systems, I see that create_time() in microsec_time_clock.hpp is calling gettimeofday() followed by a call to gmtime() or localtime() as appropriate. I think it's this second call that is the difference between our old code and boost. In our time critical chunk of code we are just time tagging events, and we aren't concerned about timezone. I was thinking about adding a function to our code that called clock_gettime() (which is what our old code did), but then constructing a time_type out of that using the UNIX epoch for the date part and the results of clock_gettime() for the time_duration part, i.e, in pseudo code: time_type our_get_time() { clock_gettime(CLOCK_REALTIME, ×pec); time_duration td = massage(timespec); return time_type(unix_epoch, td); } This still won't be as fast as our old code, because we essentially ignored the date part of the times and simply worked with durations since the epoch. But I think the killer for us is the call to gmtime, which the above avoids. Comments? I'm curious why this approach wasn't taken in boost. Was it the timezone factor? I'm also curious why gettimeofday() was chosen over clock_gettime()? Is one more available than the other? Thanks.

I wrote:
I was thinking about adding a function to our code that called clock_gettime() (which is what our old code did), but then constructing a time_type out of that using the UNIX epoch for the date part and the results of clock_gettime() for the time_duration part, i.e, in pseudo code:
time_type our_get_time() { clock_gettime(CLOCK_REALTIME, ×pec); time_duration td = massage(timespec); return time_type(unix_epoch, td); }
I ended up doing something like this: struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); time_duration td(seconds(ts.tv_sec) + nanoseconds(ts.tv_nsec)); return ptime(epochDate, td); where: const date epochDate(1970, Jan, 1); Wow...this turns out to be much, much slower, like 1000x slower, than calling gettimeofday() followed by gmtime()......! I guess it must be all the calculations involved to normalize the very large seconds value offset from 1970 into a ptime. Hmmm...back to the drawing board.

Brian Neal wrote:
We have an application that was using our own custom functions for getting the OS time. We were basically representing time as the number of milliseconds since the UNIX epoch in an unsigned long, or as the number of nanoseconds since the epoch in a 64-bit type.
We later discovered boost, and cut everything over to boost::date_time. This has worked out very, very well and has uncovered several time related bugs in our old code.
Glad it was helpful :-)
However, we do have a small percentage of code that is time critical, and we have noticed that calling microsec_clock::univeral_time() is 2.6 times slower than our old function, and for this one bit of code that is significant.
Ok.
Looking at the implementation for UNIX like systems, I see that create_time() in microsec_time_clock.hpp is calling gettimeofday() followed by a call to gmtime() or localtime() as appropriate. I think it's this second call that is the difference between our old code and boost.
Ok.
In our time critical chunk of code we are just time tagging events, and we aren't concerned about timezone. I was thinking about adding a function to our code that called clock_gettime() (which is what our old code did), but then constructing a time_type out of that using the UNIX epoch for the date part and the results of clock_gettime() for the time_duration part, i.e, in pseudo code:
time_type our_get_time() { clock_gettime(CLOCK_REALTIME, ×pec); time_duration td = massage(timespec); return time_type(unix_epoch, td); }
Looks like a solid approach. Of course you don't have to modify Boost.date_time, you can simply extend it with your own clock implementation. Since you'll only ever be calling universal time you only need to write one function: template<class time_type> class gettime_clock { public: typedef typename time_type::date_type date_type; typedef typename time_type::time_duration_type time_duration_type; typedef typename time_duration_type::rep_type resolution_traits_type; //! Get the current day in universal date as a ymd_type static time_type universal_time() { //your code here... } };
This still won't be as fast as our old code, because we essentially ignored the date part of the times and simply worked with durations since the epoch. But I think the killer for us is the call to gmtime, which the above avoids.
Comments? I'm curious why this approach wasn't taken in boost. Was it the timezone factor?
I'm also curious why gettimeofday() was chosen over clock_gettime()? Is one more available than the other?
Honestly, I don't remember why at this point. There is the issue with timezone adjustment for the other cases. My guess is portability was a factor since gettime_clock is only supported in the POSIX real-time spec, although it's probably pretty widespread now. That said, I'd be willing to improve the implementation of microsecond_clock with this change where it is possible -- looks like we can tell by checking CLOCK_REALTIME. If you send me a working implementation I can drop it in and try it out ;-) Jeff
participants (2)
-
Brian Neal
-
Jeff Garland