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
});