@cryptotaxi247 / netdata-1 / commits / 4ea49292e

increased precision by using long double; rewrote charts width management; fixed race condition that were leaving charts un-updaded

Costa Tsaousis (ktsaou) committed Apr 2, 2014 at 22:26 UTC 4ea49292ed932512984a1e20a229b2e29829f593
3 files changed +105 -101
netdata.c
+34 -28
@@ -744,7 +744,7 @@ size_t rrd_stats_json(RRD_STATS *st, char *b, size_t length, size_t entries_to_s
744 size_t current_entry = st->current_entry;
745 size_t t, lt; // t = the current entry, lt = the lest entry of data
746 long count = st->entries; // count down of the entries examined so far
747 - int pad = 0; // align the entries when grouping values together
747 + long pad = 0; // align the entries when grouping values together
748
749 RRD_DIMENSION *rd;
750 size_t c = 0; // counter for dimension loops
@@ -767,8 +767,8 @@ size_t rrd_stats_json(RRD_STATS *st, char *b, size_t length, size_t entries_to_s
767 }
768
769 // temporary storage to keep track of group values and counts
770 - long long group_values[dimensions];
771 - long long group_counts[dimensions];
770 + long double group_values[dimensions];
771 + int group_counts[dimensions];
772 for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++)
773 group_values[c] = group_counts[c] = 0;
774
@@ -832,36 +832,37 @@ size_t rrd_stats_json(RRD_STATS *st, char *b, size_t length, size_t entries_to_s
832 }
833
834 // if we need a PCENT_OVER_TOTAL, calculate the totals for the current and the last
835 - long long total = 0, oldtotal = 0;
835 + long double total = 0, oldtotal = 0;
836 if(we_need_totals) {
837 for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
838 - total += rrd_stats_dimension_get(rd, t);
839 - oldtotal += rrd_stats_dimension_get(rd, lt);
838 + total += (long double)rrd_stats_dimension_get(rd, t);
839 + oldtotal += (long double)rrd_stats_dimension_get(rd, lt);
840 }
841 }
842
843 for( rd = st->dimensions, c = 0 ; rd && c < dimensions ; rd = rd->next, c++) {
844 - long long oldvalue, value; // temp variable for storing data values
844 + //long long oldvalue, value; // temp variable for storing data values
845 + long double oldvalue, value; // temp variable for storing data values
846
846 - value = rrd_stats_dimension_get(rd, t);
847 - oldvalue = rrd_stats_dimension_get(rd, lt);
847 + value = (long double)rrd_stats_dimension_get(rd, t);
848 + oldvalue = (long double)rrd_stats_dimension_get(rd, lt);
849
850 switch(rd->type) {
851 case RRD_DIMENSION_PCENT_OVER_TOTAL:
851 - value = 100 * (value - oldvalue) / (total - oldtotal);
852 + value = (long double)100 * (value - oldvalue) / (total - oldtotal);
853 break;
854
855 case RRD_DIMENSION_INCREMENTAL:
856 if(oldvalue > value) value = 0; // detect overflows and resets
857 else value -= oldvalue;
857 - value = value * 1000000L / usec;
858 + value = value * (long double)1000000L / (long double)usec;
859 break;
860
861 default:
862 break;
863 }
864
864 - value = value * rd->multiplier / rd->divisor;
865 + value = value * (long double)rd->multiplier / (long double)rd->divisor;
866
867 group_counts[c]++;
868 switch(group_method) {
@@ -872,13 +873,14 @@ size_t rrd_stats_json(RRD_STATS *st, char *b, size_t length, size_t entries_to_s
873 default:
874 case GROUP_AVERAGE:
875 group_values[c] += value;
875 - if(((count-pad) % group_count) == 0) group_values[c] /= group_counts[c];
876 + if(((count - pad) % group_count) == 0) group_values[c] /= (long double)group_counts[c];
877 break;
878 }
879
880 if(((count-pad) % group_count) == 0) {
881 if(!rd->hidden)
881 - i += sprintf(&b[i], ",{\"v\":%lld}", group_values[c]);
882 + i += sprintf(&b[i], ",{\"v\":%0.1Lf}", group_values[c]);
883 + //i += sprintf(&b[i], ",{\"v\":%lld}", group_values[c]);
884
885 group_values[c] = group_counts[c] = 0;
886 }
@@ -2092,7 +2094,7 @@ int do_proc_net_snmp() {
2094 // see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
2095 RRD_STATS *st = rrd_stats_find(RRD_TYPE_NET_SNMP ".tcpsock");
2096 if(!st) {
2095 - st = rrd_stats_create(RRD_TYPE_NET_SNMP ".tcpsock", RRD_TYPE_NET_SNMP ".tcpsock", save_history, "IPv4 TCP Connections", "Connections", RRD_TYPE_NET_SNMP);
2097 + st = rrd_stats_create(RRD_TYPE_NET_SNMP ".tcpsock", RRD_TYPE_NET_SNMP ".tcpsock", save_history, "IPv4 TCP Connections", "tcp connections", RRD_TYPE_NET_SNMP);
2098 if(!st) {
2099 error("Cannot create RRD_STATS for %s.", RRD_TYPE_NET_SNMP ".tcpsock");
2100 continue;
@@ -2106,11 +2108,11 @@ int do_proc_net_snmp() {
2108 rrd_stats_dimension_set(st, "connections", &CurrEstab);
2109 rrd_stats_done(st);
2110
2109 - st = rrd_stats_find(RRD_TYPE_NET_SNMP ".tcp");
2111 + st = rrd_stats_find(RRD_TYPE_NET_SNMP ".tcppackets");
2112 if(!st) {
2111 - st = rrd_stats_create(RRD_TYPE_NET_SNMP ".tcp", RRD_TYPE_NET_SNMP ".tcp", save_history, "IPv4 TCP Packets", "Packets/s", RRD_TYPE_NET_SNMP);
2113 + st = rrd_stats_create(RRD_TYPE_NET_SNMP ".tcppackets", RRD_TYPE_NET_SNMP ".tcppackets", save_history, "IPv4 TCP Packets", "Packets/s", RRD_TYPE_NET_SNMP);
2114 if(!st) {
2113 - error("Cannot create RRD_STATS for %s.", RRD_TYPE_NET_SNMP ".tcp");
2115 + error("Cannot create RRD_STATS for %s.", RRD_TYPE_NET_SNMP ".tcppackets");
2116 continue;
2117 }
2118
@@ -2145,11 +2147,11 @@ int do_proc_net_snmp() {
2147 if(r != 6) error("Cannot read /proc/net/snmp UDP line. Expected 6 params, read %d.", r);
2148
2149 // see http://net-snmp.sourceforge.net/docs/mibs/udp.html
2148 - RRD_STATS *st = rrd_stats_find(RRD_TYPE_NET_SNMP ".udp");
2150 + RRD_STATS *st = rrd_stats_find(RRD_TYPE_NET_SNMP ".udppackets");
2151 if(!st) {
2150 - st = rrd_stats_create(RRD_TYPE_NET_SNMP ".udp", RRD_TYPE_NET_SNMP ".udp", save_history, "IPv4 UDP Packets", "Packets/s", RRD_TYPE_NET_SNMP);
2152 + st = rrd_stats_create(RRD_TYPE_NET_SNMP ".udppackets", RRD_TYPE_NET_SNMP ".udppackets", save_history, "IPv4 UDP Packets", "Packets/s", RRD_TYPE_NET_SNMP);
2153 if(!st) {
2152 - error("Cannot create RRD_STATS for %s.", RRD_TYPE_NET_SNMP ".udp");
2154 + error("Cannot create RRD_STATS for %s.", RRD_TYPE_NET_SNMP ".udppackets");
2155 continue;
2156 }
2157
@@ -2286,7 +2288,7 @@ int do_proc_net_stat_conntrack() {
2288
2289 RRD_STATS *st = rrd_stats_find(RRD_TYPE_NET_STAT_CONNTRACK ".sockets");
2290 if(!st) {
2289 - st = rrd_stats_create(RRD_TYPE_NET_STAT_CONNTRACK ".sockets", RRD_TYPE_NET_STAT_CONNTRACK ".sockets", save_history, "Netfilter Connections", "Connections", RRD_TYPE_NET_STAT_CONNTRACK);
2291 + st = rrd_stats_create(RRD_TYPE_NET_STAT_CONNTRACK ".sockets", RRD_TYPE_NET_STAT_CONNTRACK ".sockets", save_history, "Netfilter Connections", "netfilter connections", RRD_TYPE_NET_STAT_CONNTRACK);
2292 if(!st) {
2293 error("Cannot create RRD_STATS for %s.", RRD_TYPE_NET_STAT_CONNTRACK ".sockets");
2294 return 1;
@@ -2302,7 +2304,7 @@ int do_proc_net_stat_conntrack() {
2304
2305 st = rrd_stats_find(RRD_TYPE_NET_STAT_CONNTRACK ".new");
2306 if(!st) {
2305 - st = rrd_stats_create(RRD_TYPE_NET_STAT_CONNTRACK ".new", RRD_TYPE_NET_STAT_CONNTRACK ".new", save_history, "Netfilter New Connections", "Connections/s", RRD_TYPE_NET_STAT_CONNTRACK);
2307 + st = rrd_stats_create(RRD_TYPE_NET_STAT_CONNTRACK ".new", RRD_TYPE_NET_STAT_CONNTRACK ".new", save_history, "Netfilter New Connections", "connections/s", RRD_TYPE_NET_STAT_CONNTRACK);
2308 if(!st) {
2309 error("Cannot create RRD_STATS for %s.", RRD_TYPE_NET_STAT_CONNTRACK ".new");
2310 return 1;
@@ -2322,7 +2324,7 @@ int do_proc_net_stat_conntrack() {
2324
2325 st = rrd_stats_find(RRD_TYPE_NET_STAT_CONNTRACK ".changes");
2326 if(!st) {
2325 - st = rrd_stats_create(RRD_TYPE_NET_STAT_CONNTRACK ".changes", RRD_TYPE_NET_STAT_CONNTRACK ".changes", save_history, "Netfilter Connection Changes", "Connections/s", RRD_TYPE_NET_STAT_CONNTRACK);
2327 + st = rrd_stats_create(RRD_TYPE_NET_STAT_CONNTRACK ".changes", RRD_TYPE_NET_STAT_CONNTRACK ".changes", save_history, "Netfilter Connection Changes", "connections/s", RRD_TYPE_NET_STAT_CONNTRACK);
2328 if(!st) {
2329 error("Cannot create RRD_STATS for %s.", RRD_TYPE_NET_STAT_CONNTRACK ".changes");
2330 return 1;
@@ -2388,7 +2390,7 @@ int do_proc_net_ip_vs_stats() {
2390
2391 RRD_STATS *st = rrd_stats_find(RRD_TYPE_NET_IPVS ".sockets");
2392 if(!st) {
2391 - st = rrd_stats_create(RRD_TYPE_NET_IPVS ".sockets", RRD_TYPE_NET_IPVS ".sockets", save_history, "IPVS New Connections", "new connections", RRD_TYPE_NET_IPVS);
2393 + st = rrd_stats_create(RRD_TYPE_NET_IPVS ".sockets", RRD_TYPE_NET_IPVS ".sockets", save_history, "IPVS New Connections", "new connections/s", RRD_TYPE_NET_IPVS);
2394 if(!st) {
2395 error("Cannot create RRD_STATS for %s.", RRD_TYPE_NET_IPVS ".sockets");
2396 return 1;
@@ -2471,7 +2473,7 @@ int do_proc_stat() {
2473
2474 RRD_STATS *st = rrd_stats_find(id);
2475 if(!st) {
2474 - st = rrd_stats_create(id, id, save_history, "Time for ", "Percentage", RRD_TYPE_STAT);
2476 + st = rrd_stats_create(id, id, save_history, "Time for ", "percentage", RRD_TYPE_STAT);
2477 if(!st) {
2478 error("Cannot create RRD_STATS for %s.", id);
2479 continue;
@@ -2595,7 +2597,7 @@ int do_proc_stat() {
2597
2598 RRD_STATS *st = rrd_stats_find(id);
2599 if(!st) {
2598 - st = rrd_stats_create(id, id, save_history, "Started Processes", "processes started", RRD_TYPE_STAT);
2600 + st = rrd_stats_create(id, id, save_history, "Started Processes", "processes/s", RRD_TYPE_STAT);
2601 if(!st) {
2602 error("Cannot create RRD_STATS for %s.", id);
2603 continue;
@@ -3109,7 +3111,11 @@ int main(int argc, char **argv)
3111
3112 // never become a problem
3113 if(nice(20) == -1) {
3112 - fprintf(stderr, "Cannot lower my CPU priority. Error %s.\n", strerror(errno));
3114 + fprintf(stderr, "Cannot lower my CPU priority. Error: %s.\n", strerror(errno));
3115 + }
3116 +
3117 + if(sizeof(long long) >= sizeof(long double)) {
3118 + fprintf(stderr, "\n\nWARNING:\nThis system does not support [long double] variables properly.\nArithmetic overflows and rounding errors may occur.\n\n");
3119 }
3120
3121 if(daemon) become_daemon();
web/index.html
+48 -71
@@ -30,6 +30,10 @@
30 // Set a callback to run when the Google Visualization API is loaded.
31 google.setOnLoadCallback(initCharts);
32
33 + var TARGET_THUMB_GRAPH_WIDTH = 500; // chart width will range from 0.5 to 1.5 of that
34 + var MINIMUM_THUMB_GRAPH_WIDTH = 400; // chart will generally try to be wider than that
35 + var TARGET_THUMB_GRAPH_HEIGHT = 220;
36 +
37 var MODE_THUMBS = 1;
38 var MODE_MAIN = 2;
39 var mode; // one of the MODE_* values
@@ -49,7 +53,7 @@
53 mainchart = $.extend(true, {}, c);
54
55 mainchart.chart = null;
52 - mainchart.chartOptions.width = Math.round((($(window).width() * 0.95) - 50) / 1);
56 + mainchart.chartOptions.width = screenWidth();
57 mainchart.chartOptions.height = $(window).height() - 200;
58 if(mainchart.chartOptions.height < 300) mainchart.chartOptions.height = 300;
59
@@ -94,34 +98,34 @@
98 var now = new Date().getTime();
99
100 if((now - mainchart.last_updated) >= mainchart.chart_update_every) {
97 - refreshChart(mainchart, triggerMainChartRefresh);
101 + refreshChart(mainchart, triggerRefresh);
102 mainchart.last_updated = now;
103 }
100 - else triggerMainChartRefresh();
104 + else triggerRefresh();
105 }
106
103 - // callback for refreshing the main chart
104 - function triggerMainChartRefresh() {
105 - if(mode == MODE_MAIN) setTimeout(mainChartRefresh, 500);
107 + function screenWidth() {
108 + return (($(window).width() * 0.95) - 40);
109 }
110
111 // calculate the proper width for the thumb charts
112 function thumbWidth() {
110 - var items = Math.round((($(window).width() * 0.95) - 50) / 500);
113 + var cwidth = screenWidth();
114 + var items = Math.round(cwidth / TARGET_THUMB_GRAPH_WIDTH);
115 if(items < 1) items = 1;
116
113 - var width = Math.round((($(window).width() * 0.95) - 50) / items) - 1;
114 - //console.log("window = " + (($(window).width() * 0.95) - 50) + ", items = " + items + ", width = " + width);
117 + if(items > 1 && (cwidth / items) < MINIMUM_THUMB_GRAPH_WIDTH) items--;
118
116 - return width;
119 + return Math.round(cwidth / items) - 1;
120 }
121
122 // resize all charts
123 // if the thumb charts need resize in their width, reset them
124 function resizeCharts() {
122 - var width = Math.round((($(window).width() * 0.95) - 50) / 1);
125 + var width = screenWidth();
126 +
127 if(mainchart) {
124 - mainchart.chartOptions.width = Math.round((($(window).width() * 0.95) - 50) / 1);
128 + mainchart.chartOptions.width = width;
129 mainchart.chartOptions.height = $(window).height() - 200;
130 mainchart.last_updated = 0;
131 }
@@ -142,9 +146,7 @@
146 // generate html for the thumbgraphs to support them
147 function initCharts() {
148 var width = thumbWidth();
145 - var height = 200;
146 -
147 - document.getElementById('splash').height = $(window).height() * 0.95;
149 + var height = TARGET_THUMB_GRAPH_HEIGHT;
150
151 loadCharts(function(c) {
152 mycharts = c;
@@ -176,48 +178,6 @@
178 c.chartOptions.width = width;
179 c.chartOptions.height = height;
180
179 - switch(c.type) {
180 - case "tc":
181 - c.glyphicon = "glyphicon-transfer";
182 - c.group = 30;
183 - break;
184 -
185 - case "net":
186 - c.glyphicon = "glyphicon-cloud";
187 - c.group = 10;
188 - break;
189 -
190 - case "ipv4":
191 - c.glyphicon = "glyphicon-resize-full";
192 - c.group = 30;
193 - break;
194 -
195 - case "conntrack":
196 - c.glyphicon = "glyphicon-eye-open";
197 - c.group = 30;
198 - break;
199 -
200 - case "ipvs":
201 - c.glyphicon = "glyphicon-sort";
202 - c.group = 30;
203 - break;
204 -
205 - case "disk":
206 - c.glyphicon = "glyphicon-floppy-disk";
207 - c.group = 20;
208 - break;
209 -
210 - case "cpu":
211 - c.glyphicon = "glyphicon-search";
212 - c.group = 10;
213 - break;
214 -
215 - default:
216 - c.glyphicon = "glyphicon-search";
217 - c.group = 60;
218 - break;
219 - }
220 -
181 // calculate the time to refresh each chart
182 c.chart_update_every = c.group * 1000; // milliseconds
183
@@ -301,28 +261,43 @@
261
262 if($('#' + mycharts[last_mini].div).visible(true) == false) continue;
263
304 - refreshChart(mycharts[last_mini], triggerThumbChartsRefreshFast);
264 + refreshChart(mycharts[last_mini], chartsRefresh);
265 mycharts[last_mini].last_updated = now;
266
267 did++;
268 }
269
310 - if(did == 0) triggerThumbChartsRefresh();
270 + if(did == 0) triggerRefresh();
271 }
272
313 - function triggerThumbChartsRefresh() {
314 - setTimeout(thumbChartsRefresh, 200);
273 + // default thumbs charts refresh
274 + function thumbChartsRefresh() {
275 + thumbChartsRefreshInternal(1);
276 }
277
317 - function triggerThumbChartsRefreshFast() {
318 - thumbChartsRefresh();
319 - }
278 + // refresh the proper chart
279 + function chartsRefresh() {
280 + if(mode == MODE_THUMBS)
281 + thumbChartsRefresh();
282
321 - function thumbChartsRefresh() {
322 - if(mode == MODE_THUMBS) thumbChartsRefreshInternal(1);
283 + else if(mode == MODE_MAIN)
284 + mainChartRefresh();
285 +
286 + else
287 + setTimeout(triggerRefresh, 1000);
288 }
289
325 - // setInterval(myChartsRefresh, 500);
290 + // callback for refreshing the charts later
291 + function triggerRefresh() {
292 + if(mode == MODE_THUMBS)
293 + setTimeout(thumbChartsRefresh, 200);
294 +
295 + else if(mode == MODE_MAIN)
296 + setTimeout(mainChartRefresh, 500);
297 +
298 + else
299 + setTimeout(triggerRefresh, 1000);
300 + }
301
302 window.onresize = function(event) {
303 resizeCharts();
@@ -339,7 +314,7 @@
314 document.getElementById('maingraph_container').style.display = 'block';
315 document.getElementById('thumbgraphs_container').style.display = 'none';
316
342 - mainChartRefresh();
317 + chartsRefresh();
318 }
319
320 function showThumbGraphs() {
@@ -355,7 +330,7 @@
330 mainchart = null;
331 }
332
358 - thumbChartsRefresh(1);
333 + chartsRefresh();
334 }
335
336 </script>
@@ -403,12 +378,12 @@
378
379 <div class="container graphs" id="thumbgraphs_container">
380 <div class="allgraphs" id="thumbgraphs">
406 - <table width="100%" height="95%">
381 + <table width="100%">
382 <tr><td id="splash" align="center" style="vertical-align:middle">
383 <h1>
384 Welcome to <b>NetData</b>!
385 <br/><br/>
411 - <span class="glyphicon glyphicon-refresh"></span>
386 + <span class="glyphicon glyphicon-off"></span>
387 <br/><br/>
388 loading charts
389 <br/><br/>
@@ -418,4 +393,6 @@
393 </table>
394 </div>
395 </div>
396 +
397 + <script type="text/javascript">document.getElementById('splash').height = $(window).height();</script>
398 </html>
web/netdata.js
+23 -2
@@ -94,8 +94,8 @@ function loadCharts(doNext) {
94 json.charts[i].chartOptions = {
95 lineWidth: 2,
96 title: json.charts[i].title,
97 - hAxis: {title: "Time of Day"},
98 - vAxis: {title: json.charts[i].vtitle, minValue: 10},
97 + hAxis: {title: "Time of Day", viewWindowMode: 'maximized', format:'HH:mm:ss'},
98 + vAxis: {title: json.charts[i].vtitle, minValue: 0},
99 focusTarget: 'category',
100 };
101
@@ -138,14 +138,25 @@ function loadCharts(doNext) {
138 switch(json.charts[i].type) {
139 case "cpu":
140 json.charts[i].category = "CPU";
141 + json.charts[i].glyphicon = "glyphicon-dashboard";
142 + json.charts[i].group = 15;
143 +
144 + if(json.charts[i].id.substring(0, 7) == "cpu.cpu") {
145 + json.charts[i].chartOptions.vAxis.minValue = 0;
146 + json.charts[i].chartOptions.vAxis.maxValue = 100;
147 + }
148 break;
149
150 case "tc":
151 json.charts[i].category = "Quality of Service";
152 + json.charts[i].glyphicon = "glyphicon-random";
153 + json.charts[i].group = 30;
154 break;
155
156 case "net":
157 json.charts[i].category = "Network Interfaces";
158 + json.charts[i].glyphicon = "glyphicon-transfer";
159 + json.charts[i].group = 10;
160
161 // disable IFB and net.lo devices by default
162 if((json.charts[i].id.substring(json.charts[i].id.length - 4, json.charts[i].id.length) == "-ifb")
@@ -155,22 +166,32 @@ function loadCharts(doNext) {
166
167 case "ipv4":
168 json.charts[i].category = "IPv4";
169 + json.charts[i].glyphicon = "glyphicon-globe";
170 + json.charts[i].group = 20;
171 break;
172
173 case "conntrack":
174 json.charts[i].category = "Netfilter";
175 + json.charts[i].glyphicon = "glyphicon-cloud";
176 + json.charts[i].group = 20;
177 break;
178
179 case "ipvs":
180 json.charts[i].category = "IPVS";
181 + json.charts[i].glyphicon = "glyphicon-sort";
182 + json.charts[i].group = 15;
183 break;
184
185 case "disk":
186 json.charts[i].category = "Disk I/O";
187 + json.charts[i].glyphicon = "glyphicon-hdd";
188 + json.charts[i].group = 15;
189 break;
190
191 default:
192 json.charts[i].category = "Unknown";
193 + json.charts[i].glyphicon = "glyphicon-search";
194 + json.charts[i].group = 30;
195 break;
196 }
197 });