
On Tue, Nov 18, 2008 at 9:49 PM, Howard Hinnant <hinnant@twcny.rr.com> wrote:
On Nov 18, 2008, at 5:28 PM, Beman Dawes wrote: ...
Did you look at the boost/chrono/timer.hpp header? It supplies a timer template to create a timer from any clock. I'd be curious to get your reactionsl
You caught me napping. :-)
It looks like a nice utility.
Comments:
* It looks like you would like to see a standard overload of now:
static time_point now(); // might throw static time_point now(system::error_code& ec); // nothrow
Yes, although I haven't decided if anything other than a std::runtime_error is needed. I'm writing a short paper explaining "error_code& ec=throws" idiom so I don't have to explain it from scratch every time the discussion of error reporting idioms comes up.
Please feel free to submit an issue on this.
Already on my to-do list:-)
That being said, I just reviewed several POSIX time functions and it really looks like they just don't fail. I know the ones on darwin don't.
The POSIX clock_gettime function can fail with [EINVAL] "The clock_id argument does not specify a known clock." The Windows QueryPerformanceCounter/QueryPerformanceFrequency functions can fail "if the installed hardware does not support a high-resolution performance counter". Also, both Boost and the C++ standard library have to work for operating systems other than Windows and POSIX.
I know the C standard (and POSIX) say things like:
The value (time_t)(-1)is returned if the calendar time is not available.
This strikes me as a situation where the function either never fails (it is supported), or always fails (it isn't supported). I'm not positive that the error_code overload is warranted for this situation. My preference would be that if the platform doesn't support system_clock (for example) that code using system_clock not compile instead of always fail at run time.
The problem with both Windows and POSIX-like systems is that you can't tell until run time if a clock, particularly monotonic and high-performance, is supported. And as C++ gets used on more tiny embedded processors, the possibility of failure can't be ignored, IMO.
Thus there would be no reason to check the error code (or expect an exception from now()). Currently the only thing [time] has to say on this subject is in [time.duration]/5:
Requires: Members of duration shall not throw exceptions other than those thrown by the indicated operations on their representations.
Perhaps we should widen that sentiment to time_point and clock::now().
If we rely on an overall rule that a function that can't meet its effects, post-conditions, or returns specifications must throw, then carefully written user code for robust applications becomes so littered with try/catch blocks that it becomes unreadable and unmaintainable. That isn't something I'm speculating about; it is something I have heard from users of similar functionality.
* I've written utilities like this in the past. I've always put the functionality of elapsed() plus a print statement in ~timer() so that use cases looked like:
int main() { timer _("Entire Program"); // do stuff }
Output:
Elapsed time for Entire Program was 15 seconds.
Sure. The name of the type is "run_timer" and it is declared in header <boost/chrono/process_times.hpp> By default, the format of the message is "\nreal %rs, cpu %cs (%p%), user %us, system %ss\n", so the output would look like: real 15.000s, cpu 5.000s (33.3%), user 4.000s, system 1.000s To get the exact output you mentioned, construct the timer like this: run_timer _( "Elapsed time for Entire Program was %r seconds.", 0 ); The 0 is the number of decimal places to report. It can range from 0 to 9. It defaults to 3 in the current implementation. The ostream can also be specified; it defaults to cout of course.
... Much more discussion
Howard, I'm pressed for time so only skim read the remainder. My quick impression was that my proposed decomposition into clocks (some provided by the std lib, some by Boost or users), raw timers, and then elaborated timers derived from raw timers provides all the functionality you mention in a easy to use package, yet allows users to avoid functionality they don't need for a particular application. I'll go through the rest in more detail later and get back to you. Thanks, --Beman