master
c 720 lines 41.3 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "plugin_freebsd.h"
4
5 #include <sys/devicestat.h>
6
7 struct disk {
8 char *name;
9 uint32_t hash;
10 size_t len;
11
12 // flags
13 int configured;
14 int enabled;
15 int updated;
16
17 int do_io;
18 int do_ops;
19 int do_qops;
20 int do_util;
21 int do_iotime;
22 int do_await;
23 int do_avagsz;
24 int do_svctm;
25
26
27 // data for differential charts
28
29 struct prev_dstat {
30 collected_number bytes_read;
31 collected_number bytes_write;
32 collected_number bytes_free;
33 collected_number operations_read;
34 collected_number operations_write;
35 collected_number operations_other;
36 collected_number operations_free;
37 collected_number duration_read_ms;
38 collected_number duration_write_ms;
39 collected_number duration_other_ms;
40 collected_number duration_free_ms;
41 collected_number busy_time_ms;
42 } prev_dstat;
43
44 // charts and dimensions
45
46 RRDSET *st_io;
47 RRDDIM *rd_io_in;
48 RRDDIM *rd_io_out;
49 RRDDIM *rd_io_free;
50
51 RRDSET *st_ops;
52 RRDDIM *rd_ops_in;
53 RRDDIM *rd_ops_out;
54 RRDDIM *rd_ops_other;
55 RRDDIM *rd_ops_free;
56
57 RRDSET *st_qops;
58 RRDDIM *rd_qops;
59
60 RRDSET *st_util;
61 RRDDIM *rd_util;
62
63 RRDSET *st_iotime;
64 RRDDIM *rd_iotime_in;
65 RRDDIM *rd_iotime_out;
66 RRDDIM *rd_iotime_other;
67 RRDDIM *rd_iotime_free;
68
69 RRDSET *st_await;
70 RRDDIM *rd_await_in;
71 RRDDIM *rd_await_out;
72 RRDDIM *rd_await_other;
73 RRDDIM *rd_await_free;
74
75 RRDSET *st_avagsz;
76 RRDDIM *rd_avagsz_in;
77 RRDDIM *rd_avagsz_out;
78 RRDDIM *rd_avagsz_free;
79
80 RRDSET *st_svctm;
81 RRDDIM *rd_svctm;
82
83 struct disk *next;
84 };
85
86 static struct disk *disks_root = NULL, *disks_last_used = NULL;
87
88 static size_t disks_added = 0, disks_found = 0;
89
90 static void disk_free(struct disk *dm) {
91 if (likely(dm->st_io))
92 rrdset_is_obsolete___safe_from_collector_thread(dm->st_io);
93 if (likely(dm->st_ops))
94 rrdset_is_obsolete___safe_from_collector_thread(dm->st_ops);
95 if (likely(dm->st_qops))
96 rrdset_is_obsolete___safe_from_collector_thread(dm->st_qops);
97 if (likely(dm->st_util))
98 rrdset_is_obsolete___safe_from_collector_thread(dm->st_util);
99 if (likely(dm->st_iotime))
100 rrdset_is_obsolete___safe_from_collector_thread(dm->st_iotime);
101 if (likely(dm->st_await))
102 rrdset_is_obsolete___safe_from_collector_thread(dm->st_await);
103 if (likely(dm->st_avagsz))
104 rrdset_is_obsolete___safe_from_collector_thread(dm->st_avagsz);
105 if (likely(dm->st_svctm))
106 rrdset_is_obsolete___safe_from_collector_thread(dm->st_svctm);
107
108 disks_added--;
109 freez(dm->name);
110 freez(dm);
111 }
112
113 static void disks_cleanup() {
114 if (likely(disks_found == disks_added)) return;
115
116 struct disk *dm = disks_root, *last = NULL;
117 while(dm) {
118 if (unlikely(!dm->updated)) {
119 // collector_info("Removing disk '%s', linked after '%s'", dm->name, last?last->name:"ROOT");
120
121 if (disks_last_used == dm)
122 disks_last_used = last;
123
124 struct disk *t = dm;
125
126 if (dm == disks_root || !last)
127 disks_root = dm = dm->next;
128
129 else
130 last->next = dm = dm->next;
131
132 t->next = NULL;
133 disk_free(t);
134 }
135 else {
136 last = dm;
137 dm->updated = 0;
138 dm = dm->next;
139 }
140 }
141 }
142
143 static struct disk *get_disk(const char *name) {
144 struct disk *dm;
145
146 uint32_t hash = simple_hash(name);
147
148 // search it, from the last position to the end
149 for(dm = disks_last_used ; dm ; dm = dm->next) {
150 if (unlikely(hash == dm->hash && !strcmp(name, dm->name))) {
151 disks_last_used = dm->next;
152 return dm;
153 }
154 }
155
156 // search it from the beginning to the last position we used
157 for(dm = disks_root ; dm != disks_last_used ; dm = dm->next) {
158 if (unlikely(hash == dm->hash && !strcmp(name, dm->name))) {
159 disks_last_used = dm->next;
160 return dm;
161 }
162 }
163
164 // create a new one
165 dm = callocz(1, sizeof(struct disk));
166 dm->name = strdupz(name);
167 dm->hash = simple_hash(dm->name);
168 dm->len = strlen(dm->name);
169 disks_added++;
170
171 // link it to the end
172 if (disks_root) {
173 struct disk *e;
174 for(e = disks_root; e->next ; e = e->next) ;
175 e->next = dm;
176 }
177 else
178 disks_root = dm;
179
180 return dm;
181 }
182
183 // --------------------------------------------------------------------------------------------------------------------
184 // kern.devstat
185
186 int do_kern_devstat(int update_every, usec_t dt) {
187
188 #define DEFAULT_EXCLUDED_DISKS ""
189 #define CONFIG_SECTION_KERN_DEVSTAT "plugin:freebsd:kern.devstat"
190 #define BINTIME_SCALE 5.42101086242752217003726400434970855712890625e-17 // this is 1000/2^64
191
192 static int enable_new_disks = -1;
193 static int enable_pass_devices = -1, do_system_io = -1, do_io = -1, do_ops = -1, do_qops = -1, do_util = -1,
194 do_iotime = -1, do_await = -1, do_avagsz = -1, do_svctm = -1;
195 static SIMPLE_PATTERN *excluded_disks = NULL;
196
197 if (unlikely(enable_new_disks == -1)) {
198 enable_new_disks = inicfg_get_boolean_ondemand(&netdata_config, CONFIG_SECTION_KERN_DEVSTAT,
199 "enable new disks detected at runtime", CONFIG_BOOLEAN_AUTO);
200
201 enable_pass_devices = inicfg_get_boolean_ondemand(&netdata_config, CONFIG_SECTION_KERN_DEVSTAT,
202 "performance metrics for pass devices", CONFIG_BOOLEAN_AUTO);
203
204 do_system_io = inicfg_get_boolean_ondemand(&netdata_config, CONFIG_SECTION_KERN_DEVSTAT, "total bandwidth for all disks",
205 CONFIG_BOOLEAN_YES);
206
207 do_io = inicfg_get_boolean_ondemand(&netdata_config, CONFIG_SECTION_KERN_DEVSTAT, "bandwidth for all disks",
208 CONFIG_BOOLEAN_AUTO);
209 do_ops = inicfg_get_boolean_ondemand(&netdata_config, CONFIG_SECTION_KERN_DEVSTAT, "operations for all disks",
210 CONFIG_BOOLEAN_AUTO);
211 do_qops = inicfg_get_boolean_ondemand(&netdata_config, CONFIG_SECTION_KERN_DEVSTAT, "queued operations for all disks",
212 CONFIG_BOOLEAN_AUTO);
213 do_util = inicfg_get_boolean_ondemand(&netdata_config, CONFIG_SECTION_KERN_DEVSTAT, "utilization percentage for all disks",
214 CONFIG_BOOLEAN_AUTO);
215 do_iotime = inicfg_get_boolean_ondemand(&netdata_config, CONFIG_SECTION_KERN_DEVSTAT, "i/o time for all disks",
216 CONFIG_BOOLEAN_AUTO);
217 do_await = inicfg_get_boolean_ondemand(&netdata_config, CONFIG_SECTION_KERN_DEVSTAT, "average completed i/o time for all disks",
218 CONFIG_BOOLEAN_AUTO);
219 do_avagsz = inicfg_get_boolean_ondemand(&netdata_config, CONFIG_SECTION_KERN_DEVSTAT, "average completed i/o bandwidth for all disks",
220 CONFIG_BOOLEAN_AUTO);
221 do_svctm = inicfg_get_boolean_ondemand(&netdata_config, CONFIG_SECTION_KERN_DEVSTAT, "average service time for all disks",
222 CONFIG_BOOLEAN_AUTO);
223
224 excluded_disks = simple_pattern_create(
225 inicfg_get(&netdata_config, CONFIG_SECTION_KERN_DEVSTAT, "disable by default disks matching", DEFAULT_EXCLUDED_DISKS),
226 NULL,
227 SIMPLE_PATTERN_EXACT,
228 true);
229 }
230
231 if (likely(do_system_io || do_io || do_ops || do_qops || do_util || do_iotime || do_await || do_avagsz || do_svctm)) {
232 static int mib_numdevs[3] = {0, 0, 0};
233 int numdevs;
234 int common_error = 0;
235
236 if (unlikely(GETSYSCTL_SIMPLE("kern.devstat.numdevs", mib_numdevs, numdevs))) {
237 common_error = 1;
238 } else {
239 static int mib_devstat[3] = {0, 0, 0};
240 static void *devstat_data = NULL;
241 static int old_numdevs = 0;
242
243 if (unlikely(numdevs != old_numdevs)) {
244 devstat_data = reallocz(devstat_data, sizeof(long) + sizeof(struct devstat) *
245 numdevs); // there is generation number before devstat structures
246 old_numdevs = numdevs;
247 }
248 if (unlikely(GETSYSCTL_WSIZE("kern.devstat.all", mib_devstat, devstat_data,
249 sizeof(long) + sizeof(struct devstat) * numdevs))) {
250 common_error = 1;
251 } else {
252 struct devstat *dstat;
253 int i;
254 collected_number total_disk_kbytes_read = 0;
255 collected_number total_disk_kbytes_write = 0;
256
257 disks_found = 0;
258
259 dstat = (struct devstat*)((char*)devstat_data + sizeof(long)); // skip generation number
260
261 for (i = 0; i < numdevs; i++) {
262 if (likely(do_system_io)) {
263 if (((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) ||
264 ((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) {
265 total_disk_kbytes_read += dstat[i].bytes[DEVSTAT_READ] / KILO_FACTOR;
266 total_disk_kbytes_write += dstat[i].bytes[DEVSTAT_WRITE] / KILO_FACTOR;
267 }
268 }
269
270 if (unlikely(!enable_pass_devices))
271 if ((dstat[i].device_type & DEVSTAT_TYPE_PASS) == DEVSTAT_TYPE_PASS)
272 continue;
273
274 if (((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) ||
275 ((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) {
276 char disk[DEVSTAT_NAME_LEN + MAX_INT_DIGITS + 1];
277 struct cur_dstat {
278 collected_number duration_read_ms;
279 collected_number duration_write_ms;
280 collected_number duration_other_ms;
281 collected_number duration_free_ms;
282 collected_number busy_time_ms;
283 } cur_dstat;
284
285 sprintf(disk, "%s%d", dstat[i].device_name, dstat[i].unit_number);
286
287 struct disk *dm = get_disk(disk);
288 dm->updated = 1;
289 disks_found++;
290
291 if(unlikely(!dm->configured)) {
292 char var_name[4096 + 1];
293
294 // this is the first time we see this disk
295
296 // remember we configured it
297 dm->configured = 1;
298
299 dm->enabled = enable_new_disks;
300
301 if (likely(dm->enabled))
302 dm->enabled = !simple_pattern_matches(excluded_disks, disk);
303
304 snprintfz(var_name, 4096, "%s:%s", CONFIG_SECTION_KERN_DEVSTAT, disk);
305 dm->enabled = inicfg_get_boolean_ondemand(&netdata_config, var_name, "enabled", dm->enabled);
306
307 dm->do_io = inicfg_get_boolean_ondemand(&netdata_config, var_name, "bandwidth", do_io);
308 dm->do_ops = inicfg_get_boolean_ondemand(&netdata_config, var_name, "operations", do_ops);
309 dm->do_qops = inicfg_get_boolean_ondemand(&netdata_config, var_name, "queued operations", do_qops);
310 dm->do_util = inicfg_get_boolean_ondemand(&netdata_config, var_name, "utilization percentage", do_util);
311 dm->do_iotime = inicfg_get_boolean_ondemand(&netdata_config, var_name, "i/o time", do_iotime);
312 dm->do_await = inicfg_get_boolean_ondemand(&netdata_config, var_name, "average completed i/o time",
313 do_await);
314 dm->do_avagsz = inicfg_get_boolean_ondemand(&netdata_config, var_name, "average completed i/o bandwidth",
315 do_avagsz);
316 dm->do_svctm = inicfg_get_boolean_ondemand(&netdata_config, var_name, "average service time", do_svctm);
317
318 // initialise data for differential charts
319
320 dm->prev_dstat.bytes_read = dstat[i].bytes[DEVSTAT_READ];
321 dm->prev_dstat.bytes_write = dstat[i].bytes[DEVSTAT_WRITE];
322 dm->prev_dstat.bytes_free = dstat[i].bytes[DEVSTAT_FREE];
323 dm->prev_dstat.operations_read = dstat[i].operations[DEVSTAT_READ];
324 dm->prev_dstat.operations_write = dstat[i].operations[DEVSTAT_WRITE];
325 dm->prev_dstat.operations_other = dstat[i].operations[DEVSTAT_NO_DATA];
326 dm->prev_dstat.operations_free = dstat[i].operations[DEVSTAT_FREE];
327 dm->prev_dstat.duration_read_ms = dstat[i].duration[DEVSTAT_READ].sec * 1000
328 + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
329 dm->prev_dstat.duration_write_ms = dstat[i].duration[DEVSTAT_WRITE].sec * 1000
330 + dstat[i].duration[DEVSTAT_WRITE].frac * BINTIME_SCALE;
331 dm->prev_dstat.duration_other_ms = dstat[i].duration[DEVSTAT_NO_DATA].sec * 1000
332 + dstat[i].duration[DEVSTAT_NO_DATA].frac * BINTIME_SCALE;
333 dm->prev_dstat.duration_free_ms = dstat[i].duration[DEVSTAT_FREE].sec * 1000
334 + dstat[i].duration[DEVSTAT_FREE].frac * BINTIME_SCALE;
335 dm->prev_dstat.busy_time_ms = dstat[i].busy_time.sec * 1000
336 + dstat[i].busy_time.frac * BINTIME_SCALE;
337 }
338
339 cur_dstat.duration_read_ms = dstat[i].duration[DEVSTAT_READ].sec * 1000
340 + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
341 cur_dstat.duration_write_ms = dstat[i].duration[DEVSTAT_WRITE].sec * 1000
342 + dstat[i].duration[DEVSTAT_WRITE].frac * BINTIME_SCALE;
343 cur_dstat.duration_other_ms = dstat[i].duration[DEVSTAT_NO_DATA].sec * 1000
344 + dstat[i].duration[DEVSTAT_NO_DATA].frac * BINTIME_SCALE;
345 cur_dstat.duration_free_ms = dstat[i].duration[DEVSTAT_FREE].sec * 1000
346 + dstat[i].duration[DEVSTAT_FREE].frac * BINTIME_SCALE;
347
348 cur_dstat.busy_time_ms = dstat[i].busy_time.sec * 1000 + dstat[i].busy_time.frac * BINTIME_SCALE;
349
350 if (dm->do_io == CONFIG_BOOLEAN_YES || dm->do_io == CONFIG_BOOLEAN_AUTO) {
351 if (unlikely(!dm->st_io)) {
352 dm->st_io = rrdset_create_localhost("disk",
353 disk,
354 NULL,
355 "io",
356 "disk.io",
357 "Disk I/O Bandwidth",
358 "KiB/s",
359 "freebsd.plugin",
360 "devstat",
361 NETDATA_CHART_PRIO_DISK_IO,
362 update_every,
363 RRDSET_TYPE_AREA
364 );
365
366 dm->rd_io_in = rrddim_add(dm->st_io, "reads", NULL, 1, KILO_FACTOR,
367 RRD_ALGORITHM_INCREMENTAL);
368 dm->rd_io_out = rrddim_add(dm->st_io, "writes", NULL, -1, KILO_FACTOR,
369 RRD_ALGORITHM_INCREMENTAL);
370 dm->rd_io_free = rrddim_add(dm->st_io, "frees", NULL, -1, KILO_FACTOR,
371 RRD_ALGORITHM_INCREMENTAL);
372 rrdlabels_add(dm->st_io->rrdlabels, "device", disk, RRDLABEL_SRC_AUTO);
373 }
374
375 rrddim_set_by_pointer(dm->st_io, dm->rd_io_in, dstat[i].bytes[DEVSTAT_READ]);
376 rrddim_set_by_pointer(dm->st_io, dm->rd_io_out, dstat[i].bytes[DEVSTAT_WRITE]);
377 rrddim_set_by_pointer(dm->st_io, dm->rd_io_free, dstat[i].bytes[DEVSTAT_FREE]);
378 rrdset_done(dm->st_io);
379 }
380
381 if (dm->do_ops == CONFIG_BOOLEAN_YES || dm->do_ops == CONFIG_BOOLEAN_AUTO) {
382 if (unlikely(!dm->st_ops)) {
383 dm->st_ops = rrdset_create_localhost("disk_ops",
384 disk,
385 NULL,
386 "ops",
387 "disk.ops",
388 "Disk Completed I/O Operations",
389 "operations/s",
390 "freebsd.plugin",
391 "devstat",
392 NETDATA_CHART_PRIO_DISK_OPS,
393 update_every,
394 RRDSET_TYPE_LINE
395 );
396
397 dm->rd_ops_in = rrddim_add(dm->st_ops, "reads", NULL, 1, 1,
398 RRD_ALGORITHM_INCREMENTAL);
399 dm->rd_ops_out = rrddim_add(dm->st_ops, "writes", NULL, -1, 1,
400 RRD_ALGORITHM_INCREMENTAL);
401 dm->rd_ops_other = rrddim_add(dm->st_ops, "other", NULL, 1, 1,
402 RRD_ALGORITHM_INCREMENTAL);
403 dm->rd_ops_free = rrddim_add(dm->st_ops, "frees", NULL, -1, 1,
404 RRD_ALGORITHM_INCREMENTAL);
405 rrdlabels_add(dm->st_ops->rrdlabels, "device", disk, RRDLABEL_SRC_AUTO);
406 }
407
408 rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_in, dstat[i].operations[DEVSTAT_READ]);
409 rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_out, dstat[i].operations[DEVSTAT_WRITE]);
410 rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_other, dstat[i].operations[DEVSTAT_NO_DATA]);
411 rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_free, dstat[i].operations[DEVSTAT_FREE]);
412 rrdset_done(dm->st_ops);
413 }
414
415 if (dm->do_qops == CONFIG_BOOLEAN_YES || dm->do_qops == CONFIG_BOOLEAN_AUTO) {
416 if (unlikely(!dm->st_qops)) {
417 dm->st_qops = rrdset_create_localhost("disk_qops",
418 disk,
419 NULL,
420 "ops",
421 "disk.qops",
422 "Disk Current I/O Operations",
423 "operations",
424 "freebsd.plugin",
425 "devstat",
426 NETDATA_CHART_PRIO_DISK_QOPS,
427 update_every,
428 RRDSET_TYPE_LINE
429 );
430
431 dm->rd_qops = rrddim_add(dm->st_qops, "operations", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
432 rrdlabels_add(dm->st_qops->rrdlabels, "device", disk, RRDLABEL_SRC_AUTO);
433 }
434
435 rrddim_set_by_pointer(dm->st_qops, dm->rd_qops, dstat[i].start_count - dstat[i].end_count);
436 rrdset_done(dm->st_qops);
437 }
438
439 if (dm->do_util == CONFIG_BOOLEAN_YES || dm->do_util == CONFIG_BOOLEAN_AUTO) {
440 if (unlikely(!dm->st_util)) {
441 dm->st_util = rrdset_create_localhost("disk_util",
442 disk,
443 NULL,
444 "utilization",
445 "disk.util",
446 "Disk Utilization Time",
447 "% of time working",
448 "freebsd.plugin",
449 "devstat",
450 NETDATA_CHART_PRIO_DISK_UTIL,
451 update_every,
452 RRDSET_TYPE_AREA
453 );
454
455 dm->rd_util = rrddim_add(dm->st_util, "utilization", NULL, 1, 10,
456 RRD_ALGORITHM_INCREMENTAL);
457 rrdlabels_add(dm->st_util->rrdlabels, "device", disk, RRDLABEL_SRC_AUTO);
458 }
459
460 rrddim_set_by_pointer(dm->st_util, dm->rd_util, cur_dstat.busy_time_ms);
461 rrdset_done(dm->st_util);
462 }
463
464 if (dm->do_iotime == CONFIG_BOOLEAN_YES || dm->do_iotime == CONFIG_BOOLEAN_AUTO) {
465 if (unlikely(!dm->st_iotime)) {
466 dm->st_iotime = rrdset_create_localhost("disk_iotime",
467 disk,
468 NULL,
469 "io",
470 "disk.iotime",
471 "Disk Total I/O Time",
472 "milliseconds/s",
473 "freebsd.plugin",
474 "devstat",
475 NETDATA_CHART_PRIO_DISK_IOTIME,
476 update_every,
477 RRDSET_TYPE_LINE
478 );
479
480 dm->rd_iotime_in = rrddim_add(dm->st_iotime, "reads", NULL, 1, 1,
481 RRD_ALGORITHM_INCREMENTAL);
482 dm->rd_iotime_out = rrddim_add(dm->st_iotime, "writes", NULL, -1, 1,
483 RRD_ALGORITHM_INCREMENTAL);
484 dm->rd_iotime_other = rrddim_add(dm->st_iotime, "other", NULL, 1, 1,
485 RRD_ALGORITHM_INCREMENTAL);
486 dm->rd_iotime_free = rrddim_add(dm->st_iotime, "frees", NULL, -1, 1,
487 RRD_ALGORITHM_INCREMENTAL);
488 rrdlabels_add(dm->st_iotime->rrdlabels, "device", disk, RRDLABEL_SRC_AUTO);
489 }
490
491 rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_in, cur_dstat.duration_read_ms);
492 rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_out, cur_dstat.duration_write_ms);
493 rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_other, cur_dstat.duration_other_ms);
494 rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_free, cur_dstat.duration_free_ms);
495 rrdset_done(dm->st_iotime);
496 }
497
498 // calculate differential charts
499 // only if this is not the first time we run
500
501 if (likely(dt)) {
502 if (dm->do_await == CONFIG_BOOLEAN_YES || dm->do_await == CONFIG_BOOLEAN_AUTO) {
503 if (unlikely(!dm->st_await)) {
504 dm->st_await = rrdset_create_localhost("disk_await",
505 disk,
506 NULL,
507 "io",
508 "disk.await",
509 "Average Completed I/O Operation Time",
510 "milliseconds/operation",
511 "freebsd.plugin",
512 "devstat",
513 NETDATA_CHART_PRIO_DISK_AWAIT,
514 update_every,
515 RRDSET_TYPE_LINE
516 );
517
518 dm->rd_await_in = rrddim_add(dm->st_await, "reads", NULL, 1, 1,
519 RRD_ALGORITHM_ABSOLUTE);
520 dm->rd_await_out = rrddim_add(dm->st_await, "writes", NULL, -1, 1,
521 RRD_ALGORITHM_ABSOLUTE);
522 dm->rd_await_other = rrddim_add(dm->st_await, "other", NULL, 1, 1,
523 RRD_ALGORITHM_ABSOLUTE);
524 dm->rd_await_free = rrddim_add(dm->st_await, "frees", NULL, -1, 1,
525 RRD_ALGORITHM_ABSOLUTE);
526 rrdlabels_add(dm->st_await->rrdlabels, "device", disk, RRDLABEL_SRC_AUTO);
527 }
528
529 rrddim_set_by_pointer(dm->st_await, dm->rd_await_in,
530 (dstat[i].operations[DEVSTAT_READ] -
531 dm->prev_dstat.operations_read) ?
532 (cur_dstat.duration_read_ms - dm->prev_dstat.duration_read_ms) /
533 (dstat[i].operations[DEVSTAT_READ] -
534 dm->prev_dstat.operations_read) :
535 0);
536 rrddim_set_by_pointer(dm->st_await, dm->rd_await_out,
537 (dstat[i].operations[DEVSTAT_WRITE] -
538 dm->prev_dstat.operations_write) ?
539 (cur_dstat.duration_write_ms - dm->prev_dstat.duration_write_ms) /
540 (dstat[i].operations[DEVSTAT_WRITE] -
541 dm->prev_dstat.operations_write) :
542 0);
543 rrddim_set_by_pointer(dm->st_await, dm->rd_await_other,
544 (dstat[i].operations[DEVSTAT_NO_DATA] -
545 dm->prev_dstat.operations_other) ?
546 (cur_dstat.duration_other_ms - dm->prev_dstat.duration_other_ms) /
547 (dstat[i].operations[DEVSTAT_NO_DATA] -
548 dm->prev_dstat.operations_other) :
549 0);
550 rrddim_set_by_pointer(dm->st_await, dm->rd_await_free,
551 (dstat[i].operations[DEVSTAT_FREE] -
552 dm->prev_dstat.operations_free) ?
553 (cur_dstat.duration_free_ms - dm->prev_dstat.duration_free_ms) /
554 (dstat[i].operations[DEVSTAT_FREE] -
555 dm->prev_dstat.operations_free) :
556 0);
557 rrdset_done(dm->st_await);
558 }
559
560 if (dm->do_avagsz == CONFIG_BOOLEAN_YES || dm->do_avagsz == CONFIG_BOOLEAN_AUTO) {
561 if (unlikely(!dm->st_avagsz)) {
562 dm->st_avagsz = rrdset_create_localhost("disk_avgsz",
563 disk,
564 NULL,
565 "io",
566 "disk.avgsz",
567 "Average Completed I/O Operation Bandwidth",
568 "KiB/operation",
569 "freebsd.plugin",
570 "devstat",
571 NETDATA_CHART_PRIO_DISK_AVGSZ,
572 update_every,
573 RRDSET_TYPE_AREA
574 );
575
576 dm->rd_avagsz_in = rrddim_add(dm->st_avagsz, "reads", NULL, 1, KILO_FACTOR,
577 RRD_ALGORITHM_ABSOLUTE);
578 dm->rd_avagsz_out = rrddim_add(dm->st_avagsz, "writes", NULL, -1, KILO_FACTOR,
579 RRD_ALGORITHM_ABSOLUTE);
580 dm->rd_avagsz_free = rrddim_add(dm->st_avagsz, "frees", NULL, -1, KILO_FACTOR,
581 RRD_ALGORITHM_ABSOLUTE);
582 rrdlabels_add(dm->st_avagsz->rrdlabels, "device", disk, RRDLABEL_SRC_AUTO);
583 }
584
585 rrddim_set_by_pointer(dm->st_avagsz, dm->rd_avagsz_in,
586 (dstat[i].operations[DEVSTAT_READ] -
587 dm->prev_dstat.operations_read) ?
588 (dstat[i].bytes[DEVSTAT_READ] - dm->prev_dstat.bytes_read) /
589 (dstat[i].operations[DEVSTAT_READ] -
590 dm->prev_dstat.operations_read) :
591 0);
592 rrddim_set_by_pointer(dm->st_avagsz, dm->rd_avagsz_out,
593 (dstat[i].operations[DEVSTAT_WRITE] -
594 dm->prev_dstat.operations_write) ?
595 (dstat[i].bytes[DEVSTAT_WRITE] - dm->prev_dstat.bytes_write) /
596 (dstat[i].operations[DEVSTAT_WRITE] -
597 dm->prev_dstat.operations_write) :
598 0);
599 rrddim_set_by_pointer(dm->st_avagsz, dm->rd_avagsz_free,
600 (dstat[i].operations[DEVSTAT_FREE] -
601 dm->prev_dstat.operations_free) ?
602 (dstat[i].bytes[DEVSTAT_FREE] - dm->prev_dstat.bytes_free) /
603 (dstat[i].operations[DEVSTAT_FREE] -
604 dm->prev_dstat.operations_free) :
605 0);
606 rrdset_done(dm->st_avagsz);
607 }
608
609 if (dm->do_svctm == CONFIG_BOOLEAN_YES || dm->do_svctm == CONFIG_BOOLEAN_AUTO) {
610 if (unlikely(!dm->st_svctm)) {
611 dm->st_svctm = rrdset_create_localhost("disk_svctm",
612 disk,
613 NULL,
614 "ops",
615 "disk.svctm",
616 "Average Service Time",
617 "milliseconds/operation",
618 "freebsd.plugin",
619 "devstat",
620 NETDATA_CHART_PRIO_DISK_SVCTM,
621 update_every,
622 RRDSET_TYPE_LINE
623 );
624
625 dm->rd_svctm = rrddim_add(dm->st_svctm, "svctm", NULL, 1, 1,
626 RRD_ALGORITHM_ABSOLUTE);
627 rrdlabels_add(dm->st_svctm->rrdlabels, "device", disk, RRDLABEL_SRC_AUTO);
628 }
629
630 rrddim_set_by_pointer(dm->st_svctm, dm->rd_svctm,
631 ((dstat[i].operations[DEVSTAT_READ] - dm->prev_dstat.operations_read) +
632 (dstat[i].operations[DEVSTAT_WRITE] - dm->prev_dstat.operations_write) +
633 (dstat[i].operations[DEVSTAT_NO_DATA] - dm->prev_dstat.operations_other) +
634 (dstat[i].operations[DEVSTAT_FREE] - dm->prev_dstat.operations_free)) ?
635 (cur_dstat.busy_time_ms - dm->prev_dstat.busy_time_ms) /
636 ((dstat[i].operations[DEVSTAT_READ] - dm->prev_dstat.operations_read) +
637 (dstat[i].operations[DEVSTAT_WRITE] - dm->prev_dstat.operations_write) +
638 (dstat[i].operations[DEVSTAT_NO_DATA] - dm->prev_dstat.operations_other) +
639 (dstat[i].operations[DEVSTAT_FREE] - dm->prev_dstat.operations_free)) :
640 0);
641 rrdset_done(dm->st_svctm);
642 }
643
644 dm->prev_dstat.bytes_read = dstat[i].bytes[DEVSTAT_READ];
645 dm->prev_dstat.bytes_write = dstat[i].bytes[DEVSTAT_WRITE];
646 dm->prev_dstat.bytes_free = dstat[i].bytes[DEVSTAT_FREE];
647 dm->prev_dstat.operations_read = dstat[i].operations[DEVSTAT_READ];
648 dm->prev_dstat.operations_write = dstat[i].operations[DEVSTAT_WRITE];
649 dm->prev_dstat.operations_other = dstat[i].operations[DEVSTAT_NO_DATA];
650 dm->prev_dstat.operations_free = dstat[i].operations[DEVSTAT_FREE];
651 dm->prev_dstat.duration_read_ms = cur_dstat.duration_read_ms;
652 dm->prev_dstat.duration_write_ms = cur_dstat.duration_write_ms;
653 dm->prev_dstat.duration_other_ms = cur_dstat.duration_other_ms;
654 dm->prev_dstat.duration_free_ms = cur_dstat.duration_free_ms;
655 dm->prev_dstat.busy_time_ms = cur_dstat.busy_time_ms;
656 }
657 }
658 }
659
660 if (likely(do_system_io)) {
661 static RRDSET *st = NULL;
662 static RRDDIM *rd_in = NULL, *rd_out = NULL;
663
664 if (unlikely(!st)) {
665 st = rrdset_create_localhost("system",
666 "io",
667 NULL,
668 "disk",
669 NULL,
670 "Disk I/O",
671 "KiB/s",
672 "freebsd.plugin",
673 "devstat",
674 NETDATA_CHART_PRIO_SYSTEM_IO,
675 update_every,
676 RRDSET_TYPE_AREA
677 );
678
679 rd_in = rrddim_add(st, "in", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
680 rd_out = rrddim_add(st, "out", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
681 }
682
683 rrddim_set_by_pointer(st, rd_in, total_disk_kbytes_read);
684 rrddim_set_by_pointer(st, rd_out, total_disk_kbytes_write);
685 rrdset_done(st);
686 }
687 }
688 }
689
690 if (unlikely(common_error)) {
691 do_system_io = 0;
692 collector_error("DISABLED: system.io chart");
693 do_io = 0;
694 collector_error("DISABLED: disk.* charts");
695 do_ops = 0;
696 collector_error("DISABLED: disk_ops.* charts");
697 do_qops = 0;
698 collector_error("DISABLED: disk_qops.* charts");
699 do_util = 0;
700 collector_error("DISABLED: disk_util.* charts");
701 do_iotime = 0;
702 collector_error("DISABLED: disk_iotime.* charts");
703 do_await = 0;
704 collector_error("DISABLED: disk_await.* charts");
705 do_avagsz = 0;
706 collector_error("DISABLED: disk_avgsz.* charts");
707 do_svctm = 0;
708 collector_error("DISABLED: disk_svctm.* charts");
709 collector_error("DISABLED: kern.devstat module");
710 return 1;
711 }
712 } else {
713 collector_error("DISABLED: kern.devstat module");
714 return 1;
715 }
716
717 disks_cleanup();
718
719 return 0;
720 }