
On Wed, Sep 28, 2011 at 8:38 AM, Stewart, Robert <Robert.Stewart@sig.com> wrote:
Vicente J. Botet Escriba wrote:
* Why does stop returns cpu-times? Why by reference? Why elapsed is not returned by reference?
cpu_times elapsed() const noexcept;
const cpu_times& stop() noexcept;
The interface is, of course, directed by the current implementation. Still, it would be appropriate for stop() to return by value to avoid forcing the implementation to store a cpu_times instance in the timer.
There is only one set of times in the timer. How could an implementation not store the start times within the timer?
* I would associate the operations pairwise start/stop and suspend/resume. I guess it would be easier to explain the semantics.
Yes. Of course. I knew I didn't quite like the current semantics, but it just didn't click. Another advantage of start/stop and suspend/resume is that RAII classes can be used to control the timer.
Here's the new interface:
void start(); void stop(); bool is_stopped(); void suspend(); void resume(); bool is_suspended(); cpu_times elapsed();
I'm totally confused by having four states: stopped/suspended, stopped/not-suspended, not-stopped/suspended, not-stopped/not-suspended. What do the stopped/not-suppended and not-stopped/suspended states represent?
start() notes the current time as the start time and marks the timer as not stopped, if is_stopped(), and marks the timer as not suspended.
I can't parse that. What does ", if is_stopped()," apply to? Or does start() unconditionally mark the timer as not stopped and not suspended?
stop() notes the current time as the end time and marks the timer as stopped, if !is_stopped(), and marks the timer as not suspended.
Same problem with ", if is_stopped()," - what does the if apply to?
suspend() notes the current time as the suspension time and marks the object as being suspended, if !is_stopped() && !is_suspended().
Do you mean? Effects: If !is_stopped() && !is_suspended(), save the current time as the suspension time and mark the object as being suspended? Otherwise, no effects.
resume() calls start() and arranges for a future call to elapsed() to include the time elapsed until suspend() was called plus the time that elapses subsequently, if is_suspended().
Reasonable? I know that means that both start and end times must be stored with this interface (two cpu_times instances, for example), but that seems a worthwhile price.
For what? Are you looking for two timers that start at the same time: cpu_timer t1; cpu_timer t2(t1);
Here's a use case addressed by these ideas:
nanosecond_type status_time(0); cpu_timer timer; for (int i(0); i < 100; ++i) { task_to_time(); scoped_suspender _(timer); nanosecond_type const current_time(timer.elapsed().user); if (1000000000 < current_time - status_time) { report(timer); status_time = current_time; } }
scoped_suspender is an RAII class that calls suspend() and resume(). Thus, the overhead of checking the elapsed time and writing output is not included in the time tracked by the timer. This approach permits doing non-timed work of various sorts in the midst of timed work.
How is your example different from this? nanosecond_type status_time(0); cpu_timer timer; for (int i(0); i < 100; ++i) { task_to_time(); scoped_stop_and_resume(timer); // stop() in ctor, resume() in dtor nanosecond_type const current_time(timer.elapsed().user); if (1000000000 < current_time - status_time) { report(timer); status_time = current_time; } timer.resume(); }
scoped_suspender might be a class template with a generator:
auto _(make_scoped_suspender(timer));
That would allow supporting any timer type that provides suspend() and resume().
How is that different from stop() and resume() with current interface?
I suspect that this use case would be pretty common, so it could be captured:
timer_reporter report(1000000000); // once per second cpu_timer timer; for (int i(0); i < 100; ++i) { task_to_time(); report(timer); }
void timer_reporter::operator ()(cpu_timer & _timer) { if (_timer.is_stopped()) { return; } scoped_suspender _(_timer); nanosecond_type const current(_timer.elapsed().user); if (delay_ < current - last_) { std::string const formatted( _timer.format(precision_, format_)); os_ << formatted; last_ = current; } }
Obviously, I'm suggesting that timer_reporter is somewhat similar to auto_cpu_timer in that it would save a std::ostream & for output, as well as the precision and a format string for calling cpu_timer::format().
Understood.
I purposely did not supply the timer as a constructor argument because that would require construction after a timer already started or else stopping the timer, constructing the timer_reporter, and then starting the timer.
Interesting, --Beman