
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