added support for CPU jitter calculation
Costa Tsaousis (ktsaou) committed
Apr 4, 2014 at 22:49 UTC
059c9b4a0c0bdf47f038d128f250095d01fe1d93
3 files changed
+228
-161
netdata.c
+222
-161
@@ -178,22 +178,22 @@ void debug_int( const char *file, const char *function, const unsigned long line
178
179
void error_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
180
{
181
- if(silent) return;
182
-
181
va_list args;
182
185
- log_date();
183
+ if(!silent) {
184
+ log_date();
185
187
- va_start( args, fmt );
188
- fprintf(stderr, "ERROR (%04lu@%-15.15s): ", line, function);
189
- vfprintf( stderr, fmt, args );
190
- va_end( args );
186
+ va_start( args, fmt );
187
+ fprintf(stderr, "ERROR (%04lu@%-15.15s): ", line, function);
188
+ vfprintf( stderr, fmt, args );
189
+ va_end( args );
190
192
- if(errno) {
193
- fprintf(stderr, " (errno %d, %s)\n", errno, strerror(errno));
194
- errno = 0;
195
- }
196
- else fprintf(stderr, "\n");
191
+ if(errno) {
192
+ fprintf(stderr, " (errno %d, %s)\n", errno, strerror(errno));
193
+ errno = 0;
194
+ }
195
+ else fprintf(stderr, "\n");
196
+ }
197
198
va_start( args, fmt );
199
vsyslog(LOG_ERR, fmt, args );
@@ -204,19 +204,19 @@ void error_int( const char *file, const char *function, const unsigned long line
204
205
void fatal_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
206
{
207
- if(silent) exit(EXIT_FAILURE);
208
-
207
va_list args;
208
211
- log_date();
209
+ if(!silent) {
210
+ log_date();
211
213
- va_start( args, fmt );
214
- fprintf(stderr, "FATAL (%04lu@%-15.15s): ", line, function);
215
- vfprintf( stderr, fmt, args );
216
- va_end( args );
212
+ va_start( args, fmt );
213
+ fprintf(stderr, "FATAL (%04lu@%-15.15s): ", line, function);
214
+ vfprintf( stderr, fmt, args );
215
+ va_end( args );
216
218
- perror(" # ");
219
- fprintf(stderr, "\n");
217
+ perror(" # ");
218
+ fprintf(stderr, "\n");
219
+ }
220
221
va_start( args, fmt );
222
vsyslog(LOG_CRIT, fmt, args );
@@ -1157,6 +1157,7 @@ void web_client_reset(struct web_client *w)
1157
w->data->bytes = 0;
1158
w->data->sent = 0;
1159
1160
+ w->response_header[0] = '\0';
1161
w->data->buffer[0] = '\0';
1162
1163
w->wait_receive = 1;
@@ -1169,175 +1170,185 @@ void web_client_process(struct web_client *w)
1170
int bytes;
1171
1172
// check if we have an empty line (end of HTTP header)
1172
- if(!strstr(w->data->buffer, "\r\n\r\n")) return;
1173
+ if(strstr(w->data->buffer, "\r\n\r\n")) {
1174
+ debug(D_WEB_DATA, "%llu: Processing data buffer of %d bytes: '%s'.", w->id, w->data->bytes, w->data->buffer);
1175
1174
- w->response_header[0] = '\0';
1175
- w->data->date = time(NULL);
1176
- w->wait_receive = 0;
1177
- w->data->sent = 0;
1176
+ // check if the client requested keep-alive HTTP
1177
+ if(strcasestr(w->data->buffer, "Connection: keep-alive") == 0) w->keepalive = 0;
1178
+ else w->keepalive = 1;
1179
1179
- debug(D_WEB_DATA, "%llu: Processing data buffer of %d bytes: '%s'.", w->id, w->data->bytes, w->data->buffer);
1180
+ char *buf = w->data->buffer;
1181
+ char *tok = strsep(&buf, " \r\n");
1182
+ char *url = NULL;
1183
1181
- // check if the client requested keep-alive HTTP
1182
- if(strcasestr(w->data->buffer, "Connection: keep-alive") == 0) w->keepalive = 0;
1183
- else w->keepalive = 1;
1184
-
1185
- char *buf = w->data->buffer;
1186
- char *tok = strsep(&buf, " \r\n");
1187
- char *url = NULL;
1188
-
1189
- if(buf && strcmp(tok, "GET") == 0) {
1190
- tok = strsep(&buf, " \r\n");
1191
- url = url_decode(tok);
1192
- debug(D_WEB_CLIENT, "%llu: Processing HTTP GET on url '%s'.", w->id, url);
1193
- }
1194
- else if (buf && strcmp(tok, "POST") == 0) {
1195
- w->keepalive = 0;
1196
- tok = strsep(&buf, " \r\n");
1197
- url = url_decode(tok);
1184
+ if(buf && strcmp(tok, "GET") == 0) {
1185
+ tok = strsep(&buf, " \r\n");
1186
+ url = url_decode(tok);
1187
+ debug(D_WEB_CLIENT, "%llu: Processing HTTP GET on url '%s'.", w->id, url);
1188
+ }
1189
+ else if (buf && strcmp(tok, "POST") == 0) {
1190
+ w->keepalive = 0;
1191
+ tok = strsep(&buf, " \r\n");
1192
+ url = url_decode(tok);
1193
1199
- debug(D_WEB_CLIENT, "%llu: I don't know how to handle POST with form data. Assuming it is a GET on url '%s'.", w->id, url);
1200
- }
1194
+ debug(D_WEB_CLIENT, "%llu: I don't know how to handle POST with form data. Assuming it is a GET on url '%s'.", w->id, url);
1195
+ }
1196
1202
- if(url) {
1203
- tok = mystrsep(&url, "/?&");
1197
+ if(url) {
1198
+ tok = mystrsep(&url, "/?&");
1199
1205
- debug(D_WEB_CLIENT, "%llu: Processing command '%s'.", w->id, tok);
1200
+ debug(D_WEB_CLIENT, "%llu: Processing command '%s'.", w->id, tok);
1201
1207
- if(strcmp(tok, WEB_PATH_DATA) == 0) { // "data"
1208
- // the client is requesting rrd data
1202
+ if(strcmp(tok, WEB_PATH_DATA) == 0) { // "data"
1203
+ // the client is requesting rrd data
1204
1210
- // get the name of the data to show
1211
- tok = mystrsep(&url, "/?&");
1212
- debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
1205
+ // get the name of the data to show
1206
+ tok = mystrsep(&url, "/?&");
1207
+ debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
1208
1214
- // do we have such a data set?
1215
- RRD_STATS *st = rrd_stats_find_byname(tok);
1216
- if(!st) st = rrd_stats_find(tok);
1217
- if(!st) {
1218
- // we don't have it
1219
- // try to send a file with that name
1220
- code = mysendfile(w, tok);
1221
- }
1222
- else {
1223
- // we have it
1224
- debug(D_WEB_CLIENT, "%llu: Found RRD data with name '%s'.", w->id, tok);
1225
-
1226
- // how many entries does the client want?
1227
- size_t lines = save_history;
1228
- size_t group_count = 1;
1229
- int group_method = GROUP_AVERAGE;
1230
-
1231
- if(url) {
1232
- // parse the lines required
1233
- tok = mystrsep(&url, "/?&");
1234
- if(tok) lines = atoi(tok);
1235
- if(lines < 5) lines = save_history;
1236
- }
1237
- if(url) {
1238
- // parse the group count required
1239
- tok = mystrsep(&url, "/?&");
1240
- if(tok) group_count = atoi(tok);
1241
- if(group_count < 1) group_count = 1;
1242
- if(group_count > save_history / 20) group_count = save_history / 20;
1243
- }
1244
- if(url) {
1245
- // parse the grouping method required
1246
- tok = mystrsep(&url, "/?&");
1247
- if(strcmp(tok, "max") == 0) group_method = GROUP_MAX;
1248
- else if(strcmp(tok, "average") == 0) group_method = GROUP_AVERAGE;
1249
- else debug(D_WEB_CLIENT, "%llu: Unknown group method '%s'", w->id, tok);
1209
+ // do we have such a data set?
1210
+ RRD_STATS *st = rrd_stats_find_byname(tok);
1211
+ if(!st) st = rrd_stats_find(tok);
1212
+ if(!st) {
1213
+ // we don't have it
1214
+ // try to send a file with that name
1215
+ code = mysendfile(w, tok);
1216
}
1217
+ else {
1218
+ // we have it
1219
+ debug(D_WEB_CLIENT, "%llu: Found RRD data with name '%s'.", w->id, tok);
1220
+
1221
+ // how many entries does the client want?
1222
+ size_t lines = save_history;
1223
+ size_t group_count = 1;
1224
+ int group_method = GROUP_AVERAGE;
1225
+
1226
+ if(url) {
1227
+ // parse the lines required
1228
+ tok = mystrsep(&url, "/?&");
1229
+ if(tok) lines = atoi(tok);
1230
+ if(lines < 5) lines = save_history;
1231
+ }
1232
+ if(url) {
1233
+ // parse the group count required
1234
+ tok = mystrsep(&url, "/?&");
1235
+ if(tok) group_count = atoi(tok);
1236
+ if(group_count < 1) group_count = 1;
1237
+ if(group_count > save_history / 20) group_count = save_history / 20;
1238
+ }
1239
+ if(url) {
1240
+ // parse the grouping method required
1241
+ tok = mystrsep(&url, "/?&");
1242
+ if(strcmp(tok, "max") == 0) group_method = GROUP_MAX;
1243
+ else if(strcmp(tok, "average") == 0) group_method = GROUP_AVERAGE;
1244
+ else debug(D_WEB_CLIENT, "%llu: Unknown group method '%s'", w->id, tok);
1245
+ }
1246
1252
- debug(D_WEB_CLIENT_ACCESS, "%llu: Sending RRD data '%s' (id %s, %d lines, %d group_count, %d group_method).", w->id, st->name, st->id, lines, group_count, group_method);
1247
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Sending RRD data '%s' (id %s, %d lines, %d group_count, %d group_method).", w->id, st->name, st->id, lines, group_count, group_method);
1248
1254
- code = 200;
1255
- w->data->contenttype = CT_APPLICATION_JSON;
1256
- w->data->bytes = rrd_stats_json(st, w->data->buffer, w->data->size, lines, group_count, group_method);
1249
+ code = 200;
1250
+ w->data->contenttype = CT_APPLICATION_JSON;
1251
+ w->data->bytes = rrd_stats_json(st, w->data->buffer, w->data->size, lines, group_count, group_method);
1252
+ }
1253
}
1258
- }
1259
- else if(strcmp(tok, WEB_PATH_GRAPH) == 0) { // "graph"
1260
- // the client is requesting an rrd graph
1254
+ else if(strcmp(tok, WEB_PATH_GRAPH) == 0) { // "graph"
1255
+ // the client is requesting an rrd graph
1256
1262
- // get the name of the data to show
1263
- tok = mystrsep(&url, "/?&");
1264
- debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
1257
+ // get the name of the data to show
1258
+ tok = mystrsep(&url, "/?&");
1259
+ debug(D_WEB_CLIENT, "%llu: Searching for RRD data with name '%s'.", w->id, tok);
1260
1266
- // do we have such a data set?
1267
- RRD_STATS *st = rrd_stats_find_byname(tok);
1268
- if(!st) {
1269
- // we don't have it
1270
- // try to send a file with that name
1271
- code = mysendfile(w, tok);
1261
+ // do we have such a data set?
1262
+ RRD_STATS *st = rrd_stats_find_byname(tok);
1263
+ if(!st) {
1264
+ // we don't have it
1265
+ // try to send a file with that name
1266
+ code = mysendfile(w, tok);
1267
+ }
1268
+ else {
1269
+ code = 200;
1270
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Sending %s.json of RRD_STATS...", w->id, st->name);
1271
+ w->data->contenttype = CT_APPLICATION_JSON;
1272
+ w->data->bytes = rrd_stats_graph_json(st, url, w->data->buffer, w->data->size);
1273
+ }
1274
}
1273
- else {
1275
+ else if(strcmp(tok, "mirror") == 0) {
1276
code = 200;
1275
- debug(D_WEB_CLIENT_ACCESS, "%llu: Sending %s.json of RRD_STATS...", w->id, st->name);
1276
- w->data->contenttype = CT_APPLICATION_JSON;
1277
- w->data->bytes = rrd_stats_graph_json(st, url, w->data->buffer, w->data->size);
1278
- }
1279
- }
1280
- else if(strcmp(tok, "mirror") == 0) {
1281
- code = 200;
1277
1283
- debug(D_WEB_CLIENT_ACCESS, "%llu: Mirroring...", w->id);
1278
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Mirroring...", w->id);
1279
1285
- // just leave the buffer as is
1286
- // it will be copied back to the client
1287
- }
1288
- else if(strcmp(tok, "list") == 0) {
1289
- code = 200;
1280
+ // just leave the buffer as is
1281
+ // it will be copied back to the client
1282
+ }
1283
+ else if(strcmp(tok, "list") == 0) {
1284
+ code = 200;
1285
1291
- debug(D_WEB_CLIENT_ACCESS, "%llu: Sending list of RRD_STATS...", w->id);
1286
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Sending list of RRD_STATS...", w->id);
1287
1293
- w->data->bytes = 0;
1294
- RRD_STATS *st = root;
1288
+ w->data->bytes = 0;
1289
+ RRD_STATS *st = root;
1290
1296
- for ( ; st ; st = st->next )
1297
- w->data->bytes += sprintf(&w->data->buffer[w->data->bytes], "%s\n", st->name);
1298
- }
1299
- else if(strcmp(tok, "envlist") == 0) {
1300
- code = 200;
1291
+ for ( ; st ; st = st->next )
1292
+ w->data->bytes += sprintf(&w->data->buffer[w->data->bytes], "%s\n", st->name);
1293
+ }
1294
+ else if(strcmp(tok, "envlist") == 0) {
1295
+ code = 200;
1296
1302
- debug(D_WEB_CLIENT_ACCESS, "%llu: Sending envlist of RRD_STATS...", w->id);
1297
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Sending envlist of RRD_STATS...", w->id);
1298
1304
- w->data->bytes = 0;
1305
- RRD_STATS *st = root;
1299
+ w->data->bytes = 0;
1300
+ RRD_STATS *st = root;
1301
1307
- for ( ; st ; st = st->next ) {
1308
- w->data->bytes += sprintf(&w->data->buffer[w->data->bytes], "%s=%s\n", st->envtitle, st->usertitle);
1309
- w->data->bytes += sprintf(&w->data->buffer[w->data->bytes], "%s=%s\n", st->envpriority, st->userpriority);
1302
+ for ( ; st ; st = st->next ) {
1303
+ w->data->bytes += sprintf(&w->data->buffer[w->data->bytes], "%s=%s\n", st->envtitle, st->usertitle);
1304
+ w->data->bytes += sprintf(&w->data->buffer[w->data->bytes], "%s=%s\n", st->envpriority, st->userpriority);
1305
+ }
1306
+ }
1307
+ else if(strcmp(tok, "all.json") == 0) {
1308
+ code = 200;
1309
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Sending all.json of RRD_STATS...", w->id);
1310
+ w->data->contenttype = CT_APPLICATION_JSON;
1311
+ w->data->bytes = rrd_stats_all_json(w->data->buffer, w->data->size);
1312
+ }
1313
+ else if(strcmp(tok, WEB_PATH_FILE) == 0) { // "file"
1314
+ tok = mystrsep(&url, "/?&");
1315
+ if(tok && *tok) code = mysendfile(w, tok);
1316
+ else {
1317
+ code = 400;
1318
+ strcpy(w->data->buffer, "You have to give a filename to get.\r\n");
1319
+ w->data->bytes = strlen(w->data->buffer);
1320
+ }
1321
+ }
1322
+ else if(!tok[0]) {
1323
+ code = mysendfile(w, "index.html");
1324
}
1311
- }
1312
- else if(strcmp(tok, "all.json") == 0) {
1313
- code = 200;
1314
- debug(D_WEB_CLIENT_ACCESS, "%llu: Sending all.json of RRD_STATS...", w->id);
1315
- w->data->contenttype = CT_APPLICATION_JSON;
1316
- w->data->bytes = rrd_stats_all_json(w->data->buffer, w->data->size);
1317
- }
1318
- else if(strcmp(tok, WEB_PATH_FILE) == 0) { // "file"
1319
- tok = mystrsep(&url, "/?&");
1320
- if(tok && *tok) code = mysendfile(w, tok);
1325
else {
1322
- code = 400;
1323
- strcpy(w->data->buffer, "You have to give a filename to get.\r\n");
1324
- w->data->bytes = strlen(w->data->buffer);
1326
+ code = mysendfile(w, tok);
1327
}
1328
}
1327
- else if(!tok[0]) {
1328
- code = mysendfile(w, "index.html");
1329
- }
1329
else {
1331
- code = mysendfile(w, tok);
1330
+ if(buf) debug(D_WEB_CLIENT_ACCESS, "%llu: Cannot understand '%s'.", w->id, buf);
1331
+
1332
+ code = 500;
1333
+ strcpy(w->data->buffer, "I don't understand you...\r\n");
1334
+ w->data->bytes = strlen(w->data->buffer);
1335
}
1336
}
1334
- else {
1335
- if(buf) debug(D_WEB_CLIENT_ACCESS, "%llu: Cannot understand '%s'.", w->id, buf);
1337
+ else if(w->data->bytes > 8192) {
1338
+ debug(D_WEB_CLIENT_ACCESS, "%llu: Received request is too big.", w->id);
1339
1337
- code = 500;
1338
- strcpy(w->data->buffer, "I don't understand you...\r\n");
1340
+ code = 400;
1341
+ strcpy(w->data->buffer, "Received request is too big.\r\n");
1342
w->data->bytes = strlen(w->data->buffer);
1343
}
1344
+ else {
1345
+ // wait for more data
1346
+ return;
1347
+ }
1348
+
1349
+ w->data->date = time(NULL);
1350
+ w->wait_receive = 0;
1351
+ w->data->sent = 0;
1352
1353
// prepare the HTTP response header
1354
debug(D_WEB_CLIENT, "%llu: Generating HTTP header with response %d.", w->id, code);
@@ -1644,7 +1655,7 @@ void *new_client(void *ptr)
1655
if(w->ofd > fdmax) fdmax = w->ofd;
1656
}
1657
1647
- tv.tv_sec = 10;
1658
+ tv.tv_sec = 30;
1659
tv.tv_usec = 0;
1660
1661
debug(D_WEB_CLIENT, "%llu: Waiting...", w->id);
@@ -2883,7 +2894,7 @@ void *tc_main(void *ptr)
2894
struct tc_device *device = NULL;
2895
struct tc_class *class = NULL;
2896
2886
- sprintf(buffer, "./tc-all.sh %d", update_every);
2897
+ sprintf(buffer, "exec ./tc-all.sh %d", update_every);
2898
fp = popen(buffer, "r");
2899
2900
while(fgets(buffer, TC_LINE_MAX, fp) != NULL) {
@@ -2960,6 +2971,54 @@ void *tc_main(void *ptr)
2971
return NULL;
2972
}
2973
2974
+// ----------------------------------------------------------------------------
2975
+// cpu jitter calculation
2976
+
2977
+#define CPU_JITTER_SLEEP_TIME_MS 20
2978
+
2979
+void *cpujitter_main(void *ptr)
2980
+{
2981
+
2982
+ struct timeval before, after;
2983
+
2984
+ while(1) {
2985
+ unsigned long long usec, susec = 0;
2986
+
2987
+ while(susec < (update_every * 1000000L)) {
2988
+
2989
+ gettimeofday(&before, NULL);
2990
+ usleep(CPU_JITTER_SLEEP_TIME_MS * 1000);
2991
+ gettimeofday(&after, NULL);
2992
+
2993
+ // calculate the time it took for a full loop
2994
+ usec = usecdiff(&after, &before);
2995
+ susec += usec;
2996
+ }
2997
+ usec -= (CPU_JITTER_SLEEP_TIME_MS * 1000);
2998
+
2999
+ RRD_STATS *st = rrd_stats_find(RRD_TYPE_STAT ".jitter");
3000
+ if(!st) {
3001
+ st = rrd_stats_create(RRD_TYPE_STAT ".jitter", RRD_TYPE_STAT ".jitter", save_history, "CPU Jitter", "microseconds lost", RRD_TYPE_STAT);
3002
+ if(!st) {
3003
+ error("Cannot create RRD_STATS for interface %s.", RRD_TYPE_STAT ".jitter");
3004
+ continue;
3005
+ }
3006
+
3007
+ if(!rrd_stats_dimension_add(st, "jitter", "jitter", sizeof(unsigned long long), 1, 1, RRD_DIMENSION_ABSOLUTE))
3008
+ error("Cannot add RRD_STATS dimension %s.", "jitter");
3009
+
3010
+ }
3011
+ else rrd_stats_next(st);
3012
+
3013
+ rrd_stats_dimension_set(st, "jitter", &usec);
3014
+ rrd_stats_done(st);
3015
+ }
3016
+
3017
+ return NULL;
3018
+}
3019
+
3020
+
3021
+
3022
void bye(void)
3023
{
3024
error("bye...");
@@ -3140,12 +3199,13 @@ int main(int argc, char **argv)
3199
for (i = 1 ; i < 65 ;i++) if(i != SIGSEGV) signal(i, sig_handler);
3200
3201
3143
- pthread_t p_proc, p_tc;
3144
- int r_proc, r_tc;
3202
+ pthread_t p_proc, p_tc, p_jitter;
3203
+ int r_proc, r_tc, r_jitter;
3204
3205
// spawn a child to collect data
3147
- r_proc = pthread_create(&p_proc, NULL, proc_main, NULL);
3148
- r_tc = pthread_create(&p_tc, NULL, tc_main, NULL);
3206
+ r_proc = pthread_create(&p_proc, NULL, proc_main, NULL);
3207
+ r_tc = pthread_create(&p_tc, NULL, tc_main, NULL);
3208
+ r_jitter = pthread_create(&p_jitter, NULL, cpujitter_main, NULL);
3209
3210
// the main process - the web server listener
3211
//sleep(1);
@@ -3157,6 +3217,7 @@ int main(int argc, char **argv)
3217
3218
printf("TC thread returns: %d\n", r_tc);
3219
printf("PROC NET DEV thread returns: %d\n", r_proc);
3220
+ printf("CPU JITTER thread returns: %d\n", r_jitter);
3221
3222
exit(0);
3223
}
web/index.html
+5
@@ -168,14 +168,19 @@
168
169
width = thumbWidth();
170
$.each(mycharts, function(i, c) {
171
+ var now = new Date().getTime();
172
+
173
if(c.enabled && c.chartOptions.width != width) {
174
if(c.chart) c.chart.clearChart();
175
c.chart = null;
176
+ c.last_updated = now + (c.update_every * 1000);
177
c.chartOptions.width = width;
178
showChartIsLoading(c.div, c.chartOptions.width, c.chartOptions.height);
179
c.last_updated = 0;
180
}
181
});
182
+
183
+ chartsRefresh();
184
}
185
186
// load the charts from the server
web/netdata.js
+1
@@ -137,6 +137,7 @@ function loadCharts(base_url, doNext) {
137
|| json.charts[i].id == "cpu.intr"
138
|| json.charts[i].id == "cpu.processes"
139
|| json.charts[i].id == "cpu.procs_running"
140
+ || json.charts[i].id == "cpu.jitter"
141
)
142
&& json.charts[i].name != "ipv4.net" && json.charts[i].name != "ipvs.net") {
143