lemon/time_measure.h
author hegyi
Mon, 21 Nov 2005 18:03:20 +0000
changeset 1823 cb082cdf3667
parent 1806 1530c115580f
child 1839 b2dfd32b4895
permissions -rw-r--r--
NewMapWin has become Dialog instead of Window. Therefore it is created dynamically, when there is need for it, instead of keeping one instance in memory. This solution is slower, but more correct than before.
alpar@906
     1
/* -*- C++ -*-
ladanyi@1435
     2
 * lemon/time_measure.h - Part of LEMON, a generic C++ optimization library
alpar@906
     3
 *
alpar@1164
     4
 * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
alpar@1359
     5
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
alpar@906
     6
 *
alpar@906
     7
 * Permission to use, modify and distribute this software is granted
alpar@906
     8
 * provided that this copyright notice appears in all copies. For
alpar@906
     9
 * precise terms see the accompanying LICENSE file.
alpar@906
    10
 *
alpar@906
    11
 * This software is provided "AS IS" with no warranty of any kind,
alpar@906
    12
 * express or implied, and with no claim as to its suitability for any
alpar@906
    13
 * purpose.
alpar@906
    14
 *
alpar@906
    15
 */
alpar@906
    16
alpar@921
    17
#ifndef LEMON_TIME_MEASURE_H
alpar@921
    18
#define LEMON_TIME_MEASURE_H
alpar@428
    19
klao@491
    20
///\ingroup misc
alpar@428
    21
///\file
alpar@428
    22
///\brief Tools for measuring cpu usage
alpar@428
    23
alpar@428
    24
#include <sys/time.h>
alpar@428
    25
#include <sys/times.h>
alpar@428
    26
#include <fstream>
alpar@428
    27
#include <iostream>
alpar@428
    28
#include <unistd.h>
alpar@428
    29
alpar@921
    30
namespace lemon {
alpar@428
    31
alpar@428
    32
  /// \addtogroup misc
alpar@428
    33
  /// @{
alpar@428
    34
alpar@428
    35
  /// A class to store (cpu)time instances.
alpar@428
    36
alpar@428
    37
  /// This class stores five time values.
alpar@428
    38
  /// - a real time
alpar@428
    39
  /// - a user cpu time
alpar@428
    40
  /// - a system cpu time
alpar@428
    41
  /// - a user cpu time of children
alpar@428
    42
  /// - a system cpu time of children
alpar@428
    43
  ///
alpar@428
    44
  /// TimeStamp's can be added to or substracted from each other and
alpar@428
    45
  /// they can be pushed to a stream.
alpar@458
    46
  ///
alpar@458
    47
  /// In most cases, perhaps \ref Timer class is what you want to use instead.
alpar@458
    48
  ///
alpar@458
    49
  ///\author Alpar Juttner
alpar@428
    50
alpar@428
    51
  class TimeStamp
alpar@428
    52
  {
alpar@1689
    53
    struct rtms 
alpar@1689
    54
    {
alpar@1689
    55
      double tms_utime;
alpar@1689
    56
      double tms_stime;
alpar@1689
    57
      double tms_cutime;
alpar@1689
    58
      double tms_cstime;
alpar@1689
    59
      rtms() {}
alpar@1689
    60
      rtms(tms ts) : tms_utime(ts.tms_utime), tms_stime(ts.tms_stime),
alpar@1689
    61
		     tms_cutime(ts.tms_cutime), tms_cstime(ts.tms_cstime) {}
alpar@1689
    62
    };
alpar@1689
    63
    rtms ts;
alpar@428
    64
    double real_time;
alpar@428
    65
  
alpar@1689
    66
    rtms &getTms() {return ts;}
alpar@1689
    67
    const rtms &getTms() const {return ts;}
alpar@1689
    68
alpar@1780
    69
    void _reset() 
alpar@1780
    70
    { ts.tms_utime=ts.tms_stime=ts.tms_cutime=ts.tms_cstime=0; real_time=0;}
alpar@1780
    71
alpar@428
    72
  public:
alpar@428
    73
alpar@428
    74
    ///Read the current time values of the process
alpar@428
    75
    void stamp()
alpar@428
    76
    {
alpar@428
    77
      timeval tv;
alpar@1689
    78
      tms _ts;
alpar@1689
    79
      times(&_ts);
alpar@428
    80
      gettimeofday(&tv, 0);real_time=tv.tv_sec+double(tv.tv_usec)/1e6;
alpar@1689
    81
      ts=_ts;
alpar@428
    82
    }
alpar@428
    83
  
alpar@428
    84
    /// Constructor initializing with zero
alpar@428
    85
    TimeStamp()
alpar@1780
    86
    { _reset(); }
alpar@428
    87
    ///Constructor initializing with the current time values of the process
alpar@428
    88
    TimeStamp(void *) { stamp();}
alpar@428
    89
  
alpar@1780
    90
    ///Set every time value to zero
alpar@1780
    91
    TimeStamp &reset() {_reset();return *this;}
alpar@1780
    92
alpar@1005
    93
    ///\e
alpar@428
    94
    TimeStamp &operator+=(const TimeStamp &b)
alpar@428
    95
    {
alpar@428
    96
      ts.tms_utime+=b.ts.tms_utime;
alpar@428
    97
      ts.tms_stime+=b.ts.tms_stime;
alpar@428
    98
      ts.tms_cutime+=b.ts.tms_cutime;
alpar@428
    99
      ts.tms_cstime+=b.ts.tms_cstime;
alpar@428
   100
      real_time+=b.real_time;
alpar@428
   101
      return *this;
alpar@428
   102
    }
alpar@1005
   103
    ///\e
alpar@428
   104
    TimeStamp operator+(const TimeStamp &b) const
alpar@428
   105
    {
alpar@428
   106
      TimeStamp t(*this);
alpar@428
   107
      return t+=b;
alpar@428
   108
    }
alpar@1005
   109
    ///\e
alpar@428
   110
    TimeStamp &operator-=(const TimeStamp &b)
alpar@428
   111
    {
alpar@428
   112
      ts.tms_utime-=b.ts.tms_utime;
alpar@428
   113
      ts.tms_stime-=b.ts.tms_stime;
alpar@428
   114
      ts.tms_cutime-=b.ts.tms_cutime;
alpar@428
   115
      ts.tms_cstime-=b.ts.tms_cstime;
alpar@428
   116
      real_time-=b.real_time;
alpar@428
   117
      return *this;
alpar@428
   118
    }
alpar@1005
   119
    ///\e
alpar@428
   120
    TimeStamp operator-(const TimeStamp &b) const
alpar@428
   121
    {
alpar@428
   122
      TimeStamp t(*this);
alpar@428
   123
      return t-=b;
alpar@428
   124
    }
alpar@1689
   125
    ///\e
alpar@1689
   126
    TimeStamp &operator*=(double b)
alpar@1689
   127
    {
alpar@1689
   128
      ts.tms_utime*=b;
alpar@1689
   129
      ts.tms_stime*=b;
alpar@1689
   130
      ts.tms_cutime*=b;
alpar@1689
   131
      ts.tms_cstime*=b;
alpar@1689
   132
      real_time*=b;
alpar@1689
   133
      return *this;
alpar@1689
   134
    }
alpar@1689
   135
    ///\e
alpar@1689
   136
    TimeStamp operator*(double b) const
alpar@1689
   137
    {
alpar@1689
   138
      TimeStamp t(*this);
alpar@1689
   139
      return t*=b;
alpar@1689
   140
    }
alpar@1689
   141
    friend TimeStamp operator*(double b,const TimeStamp &t);
alpar@1689
   142
    ///\e
alpar@1689
   143
    TimeStamp &operator/=(double b)
alpar@1689
   144
    {
alpar@1689
   145
      ts.tms_utime/=b;
alpar@1689
   146
      ts.tms_stime/=b;
alpar@1689
   147
      ts.tms_cutime/=b;
alpar@1689
   148
      ts.tms_cstime/=b;
alpar@1689
   149
      real_time/=b;
alpar@1689
   150
      return *this;
alpar@1689
   151
    }
alpar@1689
   152
    ///\e
alpar@1689
   153
    TimeStamp operator/(double b) const
alpar@1689
   154
    {
alpar@1689
   155
      TimeStamp t(*this);
alpar@1689
   156
      return t/=b;
alpar@1689
   157
    }
alpar@428
   158
    ///The time ellapsed since the last call of stamp()
alpar@428
   159
    TimeStamp ellapsed() const
alpar@428
   160
    {
alpar@428
   161
      TimeStamp t(NULL);
alpar@428
   162
      return t-*this;
alpar@428
   163
    }
alpar@428
   164
  
alpar@428
   165
    friend std::ostream& operator<<(std::ostream& os,const TimeStamp &t);
alpar@428
   166
  
alpar@428
   167
    ///Gives back the user time of the process
alpar@1689
   168
    double userTime() const
alpar@428
   169
    {
alpar@428
   170
      return double(ts.tms_utime)/sysconf(_SC_CLK_TCK);
alpar@428
   171
    }
alpar@428
   172
    ///Gives back the system time of the process
alpar@1689
   173
    double systemTime() const
alpar@428
   174
    {
alpar@428
   175
      return double(ts.tms_stime)/sysconf(_SC_CLK_TCK);
alpar@428
   176
    }
alpar@428
   177
    ///Gives back the user time of the process' children
alpar@1689
   178
    double cUserTime() const
alpar@428
   179
    {
alpar@428
   180
      return double(ts.tms_cutime)/sysconf(_SC_CLK_TCK);
alpar@428
   181
    }
alpar@428
   182
    ///Gives back the user time of the process' children
alpar@1689
   183
    double cSystemTime() const
alpar@428
   184
    {
alpar@428
   185
      return double(ts.tms_cstime)/sysconf(_SC_CLK_TCK);
alpar@428
   186
    }
alpar@1780
   187
    ///Gives back the real time
alpar@1689
   188
    double realTime() const {return real_time;}
alpar@428
   189
  };
alpar@428
   190
alpar@1689
   191
  TimeStamp operator*(double b,const TimeStamp &t) 
alpar@1689
   192
  {
alpar@1689
   193
    return t*b;
alpar@1689
   194
  }
alpar@1689
   195
  
alpar@1780
   196
  ///Class for measuring the cpu time and real time usage of the process
alpar@458
   197
alpar@1780
   198
  ///Class for measuring the cpu time and real time usage of the process.
alpar@458
   199
  ///It is quite easy-to-use, here is a short example.
alpar@458
   200
  ///\code
alpar@921
   201
  ///#include<lemon/time_measure.h>
alpar@696
   202
  ///#include<iostream>
alpar@814
   203
  ///
alpar@458
   204
  ///int main()
alpar@458
   205
  ///{
alpar@458
   206
  ///
alpar@458
   207
  ///  ...
alpar@458
   208
  ///
alpar@696
   209
  ///  Timer T;
alpar@458
   210
  ///  doSomething();
alpar@696
   211
  ///  std::cout << T << '\n';
alpar@458
   212
  ///  T.reset();
alpar@458
   213
  ///  doSomethingElse();
alpar@696
   214
  ///  std::cout << T << '\n';
alpar@458
   215
  ///
alpar@458
   216
  ///  ...
alpar@458
   217
  ///
alpar@458
   218
  ///}
alpar@458
   219
  ///\endcode
alpar@458
   220
  ///
alpar@1780
   221
  ///The \ref Timer can also be \ref stop() "stopped" and
alpar@1806
   222
  ///\ref start() "started" again, so it is possible to compute collected
alpar@1780
   223
  ///running times.
alpar@1780
   224
  ///
alpar@1780
   225
  ///\warning Depending on the operation system and its actual configuration
alpar@1780
   226
  ///the time counters have a certain (relatively big) granularity.
alpar@1780
   227
  ///Therefore this tool is not appropriate to measure very short times.
alpar@1780
   228
  ///Also, if you start and stop the timer very frequently, it could lead
alpar@1780
   229
  ///distorted results.
alpar@1780
   230
  ///
alpar@1780
   231
  ///The \ref Timer also counts the number of \ref start()
alpar@1780
   232
  ///executions, and is stops only after the same amount (or more)
alpar@1780
   233
  ///\ref stop() "stop()"s. This can be useful e.g. to compute the running time
alpar@1780
   234
  ///of recursive functions.
alpar@1780
   235
  ///
alpar@458
   236
  ///\todo This shouldn't be Unix (Linux) specific.
alpar@458
   237
  ///
alpar@458
   238
  ///\author Alpar Juttner
alpar@428
   239
  class Timer
alpar@428
   240
  {
alpar@1780
   241
    int running; //Timer is running iff running>0; (running>=0 always holds)
alpar@1780
   242
    TimeStamp start_time; //This is the relativ start-time if the timer
alpar@1780
   243
                          //is running, the collected running time otherwise.
alpar@1780
   244
    
alpar@1780
   245
    void _reset() {if(running) start_time.stamp(); else start_time.reset();}
alpar@428
   246
  
alpar@428
   247
  public: 
alpar@1780
   248
    ///Constructor.
alpar@1780
   249
alpar@1780
   250
    ///\param _running indicates whether or not the timer starts immediately.
alpar@1780
   251
    ///
alpar@1780
   252
    Timer(bool _running=true) :running(_running) {_reset();}
alpar@428
   253
alpar@428
   254
    ///Computes the ellapsed time
alpar@428
   255
alpar@428
   256
    ///This conversion computes the ellapsed time
alpar@1780
   257
    ///
alpar@1005
   258
    operator TimeStamp () const
alpar@428
   259
    {
alpar@428
   260
      TimeStamp t;
alpar@428
   261
      t.stamp();
alpar@1780
   262
      return running?t-start_time:start_time;
alpar@428
   263
    }
alpar@428
   264
alpar@428
   265
    ///Resets the time counters
alpar@1069
   266
alpar@1069
   267
    ///Resets the time counters
alpar@1069
   268
    ///
alpar@1069
   269
    void reset()
alpar@428
   270
    {
alpar@428
   271
      _reset();
alpar@428
   272
    }
alpar@1005
   273
alpar@1780
   274
    ///Start the time counters
alpar@1780
   275
    
alpar@1780
   276
    ///This function starts the time counters.
alpar@1780
   277
    ///
alpar@1780
   278
    ///If the timer is started more than ones, it will remain running
alpar@1780
   279
    ///until the same amount of \ref stop() is called.
alpar@1780
   280
    ///\sa stop()
alpar@1780
   281
    void start() 
alpar@1780
   282
    {
alpar@1780
   283
      if(running) running++;
alpar@1780
   284
      else {
alpar@1780
   285
	TimeStamp t;
alpar@1780
   286
	t.stamp();
alpar@1780
   287
	start_time=t-start_time;
alpar@1780
   288
      }
alpar@1780
   289
    }
alpar@1780
   290
    
alpar@1780
   291
    ///Stop the time counters
alpar@1005
   292
alpar@1780
   293
    ///This function stops the time counters.
alpar@1780
   294
    ///
alpar@1780
   295
    ///\sa stop()
alpar@1780
   296
    void stop() 
alpar@1780
   297
    {
alpar@1780
   298
      if(running && !--running) {
alpar@1780
   299
	TimeStamp t;
alpar@1780
   300
	t.stamp();
alpar@1780
   301
	start_time=t-start_time;
alpar@1780
   302
      }
alpar@1780
   303
    }
alpar@1780
   304
    
alpar@1005
   305
    ///Gives back the ellapsed user time of the process
alpar@1689
   306
    double userTime() const
alpar@1005
   307
    {
alpar@1689
   308
      return operator TimeStamp().userTime();
alpar@1005
   309
    }
alpar@1005
   310
    ///Gives back the ellapsed system time of the process
alpar@1689
   311
    double systemTime() const
alpar@1005
   312
    {
alpar@1689
   313
      return operator TimeStamp().systemTime();
alpar@1005
   314
    }
alpar@1005
   315
    ///Gives back the ellapsed user time of the process' children
alpar@1689
   316
    double cUserTime() const
alpar@1005
   317
    {
alpar@1689
   318
      return operator TimeStamp().cUserTime();
alpar@1005
   319
    }
alpar@1005
   320
    ///Gives back the ellapsed user time of the process' children
alpar@1689
   321
    double cSystemTime() const
alpar@1005
   322
    {
alpar@1689
   323
      return operator TimeStamp().cSystemTime();
alpar@1005
   324
    }
alpar@1780
   325
    ///Gives back the ellapsed real time
alpar@1689
   326
    double realTime() const
alpar@1005
   327
    {
alpar@1689
   328
      return operator TimeStamp().realTime();
alpar@1005
   329
    }
alpar@1005
   330
alpar@428
   331
  };
alpar@428
   332
alpar@428
   333
  ///Prints the time counters
alpar@428
   334
klao@492
   335
  ///Prints the time counters in the following form:
alpar@428
   336
  ///
alpar@440
   337
  /// <tt>u: XX.XXs s: XX.XXs cu: XX.XXs cs: XX.XXs real: XX.XXs</tt>
alpar@428
   338
  ///
alpar@428
   339
  /// where the values are the
alpar@440
   340
  /// \li \c u: user cpu time,
alpar@440
   341
  /// \li \c s: system cpu time,
alpar@440
   342
  /// \li \c cu: user cpu time of children,
alpar@440
   343
  /// \li \c cs: system cpu time of children,
alpar@440
   344
  /// \li \c real: real time.
alpar@814
   345
  /// \relates TimeStamp
alpar@428
   346
  inline std::ostream& operator<<(std::ostream& os,const TimeStamp &t)
alpar@428
   347
  {
alpar@428
   348
    long cls = sysconf(_SC_CLK_TCK);
alpar@428
   349
    os << "u: " << double(t.getTms().tms_utime)/cls <<
alpar@428
   350
      "s, s: " << double(t.getTms().tms_stime)/cls <<
alpar@428
   351
      "s, cu: " << double(t.getTms().tms_cutime)/cls <<
alpar@428
   352
      "s, cs: " << double(t.getTms().tms_cstime)/cls <<
alpar@1689
   353
      "s, real: " << t.realTime() << "s";
alpar@428
   354
    return os;
alpar@428
   355
  }
alpar@428
   356
alpar@1689
   357
  
alpar@1689
   358
  ///Tool to measure the running time more exactly.
alpar@1689
   359
  
alpar@1689
   360
  ///This function calls \c f several times and returns the average
alpar@1689
   361
  ///running time. The number of the executions will be choosen in such a way
alpar@1780
   362
  ///that the full real running time will be roughly between \c min_time
alpar@1689
   363
  ///and <tt>2*min_time</tt>.
alpar@1689
   364
  ///\param f the function object to be measured.
alpar@1689
   365
  ///\param min_time the minimum total running time.
alpar@1689
   366
  ///\retval num if it is not \c NULL, then *num will contain the actual
alpar@1689
   367
  ///        number of execution of \c f.
alpar@1689
   368
  ///\retval full_time if it is not \c NULL, then *full_time
alpar@1689
   369
  ///        will contain the actual
alpar@1689
   370
  ///        total running time.
alpar@1689
   371
  ///\return The average running time of \c f.
alpar@1689
   372
  
alpar@1689
   373
  template<class F>
alpar@1806
   374
  TimeStamp runningTimeTest(const F &f,double min_time=10,int *num = NULL,
alpar@1689
   375
			TimeStamp *full_time=NULL)
alpar@1689
   376
  {
alpar@1689
   377
    Timer t;
alpar@1689
   378
    TimeStamp full;
alpar@1689
   379
    int total=0;
alpar@1689
   380
    for(int tn=1;tn < 1<<24; tn*=2) {
alpar@1811
   381
      for(;total<tn;total++) f();
alpar@1689
   382
      full=t;
alpar@1689
   383
      if(full.realTime()>min_time) {
alpar@1689
   384
	if(num) *num=total;
alpar@1689
   385
	if(full_time) *full_time=full;
alpar@1689
   386
      return full/total;
alpar@1689
   387
      }
alpar@1689
   388
    }
alpar@1689
   389
    return TimeStamp();
alpar@1689
   390
  }
alpar@1689
   391
  
alpar@428
   392
  /// @}  
alpar@428
   393
alpar@1689
   394
alpar@921
   395
} //namespace lemon
alpar@428
   396
alpar@921
   397
#endif //LEMON_TIME_MEASURE_H