Boost logo

Boost :

Subject: Re: [boost] [system] Boost.Timer replacement
From: Stewart, Robert (Robert.Stewart_at_[hidden])
Date: 2011-09-20 10:36:57


Beman Dawes wrote:
> On Mon, Sep 19, 2011 at 4:39 PM, Stewart, Robert
> <Robert.Stewart_at_[hidden]>wrote:
>
> > I dislike the idea of relying on a destructor to report
> > timing information as you've done in run_timer. The no-throw
> > demands of a destructor make I/O questionable since there is
> > no means to report failure. I realize that there is a
> > report() member function that can be called separately, but
> > using the destructor just seems too odd.
>
> It comes down to ease of use. In practice, the idiom "just
> works".

See below on this point.

> What should these be named? I settled on:
>
> class high_resolution_timer; // wall time
> class auto_high_resolution_timer; // wall time, reporting
> class cpu_timer; // wall/user/system time
> class auto_cpu_timer; // wall/user/system, reporting
>
> Applying your suggestion yields reporting_high_resolution_timer
> and reporting_cpu_timer.
>
> reporting_high_resolution_timer is kinda long, so we might use
> hi_res_timer and reporting_hi_res_timer.

I think "hi_res" is fine. "auto" conveys nothing to me in this context and smacks of the keyword. Why not "scoped"?

> > Because of all of those strikes against run_timer, I'd
> > prefer something like this:
> >
> > class timer
> > {
> > public:
> > // as before
> >
> > void
> > report(int _places = 2); // writes to std::cout
> >
> > void
> > report(int _places, std::ostream & _stream);
> >
> > void
> > report(std::string const & _format, int _places = 2);
> >
> > void
> > report(std::string const & _format, int _places,
> > std::ostream & _stream);
> > };
[snip]
> > timer t;
> > {
> > stopper _(t);
> > // do stuff
> > }
>
> Interesting, but mixing timing and reporting in the same class
> doesn't seem desirable to me.

That's what run_timer does, right? I realize that you offer timer separately. If that's all that concerns you, then provide timer and the above, derived from timer, as reporting_timer, with run_timer as further derived.

> My most frequent use of timers has been for reporting, and I
> really want to keep that usage simple.
>
> The difference between:
>
> int main()
> {
> timer t;
> {
> stopper _(t);
> // do stuff
> }
> }
>
> and:
>
> int main()
> {
> auto_timer t;
> // do stuff
> }
>
> is really major and would make the usage harder to teach and
> less likely to be used, IMO.

When the use case is more complicated, things aren't so simple with your approach:

size_t const n(100);
std::cout << "There were " << n << " iterations which took ";
run_timer t("%ts (%ss system, %us user)");
// something to be timed, producing a value to report
t.report();
std::cout << " producing the answer: " << value << std::endl;

Combining reporting in this fashion is awkward. You can see how the constructor arguments are not associated with the call to report().

The following shows one easier way to address that:

   timer t;
   // something to be timed, producing a value to report
   t.stop(); // captures elapsed time
   std::cout << "There were " << n << " iterations which took "
      << t.total_time() << "s (" << t.system_time() << "s system, "
      << t.user_time() << "s user) producing the answer: "
      << value << std::endl;

That could also be done like this:

   timer t;
   // something to be timed, producing a value to report
   t.stop();
   std::cout << "There were " << n << " iterations which took "
      << format(t, "%ts (%ss system, %us user)")
      << " producing the answer: " << value << std::endl;

Instead of the manipulator, the following is also possible, though it assumes a string type:

   os << t.format("%ts (%ss system, %us user)")

Coming full circle, there's the report() approach:

   std::cout << "There were " << n << " iterations which took ";
   t.report("%ts (%ss system, %us user)"));
   std::cout << " producing the answer: " << value << std::endl;

Doing so permits reusing the timer, even resuming it as I suggested in my previous reply. (By tracking the elapsed time, using cpu_times, whenever the timer is stopped, it can be resumed from a new start time. That elapsed time would be how total_time(), system_time(), and user_time() would get their values.) This permits doing non-timing related work, like reporting, before continuing with resume():

   int const n(100);
   timer t;
   for (int i(0); i < n; ++i)
   {
      // something to be timed, producing a value to report
      if (0 == i % 20)
      {
         t.stop();
         std::cout << i << " iterations took "
            << format(t, "%ts (%ss system, %us user)")
            << std::endl;
         t.resume();
      }
   }
   t.stop();
   // final report

The destructor-triggered reporting can still be provided via run_timer (with whatever name), but provide the basic means to produce output, including the format string rendering, in timer or a derivate.

_____
Rob Stewart robert.stewart_at_[hidden]
Software Engineer using std::disclaimer;
Dev Tools & Components
Susquehanna International Group, LLP http://www.sig.com

________________________________

IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.


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