1 /*
2 * Copyright (C) 2014 Tim Mayberry <mojofunk@gmail.com>
3 * Copyright (C) 2015 Robin Gareus <robin@gareus.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "timers.h"
21
22 #include "pbd/timer.h"
23 #include "pbd/debug.h"
24 #include "pbd/compose.h"
25 #include "pbd/g_atomic_compat.h"
26
27 #include "debug.h"
28
29 namespace {
30
31 class StandardTimer : public PBD::StandardTimer
32 {
33 public:
StandardTimer(unsigned int interval)34 StandardTimer (unsigned int interval)
35 : PBD::StandardTimer(interval)
36 { }
37
on_elapsed()38 virtual bool on_elapsed () {
39 DEBUG_TIMING_ADD_ELAPSED(PBD::DEBUG::GUITiming, timing_interval_data);
40 DEBUG_TIMING_START(PBD::DEBUG::GUITiming, timing_exec_data);
41
42 bool ret_val = PBD::StandardTimer::on_elapsed ();
43
44 DEBUG_TIMING_ADD_ELAPSED(PBD::DEBUG::GUITiming, timing_exec_data);
45 DEBUG_TIMING_START(PBD::DEBUG::GUITiming, timing_interval_data);
46 return ret_val;
47 }
48
49 #ifndef NDEBUG
50 PBD::TimingData timing_interval_data;
51 PBD::TimingData timing_exec_data;
52 #endif
53 };
54
55 class BlinkTimer : public PBD::BlinkTimer
56 {
57 public:
BlinkTimer(unsigned int interval)58 BlinkTimer (unsigned int interval)
59 : PBD::BlinkTimer(interval)
60 { }
61
on_elapsed()62 virtual bool on_elapsed () {
63 DEBUG_TIMING_ADD_ELAPSED(PBD::DEBUG::GUITiming, timing_interval_data);
64 DEBUG_TIMING_START(PBD::DEBUG::GUITiming, timing_exec_data);
65
66 bool ret_val = PBD::BlinkTimer::on_elapsed ();
67
68 DEBUG_TIMING_ADD_ELAPSED(PBD::DEBUG::GUITiming, timing_exec_data);
69 DEBUG_TIMING_START(PBD::DEBUG::GUITiming, timing_interval_data);
70 return ret_val;
71 }
72
73 #ifndef NDEBUG
74 PBD::TimingData timing_interval_data;
75 PBD::TimingData timing_exec_data;
76 #endif
77 };
78
79
80 class UITimers
81 {
82
83 public:
84
UITimers()85 UITimers ()
86 : blink(240)
87 , second(1000)
88 , rapid(100)
89 , super_rapid(40)
90 , fps(40)
91 {
92 g_atomic_int_set (&_suspend_counter, 0);
93 #ifndef NDEBUG
94 second.connect (sigc::mem_fun (*this, &UITimers::on_second_timer));
95 #endif
96 }
97
98 BlinkTimer blink;
99 StandardTimer second;
100 StandardTimer rapid;
101 StandardTimer super_rapid;
102 StandardTimer fps;
103
104 GATOMIC_QUAL gint _suspend_counter;
105
106 #ifndef NDEBUG
107 std::vector<int64_t> rapid_eps_count;
108 std::vector<int64_t> super_rapid_eps_count;
109 std::vector<int64_t> fps_eps_count;
110
111 private:
112
debug_rapid_timer()113 void debug_rapid_timer () {
114 DEBUG_TRACE(PBD::DEBUG::GUITiming, string_compose ("Rapid Connections: %1\n", rapid.connection_count ()));
115
116 rapid_eps_count.push_back (rapid.timing_exec_data.size());
117
118 DEBUG_TRACE(PBD::DEBUG::GUITiming, string_compose ("Rapid Exec Totals: %1", PBD::timing_summary (rapid_eps_count)));
119
120 DEBUG_TRACE(PBD::DEBUG::GUITiming, string_compose ("Rapid Interval: %1", rapid.timing_interval_data.summary()));
121 DEBUG_TRACE(PBD::DEBUG::GUITiming, string_compose ("Rapid Exec: %1", rapid.timing_exec_data.summary()));
122 DEBUG_TIMING_RESET(PBD::DEBUG::GUITiming, rapid.timing_interval_data);
123 DEBUG_TIMING_RESET(PBD::DEBUG::GUITiming, rapid.timing_exec_data);
124 }
125
debug_super_rapid_timer()126 void debug_super_rapid_timer () {
127 // we don't use this timer on windows so don't display empty data for it
128 #ifndef PLATFORM_WINDOWS
129
130 DEBUG_TRACE(PBD::DEBUG::GUITiming, string_compose ("Super Rapid Connections: %1\n", super_rapid.connection_count ()));
131
132 super_rapid_eps_count.push_back (super_rapid.timing_exec_data.size());
133
134 DEBUG_TRACE(PBD::DEBUG::GUITiming, string_compose ("Super Rapid Exec Totals: %1", PBD::timing_summary (super_rapid_eps_count)));
135 DEBUG_TRACE(PBD::DEBUG::GUITiming, string_compose ("Super Rapid Interval: %1", super_rapid.timing_interval_data.summary()));
136 DEBUG_TRACE(PBD::DEBUG::GUITiming, string_compose ("Super Rapid Exec: %1", super_rapid.timing_exec_data.summary()));
137 DEBUG_TIMING_RESET(PBD::DEBUG::GUITiming, super_rapid.timing_interval_data);
138 DEBUG_TIMING_RESET(PBD::DEBUG::GUITiming, super_rapid.timing_exec_data);
139 #endif
140 }
141
debug_fps_timer()142 void debug_fps_timer () {
143 DEBUG_TRACE(PBD::DEBUG::GUITiming, string_compose ("FPS Connections: %1\n", fps.connection_count ()));
144
145 fps_eps_count.push_back (fps.timing_exec_data.size());
146
147 DEBUG_TRACE(PBD::DEBUG::GUITiming, string_compose ("FPS Exec Totals: %1", PBD::timing_summary (fps_eps_count)));
148
149 DEBUG_TRACE(PBD::DEBUG::GUITiming, string_compose ("FPS Interval: %1", fps.timing_interval_data.summary()));
150 DEBUG_TRACE(PBD::DEBUG::GUITiming, string_compose ("FPS Exec: %1", fps.timing_exec_data.summary()));
151 DEBUG_TIMING_RESET(PBD::DEBUG::GUITiming, fps.timing_interval_data);
152 DEBUG_TIMING_RESET(PBD::DEBUG::GUITiming, fps.timing_exec_data);
153 }
154
on_second_timer()155 void on_second_timer () {
156 debug_rapid_timer ();
157 debug_super_rapid_timer ();
158 debug_fps_timer ();
159 }
160 #endif
161 };
162
163 UITimers&
get_timers()164 get_timers ()
165 {
166 static UITimers timers;
167 return timers;
168 }
169
170 } // anon namespace
171
172 namespace Timers {
173
174 sigc::connection
blink_connect(const sigc::slot<void,bool> & slot)175 blink_connect(const sigc::slot<void,bool>& slot)
176 {
177 return get_timers().blink.connect (slot);
178 }
179
180 sigc::connection
second_connect(const sigc::slot<void> & slot)181 second_connect(const sigc::slot<void>& slot)
182 {
183 return get_timers().second.connect (slot);
184 }
185
186 sigc::connection
rapid_connect(const sigc::slot<void> & slot)187 rapid_connect(const sigc::slot<void>& slot)
188 {
189 return get_timers().rapid.connect (slot);
190 }
191
192 sigc::connection
super_rapid_connect(const sigc::slot<void> & slot)193 super_rapid_connect(const sigc::slot<void>& slot)
194 {
195 #ifdef PLATFORM_WINDOWS
196 return get_timers().fps.connect (slot);
197 #else
198 return get_timers().super_rapid.connect (slot);
199 #endif
200 }
201
202 void
set_fps_interval(unsigned int interval)203 set_fps_interval (unsigned int interval)
204 {
205 get_timers().fps.set_interval (interval);
206 }
207
208 sigc::connection
fps_connect(const sigc::slot<void> & slot)209 fps_connect(const sigc::slot<void>& slot)
210 {
211 return get_timers().fps.connect (slot);
212 }
213
TimerSuspender()214 TimerSuspender::TimerSuspender ()
215 {
216 if (g_atomic_int_add (&get_timers()._suspend_counter, 1) == 0) {
217 get_timers().rapid.suspend();
218 get_timers().super_rapid.suspend();
219 get_timers().fps.suspend();
220 }
221 }
222
~TimerSuspender()223 TimerSuspender::~TimerSuspender ()
224 {
225 if (g_atomic_int_dec_and_test (&get_timers()._suspend_counter)) {
226 get_timers().rapid.resume();
227 get_timers().super_rapid.resume();
228 get_timers().fps.resume();
229 }
230 }
231
232 } // namespace Timers
233