@cryptotaxi247 / netdata-1 / commits / 059c9b4a0

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