Ardour  9.0-pre0-350-gf17a656217
timing.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014-2016 Tim Mayberry <mojofunk@gmail.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 #pragma once
20 
21 #include <glib.h>
22 
23 #include <stdint.h>
24 
25 #include <cmath>
26 #include <limits>
27 #include <string>
28 #include <vector>
29 
30 #include "pbd/microseconds.h"
31 #include "pbd/libpbd_visibility.h"
32 
33 #ifdef COMPILER_MSVC
34 #undef min
35 #undef max
36 #endif
37 
38 namespace PBD {
39 
40 LIBPBD_API bool get_min_max_avg_total (const std::vector<microseconds_t>& values, microseconds_t& min, microseconds_t& max, microseconds_t& avg, microseconds_t& total);
41 
42 LIBPBD_API std::string timing_summary (const std::vector<microseconds_t>& values);
43 
66 {
67 public:
68 
69  Timing ()
70  : m_start_val(0)
71  , m_last_val(0)
72  { start ();}
73 
74  bool valid () const {
75  return (m_start_val != 0 && m_last_val != 0);
76  }
77 
78  void start () {
79  m_start_val = PBD::get_microseconds ();
80  m_last_val = 0;
81  }
82 
83  void update () {
84  m_last_val = PBD::get_microseconds ();
85  }
86  void update (microseconds_t interval) {
87  m_start_val = 0;
88  m_last_val = interval;
89  }
90 
91  void reset () {
92  m_start_val = m_last_val = 0;
93  }
94 
96  microseconds_t elapsed = 0;
97  update ();
98  if (valid()) {
99  elapsed = m_last_val - m_start_val;
100  m_start_val = m_last_val;
101  m_last_val = 0;
102  }
103  return elapsed;
104  }
105 
106  bool started() const { return m_start_val != 0; }
107 
110  return m_last_val - m_start_val;
111  }
112 
115  return elapsed () / 1000;
116  }
117 
118  microseconds_t start_time() const { return m_start_val; }
119  microseconds_t last_time() const { return m_last_val; }
120 
121  protected:
124 
125 };
126 
128 {
129 public:
131  {
132  /* override implicit Timing::start () */
133  reset ();
134  }
135 
136  void update ()
137  {
138  if (_queue_reset) {
139  reset ();
140  } else {
141  Timing::update ();
142 
143  /* On Windows, querying the performance counter can fail occasionally (-1).
144  * Also on some multi-core systems, timers are CPU specific and not
145  * synchronized. The query can also fail, which will
146  * result in a value of zero, which is essentially impossible.
147  */
148 
149  if (m_start_val <= 0 || m_last_val <= 0 || m_start_val > m_last_val) {
150  return;
151  }
152 
153  calc ();
154  }
155  }
156 
157  void queue_reset () {
158  _queue_reset = true;
159  }
160 
161  void reset ()
162  {
163  _queue_reset = 0;
164  Timing::reset ();
165  _min = std::numeric_limits<microseconds_t>::max();
166  _max = 0;
167  _cnt = 0;
168  _avg = 0.;
169  _vm = 0.;
170  _vs = 0.;
171  }
172 
173  bool valid () const {
174  return Timing::valid () && _cnt > 1;
175  }
176 
178  microseconds_t& max,
179  double& avg,
180  double& dev) const
181  {
182  if (_cnt < 2) {
183  return false;
184  }
185  min = _min;
186  max = _max;
187  avg = _avg / (double)_cnt;
188  dev = sqrt (_vs / ((double) _cnt - 1.0));
189  return true;
190  }
191 
192 private:
193  void calc ()
194  {
195  const microseconds_t diff = elapsed ();
196 
197  _avg += (double) diff;
198 
199  if (diff > _max) {
200  _max = diff;
201  }
202  if (diff < _min) {
203  _min = diff;
204  }
205 
206  if (_cnt == 0) {
207  _vm = (double) diff;
208  } else {
209  const double ela = (double) diff;
210  const double var_m1 = _vm;
211  _vm = _vm + (ela - _vm) / (1.0 + (double) _cnt);
212  _vs = _vs + (ela - _vm) * (ela - var_m1);
213  }
214  ++_cnt;
215  }
216 
220  double _avg;
221  double _vm;
222  double _vs;
224 };
225 
231 {
232  public:
233  TimerRAII (TimingStats& ts, bool dbg = false) : stats (ts) { stats.start(); }
234  ~TimerRAII() { stats.update(); }
236 };
237 
245 {
246  public:
247  WaitTimerRAII (TimingStats& ts) : stats (ts) { if (stats.started()) { stats.update(); } }
248  ~WaitTimerRAII() { stats.start(); }
250 };
251 
253 {
254 public:
255  TimingData () : m_reserve_size(256)
256  { reset (); }
257 
258  void start_timing () {
259  m_timing.start ();
260  }
261 
262  void add_elapsed () {
263  m_timing.update ();
264  if (m_timing.valid()) {
265  m_elapsed_values.push_back (m_timing.elapsed());
266  }
267  }
268 
269  void add_interval () {
270  microseconds_t interval = m_timing.get_interval ();
271  m_elapsed_values.push_back (interval);
272  }
273 
274  void reset () {
275  m_elapsed_values.clear ();
276  m_elapsed_values.reserve (m_reserve_size);
277  }
278 
279  std::string summary () const
280  { return timing_summary (m_elapsed_values); }
281 
283  microseconds_t& max,
284  microseconds_t& avg,
285  microseconds_t& total) const
286  { return PBD::get_min_max_avg_total (m_elapsed_values, min, max, avg, total); }
287 
288  void reserve (uint32_t reserve_size)
289  { m_reserve_size = reserve_size; reset (); }
290 
291  std::vector<microseconds_t>::size_type size () const
292  { return m_elapsed_values.size(); }
293 
294 private:
295 
297 
298  uint32_t m_reserve_size;
299 
300  std::vector<microseconds_t> m_elapsed_values;
301 };
302 
304 {
305 public:
307  : m_data(data)
308  {
309  m_data.start_timing ();
310  }
311 
313  {
314  m_data.add_elapsed ();
315  }
316 
317 private:
318 
320 
321 };
322 
323 } // namespace PBD
324 
~Timed()
Definition: timing.h:312
Timed(TimingData &data)
Definition: timing.h:306
TimingData & m_data
Definition: timing.h:319
TimerRAII(TimingStats &ts, bool dbg=false)
Definition: timing.h:233
TimingStats & stats
Definition: timing.h:235
Timing m_timing
Definition: timing.h:296
void start_timing()
Definition: timing.h:258
std::vector< microseconds_t >::size_type size() const
Definition: timing.h:291
void add_elapsed()
Definition: timing.h:262
uint32_t m_reserve_size
Definition: timing.h:298
void add_interval()
Definition: timing.h:269
bool get_min_max_avg_total(microseconds_t &min, microseconds_t &max, microseconds_t &avg, microseconds_t &total) const
Definition: timing.h:282
std::string summary() const
Definition: timing.h:279
void reset()
Definition: timing.h:274
std::vector< microseconds_t > m_elapsed_values
Definition: timing.h:300
void reserve(uint32_t reserve_size)
Definition: timing.h:288
microseconds_t _cnt
Definition: timing.h:217
microseconds_t _max
Definition: timing.h:219
void update()
Definition: timing.h:136
double _vm
Definition: timing.h:221
double _avg
Definition: timing.h:220
int _queue_reset
Definition: timing.h:223
bool get_stats(microseconds_t &min, microseconds_t &max, double &avg, double &dev) const
Definition: timing.h:177
bool valid() const
Definition: timing.h:173
microseconds_t _min
Definition: timing.h:218
void reset()
Definition: timing.h:161
void queue_reset()
Definition: timing.h:157
double _vs
Definition: timing.h:222
void calc()
Definition: timing.h:193
bool valid() const
Definition: timing.h:74
Timing()
Definition: timing.h:69
void update(microseconds_t interval)
Definition: timing.h:86
bool started() const
Definition: timing.h:106
void start()
Definition: timing.h:78
void update()
Definition: timing.h:83
microseconds_t elapsed() const
Definition: timing.h:109
microseconds_t start_time() const
Definition: timing.h:118
microseconds_t m_last_val
Definition: timing.h:123
void reset()
Definition: timing.h:91
microseconds_t m_start_val
Definition: timing.h:122
microseconds_t elapsed_msecs() const
Definition: timing.h:114
microseconds_t get_interval()
Definition: timing.h:95
microseconds_t last_time() const
Definition: timing.h:119
WaitTimerRAII(TimingStats &ts)
Definition: timing.h:247
TimingStats & stats
Definition: timing.h:249
#define LIBPBD_API
PBD::PropertyDescriptor< timepos_t > start
Definition: axis_view.h:42
bool get_min_max_avg_total(const std::vector< microseconds_t > &values, microseconds_t &min, microseconds_t &max, microseconds_t &avg, microseconds_t &total)
int64_t microseconds_t
Definition: microseconds.h:28
microseconds_t get_microseconds()
std::string timing_summary(const std::vector< microseconds_t > &values)