Tempo ramps - audio-locked meters have a bbt of 1|1|0
[ardour.git] / libs / pbd / pbd / timing.h
1 /*
2     Copyright (C) 2014 Tim Mayberry
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
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #ifndef __libpbd_timing_h__
21 #define __libpbd_timing_h__
22
23 #include <glib.h>
24
25 #include <stdint.h>
26
27 #include <string>
28 #include <vector>
29
30 #include "pbd/libpbd_visibility.h"
31
32 namespace PBD {
33
34 LIBPBD_API bool get_min_max_avg_total (const std::vector<uint64_t>& values, uint64_t& min, uint64_t& max, uint64_t& avg, uint64_t& total);
35
36 LIBPBD_API std::string timing_summary (const std::vector<uint64_t>& values);
37
38 /**
39  * This class allows collecting timing data using two different
40  * techniques. The first is using start() and update() and then
41  * calling elapsed() to get the elapsed time. This is useful when
42  * you want to measure the elapsed time between two different
43  * execution points. e.g
44  *
45  * timing.start();
46  * do_stuff();
47  * timing.update();
48  * cerr << "do_stuff took: "
49  *      << timing.elapsed()
50  *      << "usecs" << endl;
51  *
52  * The other is timing intervals using start() and calling
53  * get_interval() periodically to measure the time intervals
54  * between the same execution point. The difference is necessary
55  * to get the most accurate timing information when timing
56  * intervals but I didn't feel it necessary to have two separate
57  * classes.
58  */
59 class LIBPBD_API Timing
60 {
61 public:
62
63         Timing ()
64                 : m_start_val(0)
65                 , m_last_val(0)
66         { start ();}
67
68         bool valid () const {
69                 return (m_start_val != 0 && m_last_val != 0);
70         }
71
72         void start () {
73                 m_start_val = g_get_monotonic_time ();
74                 m_last_val = 0;
75         }
76
77         void update () {
78                 m_last_val = g_get_monotonic_time ();
79         }
80
81         void reset () {
82                 m_start_val = m_last_val = 0;
83         }
84
85         uint64_t get_interval () {
86                 uint64_t elapsed = 0;
87                 update ();
88                 if (valid()) {
89                         elapsed = m_last_val - m_start_val;
90                         m_start_val = m_last_val;
91                         m_last_val = 0;
92                 }
93                 return elapsed;
94         }
95
96         /// Elapsed time in microseconds
97         uint64_t elapsed () const {
98                 return m_last_val - m_start_val;
99         }
100
101 private:
102
103         uint64_t m_start_val;
104         uint64_t m_last_val;
105
106 };
107
108 class LIBPBD_API TimingData
109 {
110 public:
111         TimingData () : m_reserve_size(256)
112         { reset (); }
113
114         void start_timing () {
115                 m_timing.start ();
116         }
117
118         void add_elapsed () {
119                 m_timing.update ();
120                 if (m_timing.valid()) {
121                         m_elapsed_values.push_back (m_timing.elapsed());
122                 }
123         }
124
125         void add_interval () {
126                 uint64_t interval = m_timing.get_interval ();
127                 m_elapsed_values.push_back (interval);
128         }
129
130         void reset () {
131                 m_elapsed_values.clear ();
132                 m_elapsed_values.reserve (m_reserve_size);
133         }
134
135         std::string summary () const
136         { return timing_summary (m_elapsed_values); }
137
138         bool get_min_max_avg_total (uint64_t& min,
139                                     uint64_t& max,
140                                     uint64_t& avg,
141                                     uint64_t& total) const
142         { return PBD::get_min_max_avg_total (m_elapsed_values, min, max, avg, total); }
143
144         void reserve (uint32_t reserve_size)
145         { m_reserve_size = reserve_size; reset (); }
146
147         uint32_t size () const
148         { return m_elapsed_values.size(); }
149
150 private:
151
152         Timing m_timing;
153
154         uint32_t m_reserve_size;
155
156         std::vector<uint64_t> m_elapsed_values;
157 };
158
159 class LIBPBD_API Timed
160 {
161 public:
162         Timed (TimingData& data)
163                 : m_data(data)
164         {
165                 m_data.start_timing ();
166         }
167
168         ~Timed ()
169         {
170                 m_data.add_elapsed ();
171         }
172
173 private:
174
175         TimingData& m_data;
176
177 };
178
179 } // namespace PBD
180
181 #endif // __libpbd_timing_h__