Optimize automation-event process splitting
[ardour.git] / gtk2_ardour / idleometer.cc
1 /*
2  * Copyright (C) 2076 Robin Gareus <robin@gareus.org>
3  * Copyright (C) 2011 Paul Davis
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (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
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  */
19
20 #include <glib.h>
21 #include <gtkmm/button.h>
22 #include <gtkmm/table.h>
23
24 #ifdef PLATFORM_WINDOWS
25 #include <pbd/windows_timer_utils.h>
26 #endif
27
28 #include "temporal/time.h"
29
30 #include "idleometer.h"
31 #include "pbd/i18n.h"
32
33 static int64_t _x_get_monotonic_usec() {
34 #ifdef PLATFORM_WINDOWS
35         return PBD::get_microseconds();
36 #endif
37         return g_get_monotonic_time();
38 }
39
40 using namespace Gtk;
41
42 IdleOMeter::IdleOMeter ()
43         : ArdourDialog (_("Idle O Meter"))
44 {
45         get_vbox()->set_spacing (8);
46         Label* l = manage (new Label (_("<b>GUI Idle Timing Statistics</b>"), ALIGN_CENTER));
47         l->set_use_markup ();
48
49         HBox* hbox = manage (new HBox ());
50         Table* t = manage (new Table ());
51         hbox->pack_start (*t, true, false);
52
53         Button* b = manage (new Button (_("Reset")));
54         b->signal_clicked().connect (sigc::mem_fun(*this, &IdleOMeter::reset));
55
56         get_vbox()->pack_start (*l, false, false);
57         get_vbox()->pack_start (*hbox, false, false);
58         get_vbox()->pack_start (*b, false, false);
59
60         _label_cur.set_alignment (ALIGN_RIGHT, ALIGN_CENTER);
61         _label_min.set_alignment (ALIGN_RIGHT, ALIGN_CENTER);
62         _label_max.set_alignment (ALIGN_RIGHT, ALIGN_CENTER);
63         _label_avg.set_alignment (ALIGN_RIGHT, ALIGN_CENTER);
64         _label_dev.set_alignment (ALIGN_RIGHT, ALIGN_CENTER);
65         _label_acq.set_alignment (ALIGN_CENTER, ALIGN_CENTER);
66
67         int row = 0;
68         t->attach (*manage (new Label (_("Current:"), ALIGN_RIGHT)), 0, 1, row, row + 1, FILL, SHRINK);
69         t->attach (_label_cur, 1, 2, row, row + 1, FILL, SHRINK);
70         ++row;
71         t->attach (*manage (new Label (_("Min:"),     ALIGN_RIGHT)), 0, 1, row, row + 1, FILL, SHRINK);
72         t->attach (_label_min, 1, 2, row, row + 1, FILL, SHRINK);
73         ++row;
74         t->attach (*manage (new Label (_("Max:"),     ALIGN_RIGHT)), 0, 1, row, row + 1, FILL, SHRINK);
75         t->attach (_label_max, 1, 2, row, row + 1, FILL, SHRINK);
76         ++row;
77         t->attach (*manage (new Label (_("Mean:"),    ALIGN_RIGHT)), 0, 1, row, row + 1, FILL, SHRINK);
78         t->attach (_label_avg, 1, 2, row, row + 1, FILL, SHRINK);
79         ++row;
80         t->attach (*manage (new Label (_("\u03c3:"),  ALIGN_RIGHT)), 0, 1, row, row + 1, FILL, SHRINK);
81         t->attach (_label_dev, 1, 2, row, row + 1, FILL, SHRINK);
82         ++row;
83         t->attach (*manage (new Label (_("Elapsed:"),  ALIGN_RIGHT)), 0, 1, row, row + 1, FILL, SHRINK);
84         t->attach (_label_acq, 1, 2, row, row + 1, FILL, SHRINK);
85 }
86
87 IdleOMeter::~IdleOMeter ()
88 {
89         _idle_connection.disconnect ();
90 }
91
92 bool
93 IdleOMeter::idle ()
94 {
95         const int64_t now = _x_get_monotonic_usec ();
96         const int64_t elapsed = now - _last;
97
98         _max = std::max (_max, elapsed);
99         _min = std::min (_min, elapsed);
100         _last = now;
101         _total += elapsed;
102         ++_cnt;
103
104         const double cnt = _cnt;
105
106         /* running variance */
107         if (_cnt <= 1) {
108                 _var_m = elapsed;
109                 _var_s = 0;
110         } else {
111                 const double var_m1 = _var_m;
112                 const double t = elapsed;
113                 _var_m += (t - _var_m) / cnt;
114                 _var_s += (t - _var_m) * (t - var_m1);
115         }
116
117         if (now - _last_display < 100000 || _cnt < 2) {
118                 return true;
119         }
120
121         const double avg = _total / cnt;
122         const double stddev = sqrt (_var_s / (_cnt - 1.0));
123         _last_display = now;
124
125         char buf[128];
126
127         snprintf (buf, sizeof(buf), "%8.2f ms", elapsed / 1000.0);
128         _label_cur.set_text (buf);
129         snprintf (buf, sizeof(buf), "%8.2f ms", _min / 1000.0);
130         _label_min.set_text (buf);
131         snprintf (buf, sizeof(buf), "%8.2f ms", _max / 1000.0);
132         _label_max.set_text (buf);
133         snprintf (buf, sizeof(buf), "%8.3f ms", avg / 1000.0);
134         _label_avg.set_text (buf);
135         snprintf (buf, sizeof(buf), "%8.3f ms", stddev / 1000.0);
136         _label_dev.set_text (buf);
137         _label_acq.set_text (Timecode::timecode_format_sampletime (now - _start, 1000000, 100, false));
138
139         return true;
140 }
141
142 void
143 IdleOMeter::reset ()
144 {
145         _last = _x_get_monotonic_usec ();
146         _last_display = _last;
147         _start = _last;
148         _max = 0;
149         _min = INT64_MAX;
150         _cnt = 0;
151         _total = _var_m = _var_s = 0;
152
153         _label_cur.set_text ("-");
154         _label_min.set_text ("-");
155         _label_max.set_text ("-");
156         _label_avg.set_text ("-");
157         _label_dev.set_text ("-");
158         _label_acq.set_text ("-");
159 }
160
161 void
162 IdleOMeter::on_show ()
163 {
164         ArdourDialog::on_show ();
165         reset ();
166         _idle_connection = Glib::signal_idle().connect (sigc::mem_fun (*this, &IdleOMeter::idle));
167 }
168
169 void
170 IdleOMeter::on_hide ()
171 {
172         _idle_connection.disconnect ();
173         ArdourDialog::on_hide ();
174 }