Boost logo

Boost :

Subject: Re: [boost] [timer] Boost Timer Library Version 2
From: Beman Dawes (bdawes_at_[hidden])
Date: 2011-09-28 14:33:11


On Wed, Sep 28, 2011 at 8:38 AM, Stewart, Robert <Robert.Stewart_at_[hidden]> 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


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk