timer.hh 8.04 KB
Newer Older
1
// -*- coding: utf-8 -*-
2
// Copyright (C) 2009, 2011, 2012, 2013, 2014, 2015, 2016 Laboratoire de
3
// Recherche et Développement de l'Epita (LRDE).
Guillaume Sadegh's avatar
Guillaume Sadegh committed
4
// Copyright (C) 2004 Laboratoire d'Informatique de Paris 6 (LIP6),
5
// département Systèmes Répartis Coopératifs (SRC), Université Pierre
6
7
8
9
10
11
// et Marie Curie.
//
// This file is part of Spot, a model checking library.
//
// Spot is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
12
// the Free Software Foundation; either version 3 of the License, or
13
14
15
16
17
18
19
20
// (at your option) any later version.
//
// Spot is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
21
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
22

23
24
#pragma once

25
26
#include <spot/misc/common.hh>
#include <spot/misc/_config.h>
27
28
29
30
31
32
33
34
35
#include <cassert>
#include <iosfwd>
#include <string>
#include <map>
#include <chrono>
#if SPOT_HAVE_SYS_TIMES_H
# include <sys/times.h>
#endif
#include <ctime>
36

37
38
39

namespace spot
{
40
  /// \ingroup misc_tools
41
42
  /// @{

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

  /// \brief A simple stopwatch
  struct stopwatch
  {
  protected:
    typedef std::chrono::high_resolution_clock clock;
    clock::time_point start_;
  public:
    /// Marks the start if the measurement
    void start()
    {
      start_ = clock::now();
    }

    /// \brief Returns the elapsed duration in seconds.
    ///
    /// May be called multiple times, and will always return the
    /// duration since the last call to start().
    double stop()
    {
      auto t = clock::now();
      typedef std::chrono::duration<double> seconds;
      return std::chrono::duration_cast<seconds>(t - start_).count();
    }
  };

69
70
71
72
  /// A structure to record elapsed time in clock ticks.
  struct time_info
  {
    time_info()
73
      : utime(0), stime(0), cutime(0), cstime(0)
74
75
76
77
    {
    }
    clock_t utime;
    clock_t stime;
78
79
    clock_t cutime;
    clock_t cstime;
80
81
  };

82
83
84
  /// A timekeeper that accumulate interval of time in a more detailed way.
  /// For instance, you can get the time spent with or without children
  /// processes.
85
86
87
  class timer
  {
  public:
88
89
90
91
    timer()
      : running(false)
    {
    }
92
93
94
95
96

    /// Start a time interval.
    void
    start()
    {
97
      SPOT_ASSERT(!running);
98
      running = true;
99
#ifdef SPOT_HAVE_TIMES
100
101
      struct tms tmp;
      times(&tmp);
102
103
104
105
      start_.utime = tmp.tms_utime;
      start_.cutime = tmp.tms_cutime;
      start_.stime = tmp.tms_stime;
      start_.cstime = tmp.tms_cstime;
106
107
108
#else
      start_.utime = clock();
#endif
109
110
111
112
113
114
    }

    /// Stop a time interval and update the sum of all intervals.
    void
    stop()
    {
115
#ifdef SPOT_HAVE_TIMES
116
117
      struct tms tmp;
      times(&tmp);
118
119
120
121
      total_.utime += tmp.tms_utime - start_.utime;
      total_.cutime += tmp.tms_cutime - start_.cutime;
      total_.stime += tmp.tms_stime - start_.stime;
      total_.cstime += tmp.tms_cstime - start_.cstime;
122
123
124
#else
      total_.utime += clock() - start_.utime;
#endif
125
      SPOT_ASSERT(running);
126
      running = false;
127
128
    }

129
130
    /// \brief Return the user time of the current process (without children)
    /// of all accumulated interval.
131
132
133
134
135
136
137
138
139
    ///
    /// Any time interval that has been start()ed but not stop()ed
    /// will not be accounted for.
    clock_t
    utime() const
    {
      return total_.utime;
    }

140
141
142
143
144
145
146
147
148
149
150
151
    /// \brief Return the user time of children of all accumulated interval.
    ///
    /// Any time interval that has been start()ed but not stop()ed
    /// will not be accounted for.
    clock_t
    cutime() const
    {
      return total_.cutime;
    }

    /// \brief Return the system time of the current process (whithout children)
    /// of all accumulated interval.
152
153
154
155
156
157
158
159
160
    ///
    /// Any time interval that has been start()ed but not stop()ed
    /// will not be accounted for.
    clock_t
    stime() const
    {
      return total_.stime;
    }

161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
    /// \brief Return the system time of children of all accumulated interval.
    ///
    /// Any time interval that has been start()ed but not stop()ed
    /// will not be accounted for.
    clock_t
    cstime() const
    {
      return total_.cstime;
    }

    clock_t get_uscp(bool user, bool system, bool children, bool parent) const
    {
      clock_t res = 0;

      if (user && parent)
        res += utime();

      if (user && children)
        res += cutime();

      if (system && parent)
        res += stime();

      if (system && children)
        res += cstime();

      return res;
    }
189
190
191
192
193
194
195
196

    /// \brief Whether the timer is running.
    bool
    is_running() const
    {
      return running;
    }

197
198
199
  protected:
    time_info start_;
    time_info total_;
200
    bool running;
201
202
  };

203
204
205
206
  // This function declared here must be implemented in each file
  // that includes this header, well, only if this operator is needed!
  inline std::ostream& operator<<(std::ostream& os, const timer& dt);

207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
  /// \brief A map of timer, where each timer has a name.
  ///
  /// Timer_map also keeps track of the number of measures each timer
  /// has performed.
  class timer_map
  {
  public:

    /// \brief Start a timer with name \a name.
    ///
    /// The timer is created if it did not exist already.
    /// Once started, a timer should be either stop()ed or
    /// cancel()ed.
    void
    start(const std::string& name)
    {
      item_type& it = tm[name];
      it.first.start();
      ++it.second;
    }

    /// \brief Stop timer \a name.
    ///
    /// The timer must have been previously started with start().
    void
    stop(const std::string& name)
    {
      tm[name].first.stop();
    }

    /// \brief Cancel timer \a name.
    ///
    /// The timer must have been previously started with start().
    ///
    /// This cancel only the current measure.  (Previous measures
    /// recorded by the timer are preserved.)  When a timer that has
    /// not done any measure is canceled, it is removed from the map.
    void
    cancel(const std::string& name)
    {
      tm_type::iterator i = tm.find(name);
248
249
250
      if (SPOT_UNLIKELY(i == tm.end()))
        throw std::invalid_argument("timer_map::cancel(): unknown name");
      SPOT_ASSERT(0 < i->second.second);
251
      if (0 == --i->second.second)
252
        tm.erase(i);
253
254
255
256
257
258
259
    }

    /// Return the timer \a name.
    const spot::timer&
    timer(const std::string& name) const
    {
      tm_type::const_iterator i = tm.find(name);
260
261
      if (SPOT_UNLIKELY(i == tm.end()))
        throw std::invalid_argument("timer_map::timer(): unknown name");
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
      return i->second.first;
    }

    /// \brief Whether there is no timer in the map.
    ///
    /// If empty() return true, then either no timer where ever
    /// started, or all started timers were canceled without
    /// completing any measure.
    bool
    empty() const
    {
      return tm.empty();
    }

    /// Format information about all timers in a table.
277
    SPOT_API std::ostream&
278
279
    print(std::ostream& os) const;

280
281
282
283
284
285
286
    /// \brief Remove information about all timers.
    void
    reset_all()
    {
      tm.clear();
    }

287
288
289
290
291
292
  protected:
    typedef std::pair<spot::timer, int> item_type;
    typedef std::map<std::string, item_type> tm_type;
    tm_type tm;
  };

Clément Gillard's avatar
Clément Gillard committed
293
  /// \brief Struct used to start and stop both timer and stopwatch clocks.
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
  typedef struct process_timer
  {
    void start()
    {
      walltimer.start();
      cputimer.start();
    }
    // sw.stop() --> It always returns the duration since the last call to
    // start(). Therefore, it wont't stop timing, moreover, it can be called
    // multiple times.
    void stop()
    {
      walltime_lap_ = walltimer.stop();
      cputimer.stop();
    }

    double walltime() const
    {
      return walltime_lap_;
    }

    clock_t cputime(bool user, bool system, bool children, bool parent) const
    {
      return cputimer.get_uscp(user, system, children, parent);
    }

  private:
    spot::timer cputimer;
    spot::stopwatch walltimer;
    double walltime_lap_ = 0;
  } process_timer;

326
327
  /// @}
}