@cryptotaxi247 / netdata-1 / commits / a133e33b3

monitor bcache; fixes #3482

Costa Tsaousis (ktsaou) committed Mar 5, 2018 at 09:04 UTC a133e33b3de3c9e24614e8bf8de7d4bbeb106626
1 file changed +463 -143
src/proc_diskstats.c
+463 -143
@@ -21,7 +21,6 @@ static struct disk {
21 char *mount_point;
22
23 // disk options caching
24 - int configured;
24 int do_io;
25 int do_ops;
26 int do_mops;
@@ -29,9 +28,21 @@ static struct disk {
28 int do_qops;
29 int do_util;
30 int do_backlog;
31 + int do_bcache;
32
33 int updated;
34
35 + int device_is_bcache;
36 +
37 + char *bcache_filename_dirty_data;
38 + char *bcache_filename_cache_available_percent;
39 + char *bcache_filename_cache_hits;
40 + char *bcache_filename_cache_misses;
41 + char *bcache_filename_cache_miss_collisions;
42 + char *bcache_filename_cache_bypass_hits;
43 + char *bcache_filename_cache_bypass_misses;
44 + char *bcache_filename_cache_readaheads;
45 +
46 RRDSET *st_io;
47 RRDDIM *rd_io_reads;
48 RRDDIM *rd_io_writes;
@@ -68,21 +79,84 @@ static struct disk {
79 RRDSET *st_svctm;
80 RRDDIM *rd_svctm_svctm;
81
82 + RRDSET *st_bcache_size;
83 + RRDDIM *rd_bcache_dirty_size;
84 +
85 + RRDSET *st_bcache_usage;
86 + RRDDIM *rd_bcache_available_percent;
87 +
88 + RRDSET *st_bcache;
89 + RRDDIM *rd_bcache_hits;
90 + RRDDIM *rd_bcache_misses;
91 + RRDDIM *rd_bcache_miss_collisions;
92 +
93 + RRDSET *st_bcache_bypass;
94 + RRDDIM *rd_bcache_bypass_hits;
95 + RRDDIM *rd_bcache_bypass_misses;
96 +
97 + RRDSET *st_bcache_readaheads;
98 + RRDDIM *rd_bcache_readaheads;
99 +
100 struct disk *next;
101 } *disk_root = NULL;
102
103 #define rrdset_obsolete_and_pointer_null(st) do { if(st) { rrdset_is_obsolete(st); (st) = NULL; } } while(st)
104
76 -static char *path_to_get_hw_sector_size = NULL;
77 -static char *path_to_get_hw_sector_size_partitions = NULL;
105 +// static char *path_to_get_hw_sector_size = NULL;
106 +// static char *path_to_get_hw_sector_size_partitions = NULL;
107 static char *path_to_sys_dev_block_major_minor_string = NULL;
108 static char *path_to_sys_block_device = NULL;
109 +static char *path_to_sys_block_device_bcache = NULL;
110 static char *path_to_sys_devices_virtual_block_device = NULL;
111 static char *path_to_device_mapper = NULL;
112 static char *path_to_device_label = NULL;
113 static char *path_to_device_id = NULL;
114 static int name_disks_by_id = CONFIG_BOOLEAN_NO;
115
116 +static int global_enable_new_disks_detected_at_runtime = CONFIG_BOOLEAN_YES,
117 + global_enable_performance_for_physical_disks = CONFIG_BOOLEAN_AUTO,
118 + global_enable_performance_for_virtual_disks = CONFIG_BOOLEAN_AUTO,
119 + global_enable_performance_for_partitions = CONFIG_BOOLEAN_NO,
120 + global_do_io = CONFIG_BOOLEAN_AUTO,
121 + global_do_ops = CONFIG_BOOLEAN_AUTO,
122 + global_do_mops = CONFIG_BOOLEAN_AUTO,
123 + global_do_iotime = CONFIG_BOOLEAN_AUTO,
124 + global_do_qops = CONFIG_BOOLEAN_AUTO,
125 + global_do_util = CONFIG_BOOLEAN_AUTO,
126 + global_do_backlog = CONFIG_BOOLEAN_AUTO,
127 + global_do_bcache = CONFIG_BOOLEAN_AUTO,
128 + globals_initialized = 0,
129 + global_cleanup_removed_disks = 1;
130 +
131 +static SIMPLE_PATTERN *excluded_disks = NULL;
132 +
133 +static inline int is_major_enabled(int major) {
134 + static int8_t *major_configs = NULL;
135 + static size_t major_size = 0;
136 +
137 + if(major < 0) return 1;
138 +
139 + size_t wanted_size = (size_t)major + 1;
140 +
141 + if(major_size < wanted_size) {
142 + major_configs = reallocz(major_configs, wanted_size * sizeof(int8_t));
143 +
144 + size_t i;
145 + for(i = major_size; i < wanted_size ; i++)
146 + major_configs[i] = -1;
147 +
148 + major_size = wanted_size;
149 + }
150 +
151 + if(major_configs[major] == -1) {
152 + char buffer[CONFIG_MAX_NAME + 1];
153 + snprintfz(buffer, CONFIG_MAX_NAME, "performance metrics for disks with major %d", major);
154 + major_configs[major] = (char)config_get_boolean(CONFIG_SECTION_DISKSTATS, buffer, 1);
155 + }
156 +
157 + return (int)major_configs[major];
158 +}
159 +
160 static inline int get_disk_name_from_path(const char *path, char *result, size_t result_size, unsigned long major, unsigned long minor, char *disk) {
161 char filename[FILENAME_MAX + 1];
162 int found = 0;
@@ -160,6 +234,103 @@ static inline char *get_disk_name(unsigned long major, unsigned long minor, char
234 return strdup(result);
235 }
236
237 +static void get_disk_config(struct disk *d) {
238 + int def_enable = global_enable_new_disks_detected_at_runtime;
239 +
240 + if(def_enable != CONFIG_BOOLEAN_NO && (simple_pattern_matches(excluded_disks, d->device) || simple_pattern_matches(excluded_disks, d->disk)))
241 + def_enable = CONFIG_BOOLEAN_NO;
242 +
243 + char var_name[4096 + 1];
244 + snprintfz(var_name, 4096, "plugin:proc:/proc/diskstats:%s", d->disk);
245 +
246 + def_enable = config_get_boolean_ondemand(var_name, "enable", def_enable);
247 + if(unlikely(def_enable == CONFIG_BOOLEAN_NO)) {
248 + // the user does not want any metrics for this disk
249 + d->do_io = CONFIG_BOOLEAN_NO;
250 + d->do_ops = CONFIG_BOOLEAN_NO;
251 + d->do_mops = CONFIG_BOOLEAN_NO;
252 + d->do_iotime = CONFIG_BOOLEAN_NO;
253 + d->do_qops = CONFIG_BOOLEAN_NO;
254 + d->do_util = CONFIG_BOOLEAN_NO;
255 + d->do_backlog = CONFIG_BOOLEAN_NO;
256 + d->do_bcache = CONFIG_BOOLEAN_NO;
257 + }
258 + else {
259 + // this disk is enabled
260 + // check its direct settings
261 +
262 + int def_performance = CONFIG_BOOLEAN_AUTO;
263 +
264 + // since this is 'on demand' we can figure the performance settings
265 + // based on the type of disk
266 +
267 + if(!d->device_is_bcache) {
268 + switch(d->type) {
269 + default:
270 + case DISK_TYPE_UNKNOWN:
271 + break;
272 +
273 + case DISK_TYPE_PHYSICAL:
274 + def_performance = global_enable_performance_for_physical_disks;
275 + break;
276 +
277 + case DISK_TYPE_PARTITION:
278 + def_performance = global_enable_performance_for_partitions;
279 + break;
280 +
281 + case DISK_TYPE_VIRTUAL:
282 + def_performance = global_enable_performance_for_virtual_disks;
283 + break;
284 + }
285 + }
286 +
287 + // check if we have to disable performance for this disk
288 + if(def_performance)
289 + def_performance = is_major_enabled((int)d->major);
290 +
291 + // ------------------------------------------------------------
292 + // now we have def_performance and def_space
293 + // to work further
294 +
295 + // def_performance
296 + // check the user configuration (this will also show our 'on demand' decision)
297 + def_performance = config_get_boolean_ondemand(var_name, "enable performance metrics", def_performance);
298 +
299 + int ddo_io = CONFIG_BOOLEAN_NO,
300 + ddo_ops = CONFIG_BOOLEAN_NO,
301 + ddo_mops = CONFIG_BOOLEAN_NO,
302 + ddo_iotime = CONFIG_BOOLEAN_NO,
303 + ddo_qops = CONFIG_BOOLEAN_NO,
304 + ddo_util = CONFIG_BOOLEAN_NO,
305 + ddo_backlog = CONFIG_BOOLEAN_NO,
306 + ddo_bcache = CONFIG_BOOLEAN_NO;
307 +
308 + // we enable individual performance charts only when def_performance is not disabled
309 + if(unlikely(def_performance != CONFIG_BOOLEAN_NO)) {
310 + ddo_io = global_do_io,
311 + ddo_ops = global_do_ops,
312 + ddo_mops = global_do_mops,
313 + ddo_iotime = global_do_iotime,
314 + ddo_qops = global_do_qops,
315 + ddo_util = global_do_util,
316 + ddo_backlog = global_do_backlog,
317 + ddo_bcache = global_do_bcache;
318 + }
319 +
320 + d->do_io = config_get_boolean_ondemand(var_name, "bandwidth", ddo_io);
321 + d->do_ops = config_get_boolean_ondemand(var_name, "operations", ddo_ops);
322 + d->do_mops = config_get_boolean_ondemand(var_name, "merged operations", ddo_mops);
323 + d->do_iotime = config_get_boolean_ondemand(var_name, "i/o time", ddo_iotime);
324 + d->do_qops = config_get_boolean_ondemand(var_name, "queued operations", ddo_qops);
325 + d->do_util = config_get_boolean_ondemand(var_name, "utilization percentage", ddo_util);
326 + d->do_backlog = config_get_boolean_ondemand(var_name, "backlog", ddo_backlog);
327 +
328 + if(d->device_is_bcache)
329 + d->do_bcache = config_get_boolean_ondemand(var_name, "bcache", ddo_bcache);
330 + else
331 + d->do_bcache = 0;
332 + }
333 +}
334
335 static struct disk *get_disk(unsigned long major, unsigned long minor, char *disk) {
336 static struct mountinfo *disk_mountinfo_root = NULL;
@@ -183,7 +354,6 @@ static struct disk *get_disk(unsigned long major, unsigned long minor, char *dis
354 d->major = major;
355 d->minor = minor;
356 d->type = DISK_TYPE_UNKNOWN; // Default type. Changed later if not correct.
186 - d->configured = 0;
357 d->sector_size = 512; // the default, will be changed below
358 d->next = NULL;
359
@@ -299,51 +469,72 @@ static struct disk *get_disk(unsigned long major, unsigned long minor, char *dis
469 }
470 */
471
302 - return d;
303 -}
472 + // ------------------------------------------------------------------------
473 + // check if the device is a bcache
474
305 -static inline int is_major_enabled(int major) {
306 - static int8_t *major_configs = NULL;
307 - static size_t major_size = 0;
475 + struct stat bcache;
476 + snprintfz(buffer, FILENAME_MAX, path_to_sys_block_device_bcache, disk);
477 + if(unlikely(stat(buffer, &bcache) == 0 && (bcache.st_mode & S_IFMT) == S_IFDIR)) {
478 + // we have the 'bcache' directory
479 + d->device_is_bcache = 1;
480
309 - if(major < 0) return 1;
481 + char buffer2[FILENAME_MAX + 1];
482
311 - size_t wanted_size = (size_t)major + 1;
483 + snprintfz(buffer2, FILENAME_MAX, "%s/dirty_data", buffer);
484 + if(access(buffer2, R_OK) == 0)
485 + d->bcache_filename_dirty_data = strdupz(buffer2);
486 + else
487 + error("bcache file '%s' cannot be read.", buffer2);
488
313 - if(major_size < wanted_size) {
314 - major_configs = reallocz(major_configs, wanted_size * sizeof(int8_t));
489 + snprintfz(buffer2, FILENAME_MAX, "%s/cache/cache_available_percent", buffer);
490 + if(access(buffer2, R_OK) == 0)
491 + d->bcache_filename_cache_available_percent = strdupz(buffer2);
492 + else
493 + error("bcache file '%s' cannot be read.", buffer2);
494
316 - size_t i;
317 - for(i = major_size; i < wanted_size ; i++)
318 - major_configs[i] = -1;
495 + snprintfz(buffer2, FILENAME_MAX, "%s/stats_total/cache_hits", buffer);
496 + if(access(buffer2, R_OK) == 0)
497 + d->bcache_filename_cache_hits = strdupz(buffer2);
498 + else
499 + error("bcache file '%s' cannot be read.", buffer2);
500
320 - major_size = wanted_size;
321 - }
501 + snprintfz(buffer2, FILENAME_MAX, "%s/stats_total/cache_misses", buffer);
502 + if(access(buffer2, R_OK) == 0)
503 + d->bcache_filename_cache_misses = strdupz(buffer2);
504 + else
505 + error("bcache file '%s' cannot be read.", buffer2);
506
323 - if(major_configs[major] == -1) {
324 - char buffer[CONFIG_MAX_NAME + 1];
325 - snprintfz(buffer, CONFIG_MAX_NAME, "performance metrics for disks with major %d", major);
326 - major_configs[major] = (char)config_get_boolean(CONFIG_SECTION_DISKSTATS, buffer, 1);
507 + snprintfz(buffer2, FILENAME_MAX, "%s/stats_total/cache_bypass_hits", buffer);
508 + if(access(buffer2, R_OK) == 0)
509 + d->bcache_filename_cache_bypass_hits = strdupz(buffer2);
510 + else
511 + error("bcache file '%s' cannot be read.", buffer2);
512 +
513 + snprintfz(buffer2, FILENAME_MAX, "%s/stats_total/cache_bypass_misses", buffer);
514 + if(access(buffer2, R_OK) == 0)
515 + d->bcache_filename_cache_bypass_misses = strdupz(buffer2);
516 + else
517 + error("bcache file '%s' cannot be read.", buffer2);
518 +
519 + snprintfz(buffer2, FILENAME_MAX, "%s/stats_total/cache_miss_collisions", buffer);
520 + if(access(buffer2, R_OK) == 0)
521 + d->bcache_filename_cache_miss_collisions = strdupz(buffer2);
522 + else
523 + error("bcache file '%s' cannot be read.", buffer2);
524 +
525 + snprintfz(buffer2, FILENAME_MAX, "%s/stats_total/cache_readaheads", buffer);
526 + if(access(buffer2, R_OK) == 0)
527 + d->bcache_filename_cache_readaheads = strdupz(buffer2);
528 + else
529 + error("bcache file '%s' cannot be read.", buffer2);
530 }
531
329 - return (int)major_configs[major];
532 + get_disk_config(d);
533 + return d;
534 }
535
536 int do_proc_diskstats(int update_every, usec_t dt) {
537 static procfile *ff = NULL;
334 - static int global_enable_new_disks_detected_at_runtime = CONFIG_BOOLEAN_YES,
335 - global_enable_performance_for_physical_disks = CONFIG_BOOLEAN_AUTO,
336 - global_enable_performance_for_virtual_disks = CONFIG_BOOLEAN_AUTO,
337 - global_enable_performance_for_partitions = CONFIG_BOOLEAN_NO,
338 - global_do_io = CONFIG_BOOLEAN_AUTO,
339 - global_do_ops = CONFIG_BOOLEAN_AUTO,
340 - global_do_mops = CONFIG_BOOLEAN_AUTO,
341 - global_do_iotime = CONFIG_BOOLEAN_AUTO,
342 - global_do_qops = CONFIG_BOOLEAN_AUTO,
343 - global_do_util = CONFIG_BOOLEAN_AUTO,
344 - global_do_backlog = CONFIG_BOOLEAN_AUTO,
345 - globals_initialized = 0,
346 - global_cleanup_removed_disks = 1;
538
539 if(unlikely(!globals_initialized)) {
540 globals_initialized = 1;
@@ -360,6 +551,7 @@ int do_proc_diskstats(int update_every, usec_t dt) {
551 global_do_qops = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "queued operations for all disks", global_do_qops);
552 global_do_util = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "utilization percentage for all disks", global_do_util);
553 global_do_backlog = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "backlog for all disks", global_do_backlog);
554 + global_do_bcache = config_get_boolean_ondemand(CONFIG_SECTION_DISKSTATS, "bcache for all disks", global_do_bcache);
555
556 global_cleanup_removed_disks = config_get_boolean(CONFIG_SECTION_DISKSTATS, "remove charts of removed disks" , global_cleanup_removed_disks);
557
@@ -368,17 +560,20 @@ int do_proc_diskstats(int update_every, usec_t dt) {
560 snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/block/%s");
561 path_to_sys_block_device = config_get(CONFIG_SECTION_DISKSTATS, "path to get block device", buffer);
562
563 + snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/block/%s/bcache");
564 + path_to_sys_block_device_bcache = config_get(CONFIG_SECTION_DISKSTATS, "path to get block device bcache", buffer);
565 +
566 snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/devices/virtual/block/%s");
567 path_to_sys_devices_virtual_block_device = config_get(CONFIG_SECTION_DISKSTATS, "path to get virtual block device", buffer);
568
569 snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/dev/block/%lu:%lu/%s");
570 path_to_sys_dev_block_major_minor_string = config_get(CONFIG_SECTION_DISKSTATS, "path to get block device infos", buffer);
571
377 - snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/block/%s/queue/hw_sector_size");
378 - path_to_get_hw_sector_size = config_get(CONFIG_SECTION_DISKSTATS, "path to get h/w sector size", buffer);
572 + //snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/block/%s/queue/hw_sector_size");
573 + //path_to_get_hw_sector_size = config_get(CONFIG_SECTION_DISKSTATS, "path to get h/w sector size", buffer);
574
380 - snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/dev/block/%lu:%lu/subsystem/%s/../queue/hw_sector_size");
381 - path_to_get_hw_sector_size_partitions = config_get(CONFIG_SECTION_DISKSTATS, "path to get h/w sector size for partitions", buffer);
575 + //snprintfz(buffer, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/dev/block/%lu:%lu/subsystem/%s/../queue/hw_sector_size");
576 + //path_to_get_hw_sector_size_partitions = config_get(CONFIG_SECTION_DISKSTATS, "path to get h/w sector size for partitions", buffer);
577
578 snprintfz(buffer, FILENAME_MAX, "%s/dev/mapper", netdata_configured_host_prefix);
579 path_to_device_mapper = config_get(CONFIG_SECTION_DISKSTATS, "path to device mapper", buffer);
@@ -390,6 +585,12 @@ int do_proc_diskstats(int update_every, usec_t dt) {
585 path_to_device_id = config_get(CONFIG_SECTION_DISKSTATS, "path to /dev/disk/by-id", buffer);
586
587 name_disks_by_id = config_get_boolean(CONFIG_SECTION_DISKSTATS, "name disks by id", name_disks_by_id);
588 +
589 + excluded_disks = simple_pattern_create(
590 + config_get(CONFIG_SECTION_DISKSTATS, "exclude disks", DEFAULT_EXCLUDED_DISKS)
591 + , NULL
592 + , SIMPLE_PATTERN_EXACT
593 + );
594 }
595
596 // --------------------------------------------------------------------------
@@ -483,6 +684,9 @@ int do_proc_diskstats(int update_every, usec_t dt) {
684 struct disk *d = get_disk(major, minor, disk);
685 d->updated = 1;
686
687 + // --------------------------------------------------------------------------
688 + // count the global system disk I/O of physical disks
689 +
690 if(unlikely(d->type == DISK_TYPE_PHYSICAL)) {
691 system_read_kb += readsectors * d->sector_size / 1024;
692 system_write_kb += writesectors * d->sector_size / 1024;
@@ -495,109 +699,6 @@ int do_proc_diskstats(int update_every, usec_t dt) {
699 if(!family) family = d->disk;
700
701
498 - // --------------------------------------------------------------------------
499 - // Check the configuration for the device
500 -
501 - if(unlikely(!d->configured)) {
502 - d->configured = 1;
503 -
504 - static SIMPLE_PATTERN *excluded_disks = NULL;
505 -
506 - if(unlikely(!excluded_disks)) {
507 - excluded_disks = simple_pattern_create(
508 - config_get(CONFIG_SECTION_DISKSTATS, "exclude disks", DEFAULT_EXCLUDED_DISKS)
509 - , NULL
510 - , SIMPLE_PATTERN_EXACT
511 - );
512 - }
513 -
514 - int def_enable = global_enable_new_disks_detected_at_runtime;
515 -
516 - if(def_enable != CONFIG_BOOLEAN_NO && (simple_pattern_matches(excluded_disks, d->device) || simple_pattern_matches(excluded_disks, d->disk)))
517 - def_enable = CONFIG_BOOLEAN_NO;
518 -
519 - char var_name[4096 + 1];
520 - snprintfz(var_name, 4096, "plugin:proc:/proc/diskstats:%s", d->disk);
521 -
522 - def_enable = config_get_boolean_ondemand(var_name, "enable", def_enable);
523 - if(unlikely(def_enable == CONFIG_BOOLEAN_NO)) {
524 - // the user does not want any metrics for this disk
525 - d->do_io = CONFIG_BOOLEAN_NO;
526 - d->do_ops = CONFIG_BOOLEAN_NO;
527 - d->do_mops = CONFIG_BOOLEAN_NO;
528 - d->do_iotime = CONFIG_BOOLEAN_NO;
529 - d->do_qops = CONFIG_BOOLEAN_NO;
530 - d->do_util = CONFIG_BOOLEAN_NO;
531 - d->do_backlog = CONFIG_BOOLEAN_NO;
532 - }
533 - else {
534 - // this disk is enabled
535 - // check its direct settings
536 -
537 - int def_performance = CONFIG_BOOLEAN_AUTO;
538 -
539 - // since this is 'on demand' we can figure the performance settings
540 - // based on the type of disk
541 -
542 - switch(d->type) {
543 - default:
544 - case DISK_TYPE_UNKNOWN:
545 - break;
546 -
547 - case DISK_TYPE_PHYSICAL:
548 - def_performance = global_enable_performance_for_physical_disks;
549 - break;
550 -
551 - case DISK_TYPE_PARTITION:
552 - def_performance = global_enable_performance_for_partitions;
553 - break;
554 -
555 - case DISK_TYPE_VIRTUAL:
556 - def_performance = global_enable_performance_for_virtual_disks;
557 - break;
558 - }
559 -
560 - // check if we have to disable performance for this disk
561 - if(def_performance)
562 - def_performance = is_major_enabled((int)major);
563 -
564 - // ------------------------------------------------------------
565 - // now we have def_performance and def_space
566 - // to work further
567 -
568 - // def_performance
569 - // check the user configuration (this will also show our 'on demand' decision)
570 - def_performance = config_get_boolean_ondemand(var_name, "enable performance metrics", def_performance);
571 -
572 - int ddo_io = CONFIG_BOOLEAN_NO,
573 - ddo_ops = CONFIG_BOOLEAN_NO,
574 - ddo_mops = CONFIG_BOOLEAN_NO,
575 - ddo_iotime = CONFIG_BOOLEAN_NO,
576 - ddo_qops = CONFIG_BOOLEAN_NO,
577 - ddo_util = CONFIG_BOOLEAN_NO,
578 - ddo_backlog = CONFIG_BOOLEAN_NO;
579 -
580 - // we enable individual performance charts only when def_performance is not disabled
581 - if(unlikely(def_performance != CONFIG_BOOLEAN_NO)) {
582 - ddo_io = global_do_io,
583 - ddo_ops = global_do_ops,
584 - ddo_mops = global_do_mops,
585 - ddo_iotime = global_do_iotime,
586 - ddo_qops = global_do_qops,
587 - ddo_util = global_do_util,
588 - ddo_backlog = global_do_backlog;
589 - }
590 -
591 - d->do_io = config_get_boolean_ondemand(var_name, "bandwidth", ddo_io);
592 - d->do_ops = config_get_boolean_ondemand(var_name, "operations", ddo_ops);
593 - d->do_mops = config_get_boolean_ondemand(var_name, "merged operations", ddo_mops);
594 - d->do_iotime = config_get_boolean_ondemand(var_name, "i/o time", ddo_iotime);
595 - d->do_qops = config_get_boolean_ondemand(var_name, "queued operations", ddo_qops);
596 - d->do_util = config_get_boolean_ondemand(var_name, "utilization percentage", ddo_util);
597 - d->do_backlog = config_get_boolean_ondemand(var_name, "backlog", ddo_backlog);
598 - }
599 - }
600 -
702 // --------------------------------------------------------------------------
703 // Do performance metrics
704
@@ -918,6 +1019,211 @@ int do_proc_diskstats(int update_every, usec_t dt) {
1019 rrdset_done(d->st_svctm);
1020 }
1021 }
1022 +
1023 + // --------------------------------------------------------------------------
1024 + // read bcache metrics and generate the bcache charts
1025 +
1026 + if(d->device_is_bcache && d->do_bcache != CONFIG_BOOLEAN_NO) {
1027 + unsigned long long int
1028 + cache_bypass_hits = 0,
1029 + cache_bypass_misses = 0,
1030 + cache_hits = 0,
1031 + cache_miss_collisions = 0,
1032 + cache_misses = 0,
1033 + cache_readaheads = 0,
1034 + dirty_size = 0,
1035 + cache_available_percent = 0;
1036 +
1037 + // read the bcache values
1038 +
1039 + if(d->bcache_filename_dirty_data) {
1040 + char buffer[50 + 1];
1041 + if(read_file(d->bcache_filename_dirty_data, buffer, 50) == 0) {
1042 + static int unknown_units_error = 10;
1043 +
1044 + char *end = NULL;
1045 + long double value = str2ld(buffer, &end);
1046 + if(end && *end) {
1047 + if(*end == 'k' || *end == 'K')
1048 + dirty_size = (unsigned long long int)(value * 1024.0);
1049 + else if(*end == 'M')
1050 + dirty_size = (unsigned long long int)(value * 1024.0 * 1024.0);
1051 + else if(*end == 'G' || *end == 'g')
1052 + dirty_size = (unsigned long long int)(value * 1024.0 * 1024.0 * 1024.0);
1053 + else if(unknown_units_error > 0) {
1054 + error("bcache provides value '%s' with unknown units '%s'", buffer, end);
1055 + unknown_units_error--;
1056 + }
1057 + }
1058 + }
1059 + }
1060 +
1061 + if(d->bcache_filename_cache_available_percent)
1062 + read_single_number_file(d->bcache_filename_cache_available_percent, &cache_available_percent);
1063 +
1064 + if(d->bcache_filename_cache_hits)
1065 + read_single_number_file(d->bcache_filename_cache_hits, &cache_hits);
1066 +
1067 + if(d->bcache_filename_cache_misses)
1068 + read_single_number_file(d->bcache_filename_cache_misses, &cache_misses);
1069 +
1070 + if(d->bcache_filename_cache_miss_collisions)
1071 + read_single_number_file(d->bcache_filename_cache_miss_collisions, &cache_miss_collisions);
1072 +
1073 + if(d->bcache_filename_cache_bypass_hits)
1074 + read_single_number_file(d->bcache_filename_cache_bypass_hits, &cache_bypass_hits);
1075 +
1076 + if(d->bcache_filename_cache_bypass_misses)
1077 + read_single_number_file(d->bcache_filename_cache_bypass_misses, &cache_bypass_misses);
1078 +
1079 + if(d->bcache_filename_cache_readaheads)
1080 + read_single_number_file(d->bcache_filename_cache_readaheads, &cache_readaheads);
1081 +
1082 +
1083 + // update the charts
1084 +
1085 + {
1086 + if(unlikely(!d->st_bcache_size)) {
1087 + d->st_bcache_size = rrdset_create_localhost(
1088 + "disk_bcache_size"
1089 + , d->device
1090 + , d->disk
1091 + , family
1092 + , "disk.bcache_size"
1093 + , "Block Cache Sizes"
1094 + , "MB"
1095 + , "proc"
1096 + , "diskstats"
1097 + , 2120
1098 + , update_every
1099 + , RRDSET_TYPE_AREA
1100 + );
1101 +
1102 + d->rd_bcache_dirty_size = rrddim_add(d->st_bcache_size, "dirty", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
1103 + }
1104 + else rrdset_next(d->st_bcache_size);
1105 +
1106 + rrddim_set_by_pointer(d->st_bcache_size, d->rd_bcache_dirty_size, dirty_size);
1107 + rrdset_done(d->st_bcache_size);
1108 + }
1109 +
1110 + {
1111 + if(unlikely(!d->st_bcache_usage)) {
1112 + d->st_bcache_usage = rrdset_create_localhost(
1113 + "disk_bcache_usage"
1114 + , d->device
1115 + , d->disk
1116 + , family
1117 + , "disk.bcache_usage"
1118 + , "Block Cache Usage"
1119 + , "percent"
1120 + , "proc"
1121 + , "diskstats"
1122 + , 2121
1123 + , update_every
1124 + , RRDSET_TYPE_AREA
1125 + );
1126 +
1127 + d->rd_bcache_available_percent = rrddim_add(d->st_bcache_usage, "avail", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
1128 + }
1129 + else rrdset_next(d->st_bcache_usage);
1130 +
1131 + rrddim_set_by_pointer(d->st_bcache_usage, d->rd_bcache_available_percent, cache_available_percent);
1132 + rrdset_done(d->st_bcache_usage);
1133 + }
1134 +
1135 + if(d->do_bcache == CONFIG_BOOLEAN_YES || (d->do_bcache == CONFIG_BOOLEAN_AUTO && (cache_hits != 0 || cache_misses != 0 || cache_miss_collisions != 0))) {
1136 +
1137 + cache_misses -= cache_miss_collisions;
1138 +
1139 + if(unlikely(!d->st_bcache)) {
1140 + d->st_bcache = rrdset_create_localhost(
1141 + "disk_bcache"
1142 + , d->device
1143 + , d->disk
1144 + , family
1145 + , "disk.bcache"
1146 + , "Block Cache I/O"
1147 + , "operations/s"
1148 + , "proc"
1149 + , "diskstats"
1150 + , 2122
1151 + , update_every
1152 + , RRDSET_TYPE_LINE
1153 + );
1154 +
1155 + rrdset_flag_set(d->st_bcache, RRDSET_FLAG_DETAIL);
1156 +
1157 + d->rd_bcache_hits = rrddim_add(d->st_bcache, "hits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1158 + d->rd_bcache_misses = rrddim_add(d->st_bcache, "misses", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
1159 + d->rd_bcache_miss_collisions = rrddim_add(d->st_bcache, "collisions", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1160 + }
1161 + else rrdset_next(d->st_bcache);
1162 +
1163 + rrddim_set_by_pointer(d->st_bcache, d->rd_bcache_hits, cache_hits);
1164 + rrddim_set_by_pointer(d->st_bcache, d->rd_bcache_misses, cache_misses);
1165 + rrddim_set_by_pointer(d->st_bcache, d->rd_bcache_miss_collisions, cache_miss_collisions);
1166 + rrdset_done(d->st_bcache);
1167 + }
1168 +
1169 + if(d->do_bcache == CONFIG_BOOLEAN_YES || (d->do_bcache == CONFIG_BOOLEAN_AUTO && (cache_bypass_hits != 0 || cache_bypass_misses != 0))) {
1170 +
1171 + if(unlikely(!d->st_bcache_bypass)) {
1172 + d->st_bcache_bypass = rrdset_create_localhost(
1173 + "disk_bcache_bypass"
1174 + , d->device
1175 + , d->disk
1176 + , family
1177 + , "disk.bcache_bypass"
1178 + , "Block Cache Bypass I/O"
1179 + , "operations/s"
1180 + , "proc"
1181 + , "diskstats"
1182 + , 2123
1183 + , update_every
1184 + , RRDSET_TYPE_LINE
1185 + );
1186 +
1187 + rrdset_flag_set(d->st_bcache_bypass, RRDSET_FLAG_DETAIL);
1188 +
1189 + d->rd_bcache_bypass_hits = rrddim_add(d->st_bcache_bypass, "hits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1190 + d->rd_bcache_bypass_misses = rrddim_add(d->st_bcache_bypass, "misses", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
1191 + }
1192 + else rrdset_next(d->st_bcache_bypass);
1193 +
1194 + rrddim_set_by_pointer(d->st_bcache_bypass, d->rd_bcache_bypass_hits, cache_bypass_hits);
1195 + rrddim_set_by_pointer(d->st_bcache_bypass, d->rd_bcache_bypass_misses, cache_bypass_misses);
1196 + rrdset_done(d->st_bcache_bypass);
1197 + }
1198 +
1199 + if(d->do_bcache == CONFIG_BOOLEAN_YES || (d->do_bcache == CONFIG_BOOLEAN_AUTO && cache_readaheads != 0)) {
1200 +
1201 + if(unlikely(!d->st_bcache_readaheads)) {
1202 + d->st_bcache_readaheads = rrdset_create_localhost(
1203 + "disk_bcache_readahead"
1204 + , d->device
1205 + , d->disk
1206 + , family
1207 + , "disk.bcache_readahead"
1208 + , "Block Cache Readaheads"
1209 + , "events/s"
1210 + , "proc"
1211 + , "diskstats"
1212 + , 2124
1213 + , update_every
1214 + , RRDSET_TYPE_LINE
1215 + );
1216 +
1217 + rrdset_flag_set(d->st_bcache_readaheads, RRDSET_FLAG_DETAIL);
1218 +
1219 + d->rd_bcache_readaheads = rrddim_add(d->st_bcache_readaheads, "readaheads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1220 + }
1221 + else rrdset_next(d->st_bcache_readaheads);
1222 +
1223 + rrddim_set_by_pointer(d->st_bcache_readaheads, d->rd_bcache_readaheads, cache_readaheads);
1224 + rrdset_done(d->st_bcache_readaheads);
1225 + }
1226 + }
1227 }
1228
1229
@@ -973,6 +1279,11 @@ int do_proc_diskstats(int update_every, usec_t dt) {
1279 rrdset_obsolete_and_pointer_null(d->st_qops);
1280 rrdset_obsolete_and_pointer_null(d->st_svctm);
1281 rrdset_obsolete_and_pointer_null(d->st_util);
1282 + rrdset_obsolete_and_pointer_null(d->st_bcache);
1283 + rrdset_obsolete_and_pointer_null(d->st_bcache_bypass);
1284 + rrdset_obsolete_and_pointer_null(d->st_bcache_readaheads);
1285 + rrdset_obsolete_and_pointer_null(d->st_bcache_size);
1286 + rrdset_obsolete_and_pointer_null(d->st_bcache_usage);
1287
1288 if(d == disk_root) {
1289 disk_root = d = d->next;
@@ -982,6 +1293,15 @@ int do_proc_diskstats(int update_every, usec_t dt) {
1293 last->next = d = d->next;
1294 }
1295
1296 + freez(t->bcache_filename_dirty_data);
1297 + freez(t->bcache_filename_cache_available_percent);
1298 + freez(t->bcache_filename_cache_hits);
1299 + freez(t->bcache_filename_cache_misses);
1300 + freez(t->bcache_filename_cache_miss_collisions);
1301 + freez(t->bcache_filename_cache_bypass_hits);
1302 + freez(t->bcache_filename_cache_bypass_misses);
1303 + freez(t->bcache_filename_cache_readaheads);
1304 +
1305 freez(t->disk);
1306 freez(t->device);
1307 freez(t->mount_point);