amend c9b1e6dbe
[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 #include "timecode/time.h"
25
26 #include "idleometer.h"
27 #include "pbd/i18n.h"
28
29 static int64_t _x_get_monotonic_usec() {
30 #ifdef PLATFORM_WINDOWS
31         return PBD::get_microseconds();
32 #endif
33         return g_get_monotonic_time();
34 }
35
36 using namespace Gtk;
37
38 IdleOMeter::IdleOMeter ()
39         : ArdourDialog (_("Idle O Meter"))
40 {
41         get_vbox()->set_spacing (8);
42         Label* l = manage (new Label (_("<b>GUI Idle Timing Statistics</b>"), ALIGN_CENTER));
43         l->set_use_markup ();
44
45         HBox* hbox = manage (new HBox ());
46         Table* t = manage (new Table ());
47         hbox->pack_start (*t, true, false);
48
49         Button* b = manage (new Button (_("Reset")));
50         b->signal_clicked().connect (sigc::mem_fun(*this, &IdleOMeter::reset));
51
52         get_vbox()->pack_start (*l, false, false);
53         get_vbox()->pack_start (*hbox, false, false);
54         get_vbox()->pack_start (*b, false, false);
55
56         _label_cur.set_alignment (ALIGN_RIGHT, ALIGN_CENTER);
57         _label_min.set_alignment (ALIGN_RIGHT, ALIGN_CENTER);
58         _label_max.set_alignment (ALIGN_RIGHT, ALIGN_CENTER);
59         _label_avg.set_alignment (ALIGN_RIGHT, ALIGN_CENTER);
60         _label_dev.set_alignment (ALIGN_RIGHT, ALIGN_CENTER);
61         _label_acq.set_alignment (ALIGN_CENTER, ALIGN_CENTER);
62
63         int row = 0;
64         t->attach (*manage (new Label (_("Current:"), ALIGN_RIGHT)), 0, 1, row, row + 1, FILL, SHRINK);
65         t->attach (_label_cur, 1, 2, row, row + 1, FILL, SHRINK);
66         ++row;
67         t->attach (*manage (new Label (_("Min:"),     ALIGN_RIGHT)), 0, 1, row, row + 1, FILL, SHRINK);
68         t->attach (_label_min, 1, 2, row, row + 1, FILL, SHRINK);
69         ++row;
70         t->attach (*manage (new Label (_("Max:"),     ALIGN_RIGHT)), 0, 1, row, row + 1, FILL, SHRINK);
71         t->attach (_label_max, 1, 2, row, row + 1, FILL, SHRINK);
72         ++row;
73         t->attach (*manage (new Label (_("Mean:"),    ALIGN_RIGHT)), 0, 1, row, row + 1, FILL, SHRINK);
74         t->attach (_label_avg, 1, 2, row, row + 1, FILL, SHRINK);
75         ++row;
76         t->attach (*manage (new Label (_("\u03c3:"),  ALIGN_RIGHT)), 0, 1, row, row + 1, FILL, SHRINK);
77         t->attach (_label_dev, 1, 2, row, row + 1, FILL, SHRINK);
78         ++row;
79         t->attach (*manage (new Label (_("Elapsed:"),  ALIGN_RIGHT)), 0, 1, row, row + 1, FILL, SHRINK);
80         t->attach (_label_acq, 1, 2, row, row + 1, FILL, SHRINK);
81 }
82
83 IdleOMeter::~IdleOMeter ()
84 {
85         _idle_connection.disconnect ();
86 }
87
88 bool
89 IdleOMeter::idle ()
90 {
91         const int64_t now = _x_get_monotonic_usec ();
92         const int64_t elapsed = now - _last;
93
94         _max = std::max (_max, elapsed);
95         _min = std::min (_min, elapsed);
96         _last = now;
97         _total += elapsed;
98         ++_cnt;
99
100         const double cnt = _cnt;
101
102         /* running variance */
103         if (_cnt <= 1) {
104                 _var_m = elapsed;
105                 _var_s = 0;
106         } else {
107                 const double var_m1 = _var_m;
108                 const double t = elapsed;
109                 _var_m += (t - _var_m) / cnt;
110                 _var_s += (t - _var_m) * (t - var_m1);
111         }
112
113         if (now - _last_display < 100000 || _cnt < 2) {
114                 return true;
115         }
116
117         const double avg = _total / cnt;
118         const double stddev = sqrt (_var_s / (_cnt - 1.0));
119         _last_display = now;
120
121         char buf[128];
122
123         snprintf (buf, sizeof(buf), "%8.2f ms", elapsed / 1000.0);
124         _label_cur.set_text (buf);
125         snprintf (buf, sizeof(buf), "%8.2f ms", _min / 1000.0);
126         _label_min.set_text (buf);
127         snprintf (buf, sizeof(buf), "%8.2f ms", _max / 1000.0);
128         _label_max.set_text (buf);
129         snprintf (buf, sizeof(buf), "%8.3f ms", avg / 1000.0);
130         _label_avg.set_text (buf);
131         snprintf (buf, sizeof(buf), "%8.3f ms", stddev / 1000.0);
132         _label_dev.set_text (buf);
133         _label_acq.set_text (Timecode::timecode_format_sampletime (now - _start, 1000000, 100, false));
134
135         return true;
136 }
137
138 void
139 IdleOMeter::reset ()
140 {
141         _last = _x_get_monotonic_usec ();
142         _last_display = _last;
143         _start = _last;
144         _max = 0;
145         _min = INT64_MAX;
146         _cnt = 0;
147         _total = _var_m = _var_s = 0;
148
149         _label_cur.set_text ("-");
150         _label_min.set_text ("-");
151         _label_max.set_text ("-");
152         _label_avg.set_text ("-");
153         _label_dev.set_text ("-");
154         _label_acq.set_text ("-");
155 }
156
157 void
158 IdleOMeter::on_show ()
159 {
160         ArdourDialog::on_show ();
161         reset ();
162         _idle_connection = Glib::signal_idle().connect (sigc::mem_fun (*this, &IdleOMeter::idle));
163 }
164
165 void
166 IdleOMeter::on_hide ()
167 {
168         _idle_connection.disconnect ();
169         ArdourDialog::on_hide ();
170 }