@cryptotaxi247 / netdata-1 / commits / b9d27c7c1

extended disk statistics

Costa Tsaousis (ktsaou) committed Oct 26, 2015 at 01:23 UTC b9d27c7c18d312616077e1ac601a459985e60e10
8 files changed +214 -67
src/common.c
+17
@@ -170,3 +170,20 @@ int fd_is_valid(int fd) {
170 return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
171 }
172
173 +/*
174 + ***************************************************************************
175 + * Get number of clock ticks per second.
176 + ***************************************************************************
177 + */
178 +unsigned int hz;
179 +
180 +void get_HZ(void)
181 +{
182 + long ticks;
183 +
184 + if ((ticks = sysconf(_SC_CLK_TCK)) == -1) {
185 + perror("sysconf");
186 + }
187 +
188 + hz = (unsigned int) ticks;
189 +}
src/common.h
+6
@@ -28,4 +28,10 @@ extern char *global_host_prefix;
28 #define unlikely(x) (x)
29 #endif
30
31 +
32 +/* Number of ticks per second */
33 +#define HZ hz
34 +extern unsigned int hz;
35 +extern void get_HZ(void);
36 +
37 #endif /* NETDATA_COMMON_H */
src/main.c
+3
@@ -168,6 +168,9 @@ int main(int argc, char **argv)
168 int config_loaded = 0;
169 int dont_fork = 0;
170
171 + // global initialization
172 + get_HZ();
173 +
174 // set the name for logging
175 program_name = "netdata";
176
src/plugin_tc.c
+8 -8
@@ -237,23 +237,23 @@ static void tc_device_commit(struct tc_device *d)
237 if(!c->updated) continue;
238
239 if(c->isleaf && c->hasparent) {
240 - if(rrddim_set(st, c->id, c->bytes) != 0) {
240 + RRDDIM *rd = rrddim_find(st, c->id);
241 +
242 + if(!rd) {
243 debug(D_TC_LOOP, "TC: Adding to chart '%s', dimension '%s'", st->id, c->id, c->name);
244
245 // new class, we have to add it
244 - rrddim_add(st, c->id, c->name?c->name:c->id, 8, 1024 * rrd_update_every, RRDDIM_INCREMENTAL);
245 - rrddim_set(st, c->id, c->bytes);
246 + rd = rrddim_add(st, c->id, c->name?c->name:c->id, 8, 1024 * rrd_update_every, RRDDIM_INCREMENTAL);
247 }
248 else debug(D_TC_LOOP, "TC: Updating chart '%s', dimension '%s'", st->id, c->id);
249
250 + rrddim_set_by_pointer(st, rd, c->bytes);
251 +
252 // if it has a name, different to the id
253 if(c->name) {
254 // update the rrd dimension with the new name
252 - RRDDIM *rd = rrddim_find(st, c->id);
253 - if(rd) {
254 - debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", st->id, rd->id, c->name);
255 - rrddim_set_name(st, rd, c->name);
256 - }
255 + debug(D_TC_LOOP, "TC: Setting chart '%s', dimension '%s' name to '%s'", st->id, rd->id, c->name);
256 + rrddim_set_name(st, rd, c->name);
257
258 free(c->name);
259 c->name = NULL;
src/proc_diskstats.c
+163 -41
@@ -19,7 +19,7 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
19 static procfile *ff = NULL;
20 static char path_to_get_hw_sector_size[FILENAME_MAX + 1] = "";
21 static int enable_new_disks = -1;
22 - static int do_io = -1, do_ops = -1, do_merged_ops = -1, do_iotime = -1, do_cur_ops = -1;
22 + static int do_io = -1, do_ops = -1, do_merged_ops = -1, do_iotime = -1, do_cur_ops = -1, do_util = -1, do_qsize = -1;
23
24 if(enable_new_disks == -1) enable_new_disks = config_get_boolean("plugin:proc:/proc/diskstats", "enable new disks detected at runtime", 1);
25
@@ -28,8 +28,8 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
28 if(do_merged_ops == -1) do_merged_ops = config_get_boolean("plugin:proc:/proc/diskstats", "merged operations for all disks", 1);
29 if(do_iotime == -1) do_iotime = config_get_boolean("plugin:proc:/proc/diskstats", "i/o time for all disks", 1);
30 if(do_cur_ops == -1) do_cur_ops = config_get_boolean("plugin:proc:/proc/diskstats", "current operations for all disks", 1);
31 -
32 - if(dt) {};
31 + if(do_util == -1) do_util = config_get_boolean("plugin:proc:/proc/diskstats", "utilization percentage for all disks", 1);
32 + if(do_qsize == -1) do_qsize = config_get_boolean("plugin:proc:/proc/diskstats", "queue size for all disks", 1);
33
34 if(!ff) {
35 char filename[FILENAME_MAX + 1];
@@ -57,23 +57,56 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
57 writes = 0, writes_merged = 0, writesectors = 0, writems = 0,
58 currentios = 0, iosms = 0, wiosms = 0;
59
60 + unsigned long long last_reads = 0, last_readsectors = 0, last_readms = 0,
61 + last_writes = 0, last_writesectors = 0, last_writems = 0,
62 + last_iosms = 0;
63 +
64 words = procfile_linewords(ff, l);
65 if(words < 14) continue;
66
67 major = strtoull(procfile_lineword(ff, l, 0), NULL, 10);
68 minor = strtoull(procfile_lineword(ff, l, 1), NULL, 10);
69 disk = procfile_lineword(ff, l, 2);
66 - reads = strtoull(procfile_lineword(ff, l, 3), NULL, 10);
67 - reads_merged = strtoull(procfile_lineword(ff, l, 4), NULL, 10);
68 - readsectors = strtoull(procfile_lineword(ff, l, 5), NULL, 10);
69 - readms = strtoull(procfile_lineword(ff, l, 6), NULL, 10);
70 - writes = strtoull(procfile_lineword(ff, l, 7), NULL, 10);
71 - writes_merged = strtoull(procfile_lineword(ff, l, 8), NULL, 10);
72 - writesectors = strtoull(procfile_lineword(ff, l, 9), NULL, 10);
73 - writems = strtoull(procfile_lineword(ff, l, 10), NULL, 10);
74 - currentios = strtoull(procfile_lineword(ff, l, 11), NULL, 10);
75 - iosms = strtoull(procfile_lineword(ff, l, 12), NULL, 10);
76 - wiosms = strtoull(procfile_lineword(ff, l, 13), NULL, 10);
70 +
71 + // # of reads completed # of writes completed
72 + // This is the total number of reads or writes completed successfully.
73 + reads = strtoull(procfile_lineword(ff, l, 3), NULL, 10); // rd_ios
74 + writes = strtoull(procfile_lineword(ff, l, 7), NULL, 10); // wr_ios
75 +
76 + // # of reads merged # of writes merged
77 + // Reads and writes which are adjacent to each other may be merged for
78 + // efficiency. Thus two 4K reads may become one 8K read before it is
79 + // ultimately handed to the disk, and so it will be counted (and queued)
80 + reads_merged = strtoull(procfile_lineword(ff, l, 4), NULL, 10); // rd_merges_or_rd_sec
81 + writes_merged = strtoull(procfile_lineword(ff, l, 8), NULL, 10); // wr_merges
82 +
83 + // # of sectors read # of sectors written
84 + // This is the total number of sectors read or written successfully.
85 + readsectors = strtoull(procfile_lineword(ff, l, 5), NULL, 10); // rd_sec_or_wr_ios
86 + writesectors = strtoull(procfile_lineword(ff, l, 9), NULL, 10); // wr_sec
87 +
88 + // # of milliseconds spent reading # of milliseconds spent writing
89 + // This is the total number of milliseconds spent by all reads or writes (as
90 + // measured from __make_request() to end_that_request_last()).
91 + readms = strtoull(procfile_lineword(ff, l, 6), NULL, 10); // rd_ticks_or_wr_sec
92 + writems = strtoull(procfile_lineword(ff, l, 10), NULL, 10); // wr_ticks
93 +
94 + // # of I/Os currently in progress
95 + // The only field that should go to zero. Incremented as requests are
96 + // given to appropriate struct request_queue and decremented as they finish.
97 + currentios = strtoull(procfile_lineword(ff, l, 11), NULL, 10); // ios_pgr
98 +
99 + // # of milliseconds spent doing I/Os
100 + // This field increases so long as field currentios is nonzero.
101 + iosms = strtoull(procfile_lineword(ff, l, 12), NULL, 10); // tot_ticks
102 +
103 + // weighted # of milliseconds spent doing I/Os
104 + // This field is incremented at each I/O start, I/O completion, I/O
105 + // merge, or read of these stats by the number of I/Os in progress
106 + // (field currentios) times the number of milliseconds spent doing I/O since the
107 + // last update of this field. This can provide an easy measure of both
108 + // I/O completion time and the backlog that may be accumulating.
109 + wiosms = strtoull(procfile_lineword(ff, l, 13), NULL, 10); // rq_ticks
110
111 int def_enabled = 0;
112
@@ -205,12 +238,12 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
238
239 // --------------------------------------------------------------------
240
241 + int sector_size = 512;
242 if(do_io) {
243 st = rrdset_find_bytype(RRD_TYPE_DISK, disk);
244 if(!st) {
245 char tf[FILENAME_MAX + 1], *t;
246 char ssfilename[FILENAME_MAX + 1];
213 - int sector_size = 512;
247
248 strncpy(tf, disk, FILENAME_MAX);
249 tf[FILENAME_MAX] = '\0';
@@ -242,10 +275,10 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
275 rrddim_add(st, "reads", NULL, sector_size, 1024 * update_every, RRDDIM_INCREMENTAL);
276 rrddim_add(st, "writes", NULL, sector_size * -1, 1024 * update_every, RRDDIM_INCREMENTAL);
277 }
245 - else rrdset_next(st);
278 + else rrdset_next_usec(st, dt);
279
247 - rrddim_set(st, "reads", readsectors);
248 - rrddim_set(st, "writes", writesectors);
280 + last_readsectors = rrddim_set(st, "reads", readsectors);
281 + last_writesectors = rrddim_set(st, "writes", writesectors);
282 rrdset_done(st);
283 }
284
@@ -260,25 +293,73 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
293 rrddim_add(st, "reads", NULL, 1, 1 * update_every, RRDDIM_INCREMENTAL);
294 rrddim_add(st, "writes", NULL, -1, 1 * update_every, RRDDIM_INCREMENTAL);
295 }
263 - else rrdset_next(st);
296 + else rrdset_next_usec(st, dt);
297 +
298 + last_reads = rrddim_set(st, "reads", reads);
299 + last_writes = rrddim_set(st, "writes", writes);
300 + rrdset_done(st);
301 + }
302 +
303 + // --------------------------------------------------------------------
304 +
305 + if(do_util) {
306 + st = rrdset_find_bytype("disk_util", disk);
307 + if(!st) {
308 + st = rrdset_create("disk_util", disk, NULL, disk, "Disk Utilization", "%", 2002, update_every, RRDSET_TYPE_AREA);
309 + st->isdetail = 1;
310 +
311 + rrddim_add(st, "utilization", NULL, 1, 10 * update_every, RRDDIM_INCREMENTAL);
312 + }
313 + else rrdset_next_usec(st, dt);
314 +
315 + last_iosms = rrddim_set(st, "utilization", iosms);
316 + rrdset_done(st);
317 + }
318 +
319 + // --------------------------------------------------------------------
320 +
321 + if(do_qsize) {
322 + st = rrdset_find_bytype("disk_qsize", disk);
323 + if(!st) {
324 + st = rrdset_create("disk_qsize", disk, NULL, disk, "Disk Average Queue Size", "queue size", 2003, update_every, RRDSET_TYPE_AREA);
325 + st->isdetail = 1;
326 +
327 + rrddim_add(st, "queue_size", NULL, 1, 1000 * update_every, RRDDIM_INCREMENTAL);
328 + }
329 + else rrdset_next_usec(st, dt);
330
265 - rrddim_set(st, "reads", reads);
266 - rrddim_set(st, "writes", writes);
331 + rrddim_set(st, "queue_size", wiosms);
332 rrdset_done(st);
333 }
269 -
334 +
335 + // --------------------------------------------------------------------
336 +
337 + if(do_cur_ops) {
338 + st = rrdset_find_bytype("disk_cur_ops", disk);
339 + if(!st) {
340 + st = rrdset_create("disk_cur_ops", disk, NULL, disk, "Current Disk I/O operations", "operations", 2004, update_every, RRDSET_TYPE_LINE);
341 + st->isdetail = 1;
342 +
343 + rrddim_add(st, "operations", NULL, 1, 1, RRDDIM_ABSOLUTE);
344 + }
345 + else rrdset_next_usec(st, dt);
346 +
347 + rrddim_set(st, "operations", currentios);
348 + rrdset_done(st);
349 + }
350 +
351 // --------------------------------------------------------------------
352
353 if(do_merged_ops) {
354 st = rrdset_find_bytype("disk_merged_ops", disk);
355 if(!st) {
275 - st = rrdset_create("disk_merged_ops", disk, NULL, disk, "Merged Disk Operations", "operations/s", 2010, update_every, RRDSET_TYPE_LINE);
356 + st = rrdset_create("disk_merged_ops", disk, NULL, disk, "Disk Merged Operations", "operations/s", 2021, update_every, RRDSET_TYPE_LINE);
357 st->isdetail = 1;
358
359 rrddim_add(st, "reads", NULL, 1, 1 * update_every, RRDDIM_INCREMENTAL);
360 rrddim_add(st, "writes", NULL, -1, 1 * update_every, RRDDIM_INCREMENTAL);
361 }
281 - else rrdset_next(st);
362 + else rrdset_next_usec(st, dt);
363
364 rrddim_set(st, "reads", reads_merged);
365 rrddim_set(st, "writes", writes_merged);
@@ -290,38 +371,79 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
371 if(do_iotime) {
372 st = rrdset_find_bytype("disk_iotime", disk);
373 if(!st) {
293 - st = rrdset_create("disk_iotime", disk, NULL, disk, "Disk I/O Time", "milliseconds/s", 2005, update_every, RRDSET_TYPE_LINE);
374 + st = rrdset_create("disk_iotime", disk, NULL, disk, "Disk I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE);
375 st->isdetail = 1;
376
377 rrddim_add(st, "reads", NULL, 1, 1 * update_every, RRDDIM_INCREMENTAL);
378 rrddim_add(st, "writes", NULL, -1, 1 * update_every, RRDDIM_INCREMENTAL);
298 - rrddim_add(st, "latency", NULL, 1, 1 * update_every, RRDDIM_INCREMENTAL);
299 - rrddim_add(st, "weighted", NULL, 1, 1 * update_every, RRDDIM_INCREMENTAL);
379 }
301 - else rrdset_next(st);
380 + else rrdset_next_usec(st, dt);
381
303 - rrddim_set(st, "reads", readms);
304 - rrddim_set(st, "writes", writems);
305 - rrddim_set(st, "latency", iosms);
306 - rrddim_set(st, "weighted", wiosms);
382 + last_readms = rrddim_set(st, "reads", readms);
383 + last_writems = rrddim_set(st, "writes", writems);
384 rrdset_done(st);
385 }
386
387 // --------------------------------------------------------------------
388 + // calculate differential charts
389 + // only if this is not the first time we run
390 +
391 + if(dt) {
392 + if(do_iotime && do_ops) {
393 + st = rrdset_find_bytype("disk_await", disk);
394 + if(!st) {
395 + st = rrdset_create("disk_await", disk, NULL, disk, "Average Wait Time", "ms per operation", 2005, update_every, RRDSET_TYPE_AREA);
396 + st->isdetail = 1;
397 +
398 + rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_ABSOLUTE);
399 + rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_ABSOLUTE);
400 + }
401 + else rrdset_next_usec(st, dt);
402
312 - if(do_cur_ops) {
313 - st = rrdset_find_bytype("disk_cur_ops", disk);
314 - if(!st) {
315 - st = rrdset_create("disk_cur_ops", disk, NULL, disk, "Current Disk I/O operations", "operations", 2004, update_every, RRDSET_TYPE_LINE);
316 - st->isdetail = 1;
403 + rrddim_set(st, "reads", (reads - last_reads) ? (readms - last_readms) / (reads - last_reads) : 0);
404 + rrddim_set(st, "writes", (writes - last_writes) ? (writems - last_writems) / (writes - last_writes) : 0);
405 + rrdset_done(st);
406 + }
407
318 - rrddim_add(st, "operations", NULL, 1, 1, RRDDIM_ABSOLUTE);
408 + if(do_io && do_ops) {
409 + st = rrdset_find_bytype("disk_avgsz", disk);
410 + if(!st) {
411 + st = rrdset_create("disk_avgsz", disk, NULL, disk, "Average Operation Size", "kilobytes", 2006, update_every, RRDSET_TYPE_AREA);
412 + st->isdetail = 1;
413 +
414 + rrddim_add(st, "reads", NULL, sector_size, 1024, RRDDIM_ABSOLUTE);
415 + rrddim_add(st, "writes", NULL, -sector_size, 1024, RRDDIM_ABSOLUTE);
416 + }
417 + else rrdset_next_usec(st, dt);
418 +
419 + rrddim_set(st, "reads", (reads - last_reads) ? (readsectors - last_readsectors) / (reads - last_reads) : 0);
420 + rrddim_set(st, "writes", (writes - last_writes) ? (writesectors - last_writesectors) / (writes - last_writes) : 0);
421 + rrdset_done(st);
422 }
320 - else rrdset_next(st);
423
322 - rrddim_set(st, "operations", currentios);
323 - rrdset_done(st);
424 + if(do_util && do_ops) {
425 + st = rrdset_find_bytype("disk_svctm", disk);
426 + if(!st) {
427 + st = rrdset_create("disk_svctm", disk, NULL, disk, "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_AREA);
428 + st->isdetail = 1;
429 +
430 + rrddim_add(st, "svctm", NULL, -1, 1, RRDDIM_ABSOLUTE);
431 + }
432 + else rrdset_next_usec(st, dt);
433 +
434 + rrddim_set(st, "svctm", ((reads - last_reads) + (writes - last_writes)) ? (iosms - last_iosms) / ((reads - last_reads) + (writes - last_writes)) : 0);
435 + rrdset_done(st);
436 + }
437 }
438 +
439 + // TODO
440 + // the differential (readms + writems) / (reads + writes) = average wait time
441 + // the differential (readms ) / (reads ) = the average wait time for reads
442 + // the differential (writems) / (writes) = the average wait time for writes
443 +
444 + // similarly for bytes to find the average read and write size
445 +
446 + // svctm = % of utilization per request (reads + writes)
447 }
448
449 return 0;
src/rrd.c
+12 -8
@@ -745,33 +745,37 @@ int rrddim_unhide(RRDSET *st, const char *id)
745 return 0;
746 }
747
748 -void rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, collected_number value)
748 +collected_number rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, collected_number value)
749 {
750 debug(D_RRD_CALLS, "rrddim_set_by_pointer() for chart %s, dimension %s, value " COLLECTED_NUMBER_FORMAT, st->name, rd->name, value);
751
752 gettimeofday(&rd->last_collected_time, NULL);
753 rd->collected_value = value;
754 rd->updated = 1;
755 +
756 + return rd->last_collected_value;
757 }
758
757 -int rrddim_set(RRDSET *st, const char *id, collected_number value)
759 +collected_number rrddim_set(RRDSET *st, const char *id, collected_number value)
760 {
761 RRDDIM *rd = rrddim_find(st, id);
762 if(unlikely(!rd)) {
763 error("Cannot find dimension with id '%s' on stats '%s' (%s).", id, st->name, st->id);
762 - return 1;
764 + return 0;
765 }
766
765 - rrddim_set_by_pointer(st, rd, value);
766 - return 0;
767 + return rrddim_set_by_pointer(st, rd, value);
768 }
769
770 void rrdset_next_usec(RRDSET *st, unsigned long long microseconds)
771 {
771 - debug(D_RRD_CALLS, "rrdset_next_usec() for chart %s with microseconds %llu", st->name, microseconds);
772 + if(!microseconds) rrdset_next(st);
773 + else {
774 + debug(D_RRD_CALLS, "rrdset_next_usec() for chart %s with microseconds %llu", st->name, microseconds);
775
773 - if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: NEXT: %llu microseconds", st->name, microseconds);
774 - st->usec_since_last_update = microseconds;
776 + if(unlikely(st->debug)) debug(D_RRD_STATS, "%s: NEXT: %llu microseconds", st->name, microseconds);
777 + st->usec_since_last_update = microseconds;
778 + }
779 }
780
781 void rrdset_next(RRDSET *st)
src/rrd.h
+2 -5
@@ -315,10 +315,7 @@ extern RRDDIM *rrddim_find(RRDSET *st, const char *id);
315 extern int rrddim_hide(RRDSET *st, const char *id);
316 extern int rrddim_unhide(RRDSET *st, const char *id);
317
318 -extern void rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, collected_number value);
319 -extern int rrddim_set(RRDSET *st, const char *id, collected_number value);
320 -
321 -
322 -
318 +extern collected_number rrddim_set_by_pointer(RRDSET *st, RRDDIM *rd, collected_number value);
319 +extern collected_number rrddim_set(RRDSET *st, const char *id, collected_number value);
320
321 #endif /* NETDATA_RRD_H */
src/rrd2json.c
+3 -5
@@ -383,11 +383,6 @@ RRDR *rrd2rrdr(RRDSET *st, long points, time_t after, time_t before, int group_m
383 if(group <= 0) group = 1;
384 if(duration / group > points) group++;
385
386 - // align timestamps to group
387 - before -= before % group;
388 - after -= after % group;
389 - duration = before - after;
390 -
386 // error("NEW: points=%d after=%d before=%d group=%d, duration=%d", points, after, before, group, duration);
387
388 // Now we have:
@@ -459,6 +454,9 @@ RRDR *rrd2rrdr(RRDSET *st, long points, time_t after, time_t before, int group_m
454 add_this = 0,
455 stop_now = 0;
456
457 + // align to group for proper panning of data
458 + t -= t % group;
459 +
460 time_t now = rrdset_slot2time(st, t),
461 dt = st->update_every,
462 group_start_t = 0;