Boost logo

Boost :

From: Jeff Garland (jeff_at_[hidden])
Date: 2006-06-25 11:49:49


Beman Dawes wrote:
> After years of procrastination, I've finally put together the CPU timer
> I've always wanted. It provides wall-clock time, user CPU time, and

A few thoughts:

1) long long isn't portable -- use boost::int64_t instead
2) get_process_times compile fails on Linux -- fairly obvious issue here...I'm
guessing you are testing on Windows :-)

cpu_timer.cpp:86: error: ‘m_wall’ was not declared in this scope
cpu_timer.cpp:87: error: ‘m_user’ was not declared in this scope
cpu_timer.cpp:88: error: ‘m_system’ was not declared in this scope
cpu_timer.cpp:90: error: ‘m_wall’ was not declared in this scope
cpu_timer.cpp:90: error: ‘m_user’ was not declared in this scope
cpu_timer.cpp:90: error: ‘m_system’ was not declared in this scope
cpu_timer.cpp: At global scope:

# if defined(BOOST_WINDOWS_API)
   //...snip....

# else
     tms tm;
     clock_t c = ::times( &tm );
     if ( c == -1 ) // error
     {
       wall = system = user = -1;
     }
     else
     {
       wall = c;
       system = tm.tms_stime + tm.tms_cstime;
       user = tm.tms_utime + tm.tms_cutime;
       if ( tick_factor() != -1 )
       {
         wall -= m_wall; wall *= tick_factor();
         user -= m_user; user *= tick_factor();
         system -= m_system; system *= tick_factor();
       }
       else { m_wall = m_user = m_system = -1; }
       }

     }
# endif
   }

3) I see some major overlap in your plans with Boost.Process. You are
providing what amounts to a a simplified form of what I what Julio is doing in
his SOC project. You might have a look at Julio's current design page and
provide feedback:

https://boost-consulting.com:8443/trac/soc/wiki/process/DesignThoughts

I believe he would treat the various times you are measuring as attributes of
the process class. So the code would be something like:

bp::cmdline cl("...do something...");
bp::generic_attributes attrs(cl);

bp::launcher l(attrs);
bp::child c = l.start();

while (!c.exited()) {
   time_duration wall = attrs.wall;
   time_duration user = attrs.user;
   ...
};

4) Eating exceptions:

I don't like this code. I've been burned a few times by code that does eats
exceptions....

     // A) Throwing an exception from a destructor is a Bad Thing,
     // and report() will often be called from destructors
     // B) The destructor does output, and that may throw.
     // C) A cpu_time_reporter is usually not critical to the application.
     // Therefore, wrap the I/O in a try block, catch and ignore all exceptions.
       try
       {
         show_time( m_format.empty()
             ? "\nwall %w s, user %u s, system %s s, total cpu %t s, %p%\n"
             : m_format.c_str(),
           m_places, m_os, this->wall(), this->user(), this->system() );
       }

       catch (...) {} // eat any exceptions
     }

> system CPU time. A time reporter class handles the details of display.
> Typical output would be:
>
> wall 0.50 s, user 0.03 s, system 0.05 s, total cpu 0.08 s, 15.6%
>
> The percentage is CPU utilization relative to wall clock.
>
> Note that I see a CPU timer as complementary rather than competitive to
> the high-precision timer component others are working on. I'm all for
> their effort to continue.

I'm not so sure, but I agree we should continue on both tracks for awhile.

> My plan is to submit the CPU timer stuff as part of a Boost.System
> library, which packages small operating system dependent components
> together for convenience.

For the moment, I mostly see things that overlap other current library efforts
-- error codes excepted. That said, I really applaud the effort. In my view,
Boost has being a piecemeal design OS api portability -- as an example, we
have 3 libraries that retrieve clock time values from the system clock
(thread, date-time, timer). I really think we would make a major advance if
Boost.system would be focused on providing a 'low-level' portable API and then
all the 'higher layer' libraries could use the elements of Boost.system that
they need. This would be kinda like Boost.Config at the system api level.
Then Boost.system would be the first point of porting Boost to new platforms.

There are some issues. Some libraries need their portability functions to be
all header -- others might prefer a library based approach. At what point do
we add to Boost.system as opposed to providing the function in the the library
-- like the filesystem code? And, of course, code gets more scattered around
in the boost tree.

> Note that I did use Boost.Date_Time components. That was because I'm not
                     ^^^^ missing a not
> very familiar with Boost.Date_Time, and wanted to initially concentrate
> on getting the desired results. Advice on how to best make use of
> Boost.Date_Time would be appreciated.

Overall, the intent of the Boost.date_time types is to be efficient wrappers
around core types (eg: integers) that provide the additional functions you
would expect in a time representation. You could probably replace your
microseconds_t type with boost::posix_time::microseconds with little or no
loss of efficiency. By returning a microseconds from functions like wall()
the user can use the date-time streaming operators directly including the
output formatting strings associated with time duration. I believe this would
also eliminate the the double-based precision issues in the I/O code. One
problem I see is that date-time doesn't have an easy way to do set-precision
on i/o...something it probably needs.

Anyway, once you have a version that compiles on Linux I can take a shot at
replacing this and seeing what happens...

Jeff


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