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