freebsd_devstat.c 44 KB

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