alpar@906: /* -*- C++ -*- ladanyi@1435: * lemon/time_measure.h - Part of LEMON, a generic C++ optimization library alpar@906: * alpar@1875: * Copyright (C) 2006 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport alpar@1359: * (Egervary Research Group on Combinatorial Optimization, EGRES). alpar@906: * alpar@906: * Permission to use, modify and distribute this software is granted alpar@906: * provided that this copyright notice appears in all copies. For alpar@906: * precise terms see the accompanying LICENSE file. alpar@906: * alpar@906: * This software is provided "AS IS" with no warranty of any kind, alpar@906: * express or implied, and with no claim as to its suitability for any alpar@906: * purpose. alpar@906: * alpar@906: */ alpar@906: alpar@921: #ifndef LEMON_TIME_MEASURE_H alpar@921: #define LEMON_TIME_MEASURE_H alpar@428: alpar@1847: ///\ingroup timecount alpar@428: ///\file alpar@428: ///\brief Tools for measuring cpu usage alpar@428: alpar@428: #include alpar@428: #include alpar@428: #include alpar@428: #include alpar@428: #include alpar@428: alpar@921: namespace lemon { alpar@428: alpar@1847: /// \addtogroup timecount alpar@428: /// @{ alpar@428: alpar@428: /// A class to store (cpu)time instances. alpar@428: alpar@428: /// This class stores five time values. alpar@428: /// - a real time alpar@428: /// - a user cpu time alpar@428: /// - a system cpu time alpar@428: /// - a user cpu time of children alpar@428: /// - a system cpu time of children alpar@428: /// alpar@428: /// TimeStamp's can be added to or substracted from each other and alpar@428: /// they can be pushed to a stream. alpar@458: /// alpar@1851: /// In most cases, perhaps the \ref Timer or the \ref TimeReport alpar@1851: /// class is what you want to use instead. alpar@458: /// alpar@458: ///\author Alpar Juttner alpar@428: alpar@428: class TimeStamp alpar@428: { alpar@1689: struct rtms alpar@1689: { alpar@1689: double tms_utime; alpar@1689: double tms_stime; alpar@1689: double tms_cutime; alpar@1689: double tms_cstime; alpar@1689: rtms() {} alpar@1689: rtms(tms ts) : tms_utime(ts.tms_utime), tms_stime(ts.tms_stime), alpar@1689: tms_cutime(ts.tms_cutime), tms_cstime(ts.tms_cstime) {} alpar@1689: }; alpar@1689: rtms ts; alpar@428: double real_time; alpar@428: alpar@1689: rtms &getTms() {return ts;} alpar@1689: const rtms &getTms() const {return ts;} alpar@1689: alpar@1780: void _reset() alpar@1780: { ts.tms_utime=ts.tms_stime=ts.tms_cutime=ts.tms_cstime=0; real_time=0;} alpar@1780: alpar@428: public: alpar@428: alpar@428: ///Read the current time values of the process alpar@428: void stamp() alpar@428: { alpar@428: timeval tv; alpar@1689: tms _ts; alpar@1689: times(&_ts); alpar@428: gettimeofday(&tv, 0);real_time=tv.tv_sec+double(tv.tv_usec)/1e6; alpar@1689: ts=_ts; alpar@428: } alpar@428: alpar@428: /// Constructor initializing with zero alpar@428: TimeStamp() alpar@1780: { _reset(); } alpar@428: ///Constructor initializing with the current time values of the process alpar@428: TimeStamp(void *) { stamp();} alpar@428: alpar@1780: ///Set every time value to zero alpar@1780: TimeStamp &reset() {_reset();return *this;} alpar@1780: alpar@1005: ///\e alpar@428: TimeStamp &operator+=(const TimeStamp &b) alpar@428: { alpar@428: ts.tms_utime+=b.ts.tms_utime; alpar@428: ts.tms_stime+=b.ts.tms_stime; alpar@428: ts.tms_cutime+=b.ts.tms_cutime; alpar@428: ts.tms_cstime+=b.ts.tms_cstime; alpar@428: real_time+=b.real_time; alpar@428: return *this; alpar@428: } alpar@1005: ///\e alpar@428: TimeStamp operator+(const TimeStamp &b) const alpar@428: { alpar@428: TimeStamp t(*this); alpar@428: return t+=b; alpar@428: } alpar@1005: ///\e alpar@428: TimeStamp &operator-=(const TimeStamp &b) alpar@428: { alpar@428: ts.tms_utime-=b.ts.tms_utime; alpar@428: ts.tms_stime-=b.ts.tms_stime; alpar@428: ts.tms_cutime-=b.ts.tms_cutime; alpar@428: ts.tms_cstime-=b.ts.tms_cstime; alpar@428: real_time-=b.real_time; alpar@428: return *this; alpar@428: } alpar@1005: ///\e alpar@428: TimeStamp operator-(const TimeStamp &b) const alpar@428: { alpar@428: TimeStamp t(*this); alpar@428: return t-=b; alpar@428: } alpar@1689: ///\e alpar@1689: TimeStamp &operator*=(double b) alpar@1689: { alpar@1689: ts.tms_utime*=b; alpar@1689: ts.tms_stime*=b; alpar@1689: ts.tms_cutime*=b; alpar@1689: ts.tms_cstime*=b; alpar@1689: real_time*=b; alpar@1689: return *this; alpar@1689: } alpar@1689: ///\e alpar@1689: TimeStamp operator*(double b) const alpar@1689: { alpar@1689: TimeStamp t(*this); alpar@1689: return t*=b; alpar@1689: } alpar@1689: friend TimeStamp operator*(double b,const TimeStamp &t); alpar@1689: ///\e alpar@1689: TimeStamp &operator/=(double b) alpar@1689: { alpar@1689: ts.tms_utime/=b; alpar@1689: ts.tms_stime/=b; alpar@1689: ts.tms_cutime/=b; alpar@1689: ts.tms_cstime/=b; alpar@1689: real_time/=b; alpar@1689: return *this; alpar@1689: } alpar@1689: ///\e alpar@1689: TimeStamp operator/(double b) const alpar@1689: { alpar@1689: TimeStamp t(*this); alpar@1689: return t/=b; alpar@1689: } alpar@428: ///The time ellapsed since the last call of stamp() alpar@428: TimeStamp ellapsed() const alpar@428: { alpar@428: TimeStamp t(NULL); alpar@428: return t-*this; alpar@428: } alpar@428: alpar@428: friend std::ostream& operator<<(std::ostream& os,const TimeStamp &t); alpar@428: alpar@428: ///Gives back the user time of the process alpar@1689: double userTime() const alpar@428: { alpar@428: return double(ts.tms_utime)/sysconf(_SC_CLK_TCK); alpar@428: } alpar@428: ///Gives back the system time of the process alpar@1689: double systemTime() const alpar@428: { alpar@428: return double(ts.tms_stime)/sysconf(_SC_CLK_TCK); alpar@428: } alpar@428: ///Gives back the user time of the process' children alpar@1689: double cUserTime() const alpar@428: { alpar@428: return double(ts.tms_cutime)/sysconf(_SC_CLK_TCK); alpar@428: } alpar@428: ///Gives back the user time of the process' children alpar@1689: double cSystemTime() const alpar@428: { alpar@428: return double(ts.tms_cstime)/sysconf(_SC_CLK_TCK); alpar@428: } alpar@1780: ///Gives back the real time alpar@1689: double realTime() const {return real_time;} alpar@428: }; alpar@428: alpar@1689: TimeStamp operator*(double b,const TimeStamp &t) alpar@1689: { alpar@1689: return t*b; alpar@1689: } alpar@1689: alpar@1851: ///Prints the time counters alpar@1851: alpar@1851: ///Prints the time counters in the following form: alpar@1851: /// alpar@1851: /// u: XX.XXs s: XX.XXs cu: XX.XXs cs: XX.XXs real: XX.XXs alpar@1851: /// alpar@1851: /// where the values are the alpar@1851: /// \li \c u: user cpu time, alpar@1851: /// \li \c s: system cpu time, alpar@1851: /// \li \c cu: user cpu time of children, alpar@1851: /// \li \c cs: system cpu time of children, alpar@1851: /// \li \c real: real time. alpar@1851: /// \relates TimeStamp alpar@1851: inline std::ostream& operator<<(std::ostream& os,const TimeStamp &t) alpar@1851: { alpar@1851: long cls = sysconf(_SC_CLK_TCK); alpar@1851: os << "u: " << double(t.getTms().tms_utime)/cls << alpar@1851: "s, s: " << double(t.getTms().tms_stime)/cls << alpar@1851: "s, cu: " << double(t.getTms().tms_cutime)/cls << alpar@1851: "s, cs: " << double(t.getTms().tms_cstime)/cls << alpar@1851: "s, real: " << t.realTime() << "s"; alpar@1851: return os; alpar@1851: } alpar@1851: alpar@1780: ///Class for measuring the cpu time and real time usage of the process alpar@458: alpar@1780: ///Class for measuring the cpu time and real time usage of the process. alpar@458: ///It is quite easy-to-use, here is a short example. alpar@458: ///\code alpar@921: ///#include alpar@696: ///#include alpar@814: /// alpar@458: ///int main() alpar@458: ///{ alpar@458: /// alpar@458: /// ... alpar@458: /// alpar@696: /// Timer T; alpar@458: /// doSomething(); alpar@696: /// std::cout << T << '\n'; alpar@1847: /// T.restart(); alpar@458: /// doSomethingElse(); alpar@696: /// std::cout << T << '\n'; alpar@458: /// alpar@458: /// ... alpar@458: /// alpar@458: ///} alpar@458: ///\endcode alpar@458: /// alpar@1780: ///The \ref Timer can also be \ref stop() "stopped" and alpar@1806: ///\ref start() "started" again, so it is possible to compute collected alpar@1780: ///running times. alpar@1780: /// alpar@1780: ///\warning Depending on the operation system and its actual configuration alpar@1847: ///the time counters have a certain (10ms on a typical Linux system) alpar@1847: ///granularity. alpar@1780: ///Therefore this tool is not appropriate to measure very short times. alpar@1780: ///Also, if you start and stop the timer very frequently, it could lead alpar@1780: ///distorted results. alpar@1780: /// alpar@1851: ///\note If you want to measure the running time of the execution of a certain alpar@1851: ///function, consider the usage of \ref TimeReport instead. alpar@1780: /// alpar@458: ///\todo This shouldn't be Unix (Linux) specific. alpar@1851: ///\sa TimeReport alpar@458: /// alpar@458: ///\author Alpar Juttner alpar@428: class Timer alpar@428: { alpar@1847: int _running; //Timer is running iff _running>0; (_running>=0 always holds) alpar@1780: TimeStamp start_time; //This is the relativ start-time if the timer alpar@1847: //is _running, the collected _running time otherwise. alpar@1780: alpar@1847: void _reset() {if(_running) start_time.stamp(); else start_time.reset();} alpar@428: alpar@428: public: alpar@1780: ///Constructor. alpar@1780: alpar@1953: ///\param run indicates whether or not the timer starts immediately. alpar@1780: /// alpar@1847: Timer(bool run=true) :_running(run) {_reset();} alpar@428: alpar@1851: ///\name Control the state of the timer alpar@1851: ///Basically a Timer can be either running or stopped, alpar@1851: ///but it provides a bit finer control on the execution. alpar@1851: ///The \ref Timer also counts the number of \ref start() alpar@1851: ///executions, and is stops only after the same amount (or more) alpar@1851: ///\ref stop() "stop()"s. This can be useful e.g. to compute the running time alpar@1851: ///of recursive functions. alpar@1851: /// alpar@428: alpar@1851: ///@{ alpar@428: alpar@1847: ///Reset and stop the time counters alpar@1069: alpar@1847: ///This function resets and stops the time counters alpar@1847: ///\sa restart() alpar@1069: void reset() alpar@428: { alpar@1847: _running=0; alpar@428: _reset(); alpar@428: } alpar@1005: alpar@1780: ///Start the time counters alpar@1780: alpar@1780: ///This function starts the time counters. alpar@1780: /// alpar@1780: ///If the timer is started more than ones, it will remain running alpar@1780: ///until the same amount of \ref stop() is called. alpar@1780: ///\sa stop() alpar@1780: void start() alpar@1780: { alpar@1847: if(_running) _running++; alpar@1780: else { marci@1850: _running=1; alpar@1780: TimeStamp t; alpar@1780: t.stamp(); alpar@1780: start_time=t-start_time; alpar@1780: } alpar@1780: } alpar@1847: alpar@1780: alpar@1780: ///Stop the time counters alpar@1005: alpar@1847: ///This function stops the time counters. If start() was executed more than alpar@1847: ///once, then the same number of stop() execution is necessary the really alpar@1847: ///stop the timer. alpar@1847: /// alpar@1847: ///\sa halt() alpar@1847: ///\sa start() alpar@1847: ///\sa restart() alpar@1847: ///\sa reset() alpar@1847: alpar@1780: void stop() alpar@1780: { alpar@1847: if(_running && !--_running) { alpar@1780: TimeStamp t; alpar@1780: t.stamp(); alpar@1780: start_time=t-start_time; alpar@1780: } alpar@1780: } alpar@1847: alpar@1847: ///Halt (i.e stop immediately) the time counters alpar@1847: alpar@1847: ///This function stops immediately the time counters. alpar@1847: /// alpar@1847: ///\sa stop() alpar@1847: ///\sa restart() alpar@1847: ///\sa reset() alpar@1847: alpar@1847: void halt() alpar@1847: { alpar@1847: if(_running) { alpar@1847: _running=0; alpar@1847: TimeStamp t; alpar@1847: t.stamp(); alpar@1847: start_time=t-start_time; alpar@1847: } alpar@1847: } alpar@1847: alpar@1847: ///Returns the running state of the timer alpar@1847: alpar@1847: ///This function returns the number of stop() exections that is alpar@1847: ///necessary to really stop the timer. alpar@1847: ///For example the timer alpar@1847: ///is running if and only if the return value is \c true alpar@1847: ///(i.e. greater than alpar@1847: ///zero). alpar@1847: int running() { return _running; } alpar@1847: alpar@1847: alpar@1847: ///Restart the time counters alpar@1847: alpar@1847: ///This function is a shorthand for alpar@1847: ///a reset() and a start() calls. alpar@1847: /// alpar@1847: void restart() alpar@1847: { alpar@1847: reset(); alpar@1847: start(); alpar@1847: } alpar@1780: alpar@1851: ///@} alpar@1851: alpar@1851: ///\name Query Functions for the ellapsed time alpar@1851: alpar@1851: ///@{ alpar@1851: alpar@1005: ///Gives back the ellapsed user time of the process alpar@1689: double userTime() const alpar@1005: { alpar@1689: return operator TimeStamp().userTime(); alpar@1005: } alpar@1005: ///Gives back the ellapsed system time of the process alpar@1689: double systemTime() const alpar@1005: { alpar@1689: return operator TimeStamp().systemTime(); alpar@1005: } alpar@1005: ///Gives back the ellapsed user time of the process' children alpar@1689: double cUserTime() const alpar@1005: { alpar@1689: return operator TimeStamp().cUserTime(); alpar@1005: } alpar@1005: ///Gives back the ellapsed user time of the process' children alpar@1689: double cSystemTime() const alpar@1005: { alpar@1689: return operator TimeStamp().cSystemTime(); alpar@1005: } alpar@1780: ///Gives back the ellapsed real time alpar@1689: double realTime() const alpar@1005: { alpar@1689: return operator TimeStamp().realTime(); alpar@1005: } alpar@1851: ///Computes the ellapsed time alpar@1005: alpar@1851: ///This conversion computes the ellapsed time, therefore you can print alpar@1851: ///the ellapsed time like this. alpar@1851: ///\code alpar@1851: /// Timer T; alpar@1851: /// doSomething(); alpar@1851: /// std::cout << T << '\n'; alpar@1851: ///\endcode alpar@1851: operator TimeStamp () const alpar@1851: { alpar@1851: TimeStamp t; alpar@1851: t.stamp(); alpar@1851: return _running?t-start_time:start_time; alpar@1851: } alpar@1851: alpar@1851: alpar@1851: ///@} alpar@428: }; alpar@428: alpar@1847: ///Same as \ref Timer but prints a report on destruction. alpar@1847: alpar@1847: ///Same as \ref Timer but prints a report on destruction. alpar@1851: ///This example shows its usage. alpar@1851: ///\code alpar@1851: /// void myAlg(ListGraph &g,int n) alpar@1851: /// { alpar@1851: /// TimeReport TR("Running time of myAlg: "); alpar@1851: /// ... //Here comes the algorithm alpar@1851: /// } alpar@1851: ///\endcode alpar@1851: /// alpar@1851: ///\sa Timer alpar@1851: ///\sa NoTimeReport alpar@1851: ///\todo There is no test case for this alpar@1847: class TimeReport : public Timer alpar@1847: { alpar@1847: std::string _title; alpar@1847: std::ostream &_os; alpar@1847: public: alpar@1847: ///\e alpar@1851: alpar@1851: ///\param title This text will be printed before the ellapsed time. alpar@1851: ///\param os The stream to print the report to. alpar@1851: ///\param run Sets whether the timer should start immediately. alpar@1851: alpar@1851: TimeReport(std::string title,std::ostream &os=std::cerr,bool run=true) alpar@1847: : Timer(run), _title(title), _os(os){} alpar@1851: ///\e Prints the ellapsed time on destruction. alpar@1847: ~TimeReport() alpar@1847: { alpar@1851: _os << _title << *this << std::endl; alpar@1847: } alpar@1847: }; alpar@1847: alpar@1851: ///'Do nothing' version of \ref TimeReport alpar@428: alpar@1851: ///\sa TimeReport alpar@428: /// alpar@1851: class NoTimeReport alpar@428: { alpar@1851: public: alpar@1851: ///\e alpar@1855: NoTimeReport(std::string,std::ostream &,bool) {} alpar@1855: ///\e alpar@1855: NoTimeReport(std::string,std::ostream &) {} alpar@1855: ///\e alpar@1855: NoTimeReport(std::string) {} alpar@1851: ///\e Do nothing. alpar@1851: ~NoTimeReport() {} alpar@428: alpar@1851: operator TimeStamp () const { return TimeStamp(); } alpar@1851: void reset() {} alpar@1851: void start() {} alpar@1851: void stop() {} alpar@1851: void halt() {} alpar@1851: int running() { return 0; } alpar@1851: void restart() {} alpar@1851: double userTime() const { return 0; } alpar@1851: double systemTime() const { return 0; } alpar@1851: double cUserTime() const { return 0; } alpar@1851: double cSystemTime() const { return 0; } alpar@1851: double realTime() const { return 0; } alpar@1851: }; alpar@1851: alpar@1689: ///Tool to measure the running time more exactly. alpar@1689: alpar@1689: ///This function calls \c f several times and returns the average alpar@1689: ///running time. The number of the executions will be choosen in such a way alpar@1780: ///that the full real running time will be roughly between \c min_time alpar@1689: ///and 2*min_time. alpar@1689: ///\param f the function object to be measured. alpar@1689: ///\param min_time the minimum total running time. alpar@1894: ///\retval num if it is not \c NULL, then the actual alpar@1894: /// number of execution of \c f will be written into *num. alpar@1894: ///\retval full_time if it is not \c NULL, then the actual alpar@1894: /// total running time will be written into *full_time. alpar@1689: ///\return The average running time of \c f. alpar@1689: alpar@1689: template deba@1839: TimeStamp runningTimeTest(F f,double min_time=10,int *num = NULL, alpar@1689: TimeStamp *full_time=NULL) alpar@1689: { alpar@1689: Timer t; alpar@1689: TimeStamp full; alpar@1689: int total=0; alpar@1689: for(int tn=1;tn < 1<<24; tn*=2) { alpar@1811: for(;totalmin_time) { alpar@1689: if(num) *num=total; alpar@1689: if(full_time) *full_time=full; alpar@1689: return full/total; alpar@1689: } alpar@1689: } alpar@1689: return TimeStamp(); alpar@1689: } alpar@1689: alpar@428: /// @} alpar@428: alpar@1689: alpar@921: } //namespace lemon alpar@428: alpar@921: #endif //LEMON_TIME_MEASURE_H