Use XMLNode::set_property in PBD::PropertyTemplate<T> class
[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         /// @return Elapsed time in microseconds
97         uint64_t elapsed () const {
98                 return m_last_val - m_start_val;
99         }
100
101         /// @return Elapsed time in milliseconds
102         uint64_t elapsed_msecs () const {
103                 return elapsed () / 1000;
104         }
105
106 private:
107
108         uint64_t m_start_val;
109         uint64_t m_last_val;
110
111 };
112
113 class LIBPBD_API TimingData
114 {
115 public:
116         TimingData () : m_reserve_size(256)
117         { reset (); }
118
119         void start_timing () {
120                 m_timing.start ();
121         }
122
123         void add_elapsed () {
124                 m_timing.update ();
125                 if (m_timing.valid()) {
126                         m_elapsed_values.push_back (m_timing.elapsed());
127                 }
128         }
129
130         void add_interval () {
131                 uint64_t interval = m_timing.get_interval ();
132                 m_elapsed_values.push_back (interval);
133         }
134
135         void reset () {
136                 m_elapsed_values.clear ();
137                 m_elapsed_values.reserve (m_reserve_size);
138         }
139
140         std::string summary () const
141         { return timing_summary (m_elapsed_values); }
142
143         bool get_min_max_avg_total (uint64_t& min,
144                                     uint64_t& max,
145                                     uint64_t& avg,
146                                     uint64_t& total) const
147         { return PBD::get_min_max_avg_total (m_elapsed_values, min, max, avg, total); }
148
149         void reserve (uint32_t reserve_size)
150         { m_reserve_size = reserve_size; reset (); }
151
152         uint32_t size () const
153         { return m_elapsed_values.size(); }
154
155 private:
156
157         Timing m_timing;
158
159         uint32_t m_reserve_size;
160
161         std::vector<uint64_t> m_elapsed_values;
162 };
163
164 class LIBPBD_API Timed
165 {
166 public:
167         Timed (TimingData& data)
168                 : m_data(data)
169         {
170                 m_data.start_timing ();
171         }
172
173         ~Timed ()
174         {
175                 m_data.add_elapsed ();
176         }
177
178 private:
179
180         TimingData& m_data;
181
182 };
183
184 } // namespace PBD
185
186 #endif // __libpbd_timing_h__