freebsd_devstat.c 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  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. // 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. );
  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. // --------------------------------------------------------------------
  284. if(dm->do_io == CONFIG_BOOLEAN_YES || (dm->do_io == CONFIG_BOOLEAN_AUTO &&
  285. (dstat[i].bytes[DEVSTAT_READ] ||
  286. dstat[i].bytes[DEVSTAT_WRITE] ||
  287. dstat[i].bytes[DEVSTAT_FREE] ||
  288. netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
  289. if (unlikely(!dm->st_io)) {
  290. dm->st_io = rrdset_create_localhost("disk",
  291. disk,
  292. NULL,
  293. disk,
  294. "disk.io",
  295. "Disk I/O Bandwidth",
  296. "KiB/s",
  297. "freebsd.plugin",
  298. "devstat",
  299. NETDATA_CHART_PRIO_DISK_IO,
  300. update_every,
  301. RRDSET_TYPE_AREA
  302. );
  303. dm->rd_io_in = rrddim_add(dm->st_io, "reads", NULL, 1, KILO_FACTOR,
  304. RRD_ALGORITHM_INCREMENTAL);
  305. dm->rd_io_out = rrddim_add(dm->st_io, "writes", NULL, -1, KILO_FACTOR,
  306. RRD_ALGORITHM_INCREMENTAL);
  307. dm->rd_io_free = rrddim_add(dm->st_io, "frees", NULL, -1, KILO_FACTOR,
  308. RRD_ALGORITHM_INCREMENTAL);
  309. } else
  310. rrdset_next(dm->st_io);
  311. rrddim_set_by_pointer(dm->st_io, dm->rd_io_in, dstat[i].bytes[DEVSTAT_READ]);
  312. rrddim_set_by_pointer(dm->st_io, dm->rd_io_out, dstat[i].bytes[DEVSTAT_WRITE]);
  313. rrddim_set_by_pointer(dm->st_io, dm->rd_io_free, dstat[i].bytes[DEVSTAT_FREE]);
  314. rrdset_done(dm->st_io);
  315. }
  316. // --------------------------------------------------------------------
  317. if(dm->do_ops == CONFIG_BOOLEAN_YES || (dm->do_ops == CONFIG_BOOLEAN_AUTO &&
  318. (dstat[i].operations[DEVSTAT_READ] ||
  319. dstat[i].operations[DEVSTAT_WRITE] ||
  320. dstat[i].operations[DEVSTAT_NO_DATA] ||
  321. dstat[i].operations[DEVSTAT_FREE] ||
  322. netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
  323. if (unlikely(!dm->st_ops)) {
  324. dm->st_ops = rrdset_create_localhost("disk_ops",
  325. disk,
  326. NULL,
  327. disk,
  328. "disk.ops",
  329. "Disk Completed I/O Operations",
  330. "operations/s",
  331. "freebsd.plugin",
  332. "devstat",
  333. NETDATA_CHART_PRIO_DISK_OPS,
  334. update_every,
  335. RRDSET_TYPE_LINE
  336. );
  337. rrdset_flag_set(dm->st_ops, RRDSET_FLAG_DETAIL);
  338. dm->rd_ops_in = rrddim_add(dm->st_ops, "reads", NULL, 1, 1,
  339. RRD_ALGORITHM_INCREMENTAL);
  340. dm->rd_ops_out = rrddim_add(dm->st_ops, "writes", NULL, -1, 1,
  341. RRD_ALGORITHM_INCREMENTAL);
  342. dm->rd_ops_other = rrddim_add(dm->st_ops, "other", NULL, 1, 1,
  343. RRD_ALGORITHM_INCREMENTAL);
  344. dm->rd_ops_free = rrddim_add(dm->st_ops, "frees", NULL, -1, 1,
  345. RRD_ALGORITHM_INCREMENTAL);
  346. } else
  347. rrdset_next(dm->st_ops);
  348. rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_in, dstat[i].operations[DEVSTAT_READ]);
  349. rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_out, dstat[i].operations[DEVSTAT_WRITE]);
  350. rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_other, dstat[i].operations[DEVSTAT_NO_DATA]);
  351. rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_free, dstat[i].operations[DEVSTAT_FREE]);
  352. rrdset_done(dm->st_ops);
  353. }
  354. // --------------------------------------------------------------------
  355. if(dm->do_qops == CONFIG_BOOLEAN_YES || (dm->do_qops == CONFIG_BOOLEAN_AUTO &&
  356. (dstat[i].start_count ||
  357. dstat[i].end_count ||
  358. netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
  359. if (unlikely(!dm->st_qops)) {
  360. dm->st_qops = rrdset_create_localhost("disk_qops",
  361. disk,
  362. NULL,
  363. disk,
  364. "disk.qops",
  365. "Disk Current I/O Operations",
  366. "operations",
  367. "freebsd.plugin",
  368. "devstat",
  369. NETDATA_CHART_PRIO_DISK_QOPS,
  370. update_every,
  371. RRDSET_TYPE_LINE
  372. );
  373. rrdset_flag_set(dm->st_qops, RRDSET_FLAG_DETAIL);
  374. dm->rd_qops = rrddim_add(dm->st_qops, "operations", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
  375. } else
  376. rrdset_next(dm->st_qops);
  377. rrddim_set_by_pointer(dm->st_qops, dm->rd_qops, dstat[i].start_count - dstat[i].end_count);
  378. rrdset_done(dm->st_qops);
  379. }
  380. // --------------------------------------------------------------------
  381. if(dm->do_util == CONFIG_BOOLEAN_YES || (dm->do_util == CONFIG_BOOLEAN_AUTO &&
  382. (cur_dstat.busy_time_ms ||
  383. netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
  384. if (unlikely(!dm->st_util)) {
  385. dm->st_util = rrdset_create_localhost("disk_util",
  386. disk,
  387. NULL,
  388. disk,
  389. "disk.util",
  390. "Disk Utilization Time",
  391. "% of time working",
  392. "freebsd.plugin",
  393. "devstat",
  394. NETDATA_CHART_PRIO_DISK_UTIL,
  395. update_every,
  396. RRDSET_TYPE_AREA
  397. );
  398. rrdset_flag_set(dm->st_util, RRDSET_FLAG_DETAIL);
  399. dm->rd_util = rrddim_add(dm->st_util, "utilization", NULL, 1, 10,
  400. RRD_ALGORITHM_INCREMENTAL);
  401. } else
  402. rrdset_next(dm->st_util);
  403. rrddim_set_by_pointer(dm->st_util, dm->rd_util, cur_dstat.busy_time_ms);
  404. rrdset_done(dm->st_util);
  405. }
  406. // --------------------------------------------------------------------
  407. if(dm->do_iotime == CONFIG_BOOLEAN_YES || (dm->do_iotime == CONFIG_BOOLEAN_AUTO &&
  408. (cur_dstat.duration_read_ms ||
  409. cur_dstat.duration_write_ms ||
  410. cur_dstat.duration_other_ms ||
  411. cur_dstat.duration_free_ms ||
  412. netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
  413. if (unlikely(!dm->st_iotime)) {
  414. dm->st_iotime = rrdset_create_localhost("disk_iotime",
  415. disk,
  416. NULL,
  417. disk,
  418. "disk.iotime",
  419. "Disk Total I/O Time",
  420. "milliseconds/s",
  421. "freebsd.plugin",
  422. "devstat",
  423. NETDATA_CHART_PRIO_DISK_IOTIME,
  424. update_every,
  425. RRDSET_TYPE_LINE
  426. );
  427. rrdset_flag_set(dm->st_iotime, RRDSET_FLAG_DETAIL);
  428. dm->rd_iotime_in = rrddim_add(dm->st_iotime, "reads", NULL, 1, 1,
  429. RRD_ALGORITHM_INCREMENTAL);
  430. dm->rd_iotime_out = rrddim_add(dm->st_iotime, "writes", NULL, -1, 1,
  431. RRD_ALGORITHM_INCREMENTAL);
  432. dm->rd_iotime_other = rrddim_add(dm->st_iotime, "other", NULL, 1, 1,
  433. RRD_ALGORITHM_INCREMENTAL);
  434. dm->rd_iotime_free = rrddim_add(dm->st_iotime, "frees", NULL, -1, 1,
  435. RRD_ALGORITHM_INCREMENTAL);
  436. } else
  437. rrdset_next(dm->st_iotime);
  438. rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_in, cur_dstat.duration_read_ms);
  439. rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_out, cur_dstat.duration_write_ms);
  440. rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_other, cur_dstat.duration_other_ms);
  441. rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_free, cur_dstat.duration_free_ms);
  442. rrdset_done(dm->st_iotime);
  443. }
  444. // --------------------------------------------------------------------
  445. // calculate differential charts
  446. // only if this is not the first time we run
  447. if (likely(dt)) {
  448. // --------------------------------------------------------------------
  449. if(dm->do_await == CONFIG_BOOLEAN_YES || (dm->do_await == CONFIG_BOOLEAN_AUTO &&
  450. (dstat[i].operations[DEVSTAT_READ] ||
  451. dstat[i].operations[DEVSTAT_WRITE] ||
  452. dstat[i].operations[DEVSTAT_NO_DATA] ||
  453. dstat[i].operations[DEVSTAT_FREE] ||
  454. netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
  455. if (unlikely(!dm->st_await)) {
  456. dm->st_await = rrdset_create_localhost("disk_await",
  457. disk,
  458. NULL,
  459. disk,
  460. "disk.await",
  461. "Average Completed I/O Operation Time",
  462. "milliseconds/operation",
  463. "freebsd.plugin",
  464. "devstat",
  465. NETDATA_CHART_PRIO_DISK_AWAIT,
  466. update_every,
  467. RRDSET_TYPE_LINE
  468. );
  469. rrdset_flag_set(dm->st_await, RRDSET_FLAG_DETAIL);
  470. dm->rd_await_in = rrddim_add(dm->st_await, "reads", NULL, 1, 1,
  471. RRD_ALGORITHM_ABSOLUTE);
  472. dm->rd_await_out = rrddim_add(dm->st_await, "writes", NULL, -1, 1,
  473. RRD_ALGORITHM_ABSOLUTE);
  474. dm->rd_await_other = rrddim_add(dm->st_await, "other", NULL, 1, 1,
  475. RRD_ALGORITHM_ABSOLUTE);
  476. dm->rd_await_free = rrddim_add(dm->st_await, "frees", NULL, -1, 1,
  477. RRD_ALGORITHM_ABSOLUTE);
  478. } else
  479. rrdset_next(dm->st_await);
  480. rrddim_set_by_pointer(dm->st_await, dm->rd_await_in,
  481. (dstat[i].operations[DEVSTAT_READ] -
  482. dm->prev_dstat.operations_read) ?
  483. (cur_dstat.duration_read_ms - dm->prev_dstat.duration_read_ms) /
  484. (dstat[i].operations[DEVSTAT_READ] -
  485. dm->prev_dstat.operations_read) :
  486. 0);
  487. rrddim_set_by_pointer(dm->st_await, dm->rd_await_out,
  488. (dstat[i].operations[DEVSTAT_WRITE] -
  489. dm->prev_dstat.operations_write) ?
  490. (cur_dstat.duration_write_ms - dm->prev_dstat.duration_write_ms) /
  491. (dstat[i].operations[DEVSTAT_WRITE] -
  492. dm->prev_dstat.operations_write) :
  493. 0);
  494. rrddim_set_by_pointer(dm->st_await, dm->rd_await_other,
  495. (dstat[i].operations[DEVSTAT_NO_DATA] -
  496. dm->prev_dstat.operations_other) ?
  497. (cur_dstat.duration_other_ms - dm->prev_dstat.duration_other_ms) /
  498. (dstat[i].operations[DEVSTAT_NO_DATA] -
  499. dm->prev_dstat.operations_other) :
  500. 0);
  501. rrddim_set_by_pointer(dm->st_await, dm->rd_await_free,
  502. (dstat[i].operations[DEVSTAT_FREE] -
  503. dm->prev_dstat.operations_free) ?
  504. (cur_dstat.duration_free_ms - dm->prev_dstat.duration_free_ms) /
  505. (dstat[i].operations[DEVSTAT_FREE] -
  506. dm->prev_dstat.operations_free) :
  507. 0);
  508. rrdset_done(dm->st_await);
  509. }
  510. // --------------------------------------------------------------------
  511. if(dm->do_avagsz == CONFIG_BOOLEAN_YES || (dm->do_avagsz == CONFIG_BOOLEAN_AUTO &&
  512. (dstat[i].operations[DEVSTAT_READ] ||
  513. dstat[i].operations[DEVSTAT_WRITE] ||
  514. dstat[i].operations[DEVSTAT_FREE] ||
  515. netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
  516. if (unlikely(!dm->st_avagsz)) {
  517. dm->st_avagsz = rrdset_create_localhost("disk_avgsz",
  518. disk,
  519. NULL,
  520. disk,
  521. "disk.avgsz",
  522. "Average Completed I/O Operation Bandwidth",
  523. "KiB/operation",
  524. "freebsd.plugin",
  525. "devstat",
  526. NETDATA_CHART_PRIO_DISK_AVGSZ,
  527. update_every,
  528. RRDSET_TYPE_AREA
  529. );
  530. rrdset_flag_set(dm->st_avagsz, RRDSET_FLAG_DETAIL);
  531. dm->rd_avagsz_in = rrddim_add(dm->st_avagsz, "reads", NULL, 1, KILO_FACTOR,
  532. RRD_ALGORITHM_ABSOLUTE);
  533. dm->rd_avagsz_out = rrddim_add(dm->st_avagsz, "writes", NULL, -1, KILO_FACTOR,
  534. RRD_ALGORITHM_ABSOLUTE);
  535. dm->rd_avagsz_free = rrddim_add(dm->st_avagsz, "frees", NULL, -1, KILO_FACTOR,
  536. RRD_ALGORITHM_ABSOLUTE);
  537. } else
  538. rrdset_next(dm->st_avagsz);
  539. rrddim_set_by_pointer(dm->st_avagsz, dm->rd_avagsz_in,
  540. (dstat[i].operations[DEVSTAT_READ] -
  541. dm->prev_dstat.operations_read) ?
  542. (dstat[i].bytes[DEVSTAT_READ] - dm->prev_dstat.bytes_read) /
  543. (dstat[i].operations[DEVSTAT_READ] -
  544. dm->prev_dstat.operations_read) :
  545. 0);
  546. rrddim_set_by_pointer(dm->st_avagsz, dm->rd_avagsz_out,
  547. (dstat[i].operations[DEVSTAT_WRITE] -
  548. dm->prev_dstat.operations_write) ?
  549. (dstat[i].bytes[DEVSTAT_WRITE] - dm->prev_dstat.bytes_write) /
  550. (dstat[i].operations[DEVSTAT_WRITE] -
  551. dm->prev_dstat.operations_write) :
  552. 0);
  553. rrddim_set_by_pointer(dm->st_avagsz, dm->rd_avagsz_free,
  554. (dstat[i].operations[DEVSTAT_FREE] -
  555. dm->prev_dstat.operations_free) ?
  556. (dstat[i].bytes[DEVSTAT_FREE] - dm->prev_dstat.bytes_free) /
  557. (dstat[i].operations[DEVSTAT_FREE] -
  558. dm->prev_dstat.operations_free) :
  559. 0);
  560. rrdset_done(dm->st_avagsz);
  561. }
  562. // --------------------------------------------------------------------
  563. if(dm->do_svctm == CONFIG_BOOLEAN_YES || (dm->do_svctm == CONFIG_BOOLEAN_AUTO &&
  564. (dstat[i].operations[DEVSTAT_READ] ||
  565. dstat[i].operations[DEVSTAT_WRITE] ||
  566. dstat[i].operations[DEVSTAT_NO_DATA] ||
  567. dstat[i].operations[DEVSTAT_FREE] ||
  568. netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
  569. if (unlikely(!dm->st_svctm)) {
  570. dm->st_svctm = rrdset_create_localhost("disk_svctm",
  571. disk,
  572. NULL,
  573. disk,
  574. "disk.svctm",
  575. "Average Service Time",
  576. "milliseconds/operation",
  577. "freebsd.plugin",
  578. "devstat",
  579. NETDATA_CHART_PRIO_DISK_SVCTM,
  580. update_every,
  581. RRDSET_TYPE_LINE
  582. );
  583. rrdset_flag_set(dm->st_svctm, RRDSET_FLAG_DETAIL);
  584. dm->rd_svctm = rrddim_add(dm->st_svctm, "svctm", NULL, 1, 1,
  585. RRD_ALGORITHM_ABSOLUTE);
  586. } else
  587. rrdset_next(dm->st_svctm);
  588. rrddim_set_by_pointer(dm->st_svctm, dm->rd_svctm,
  589. ((dstat[i].operations[DEVSTAT_READ] - dm->prev_dstat.operations_read) +
  590. (dstat[i].operations[DEVSTAT_WRITE] - dm->prev_dstat.operations_write) +
  591. (dstat[i].operations[DEVSTAT_NO_DATA] - dm->prev_dstat.operations_other) +
  592. (dstat[i].operations[DEVSTAT_FREE] - dm->prev_dstat.operations_free)) ?
  593. (cur_dstat.busy_time_ms - dm->prev_dstat.busy_time_ms) /
  594. ((dstat[i].operations[DEVSTAT_READ] - dm->prev_dstat.operations_read) +
  595. (dstat[i].operations[DEVSTAT_WRITE] - dm->prev_dstat.operations_write) +
  596. (dstat[i].operations[DEVSTAT_NO_DATA] - dm->prev_dstat.operations_other) +
  597. (dstat[i].operations[DEVSTAT_FREE] - dm->prev_dstat.operations_free)) :
  598. 0);
  599. rrdset_done(dm->st_svctm);
  600. }
  601. // --------------------------------------------------------------------
  602. dm->prev_dstat.bytes_read = dstat[i].bytes[DEVSTAT_READ];
  603. dm->prev_dstat.bytes_write = dstat[i].bytes[DEVSTAT_WRITE];
  604. dm->prev_dstat.bytes_free = dstat[i].bytes[DEVSTAT_FREE];
  605. dm->prev_dstat.operations_read = dstat[i].operations[DEVSTAT_READ];
  606. dm->prev_dstat.operations_write = dstat[i].operations[DEVSTAT_WRITE];
  607. dm->prev_dstat.operations_other = dstat[i].operations[DEVSTAT_NO_DATA];
  608. dm->prev_dstat.operations_free = dstat[i].operations[DEVSTAT_FREE];
  609. dm->prev_dstat.duration_read_ms = cur_dstat.duration_read_ms;
  610. dm->prev_dstat.duration_write_ms = cur_dstat.duration_write_ms;
  611. dm->prev_dstat.duration_other_ms = cur_dstat.duration_other_ms;
  612. dm->prev_dstat.duration_free_ms = cur_dstat.duration_free_ms;
  613. dm->prev_dstat.busy_time_ms = cur_dstat.busy_time_ms;
  614. }
  615. }
  616. }
  617. // --------------------------------------------------------------------
  618. if (likely(do_system_io)) {
  619. static RRDSET *st = NULL;
  620. static RRDDIM *rd_in = NULL, *rd_out = NULL;
  621. if (unlikely(!st)) {
  622. st = rrdset_create_localhost("system",
  623. "io",
  624. NULL,
  625. "disk",
  626. NULL,
  627. "Disk I/O",
  628. "KiB/s",
  629. "freebsd.plugin",
  630. "devstat",
  631. NETDATA_CHART_PRIO_SYSTEM_IO,
  632. update_every,
  633. RRDSET_TYPE_AREA
  634. );
  635. rd_in = rrddim_add(st, "in", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
  636. rd_out = rrddim_add(st, "out", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
  637. } else
  638. rrdset_next(st);
  639. rrddim_set_by_pointer(st, rd_in, total_disk_kbytes_read);
  640. rrddim_set_by_pointer(st, rd_out, total_disk_kbytes_write);
  641. rrdset_done(st);
  642. }
  643. }
  644. }
  645. if (unlikely(common_error)) {
  646. do_system_io = 0;
  647. error("DISABLED: system.io chart");
  648. do_io = 0;
  649. error("DISABLED: disk.* charts");
  650. do_ops = 0;
  651. error("DISABLED: disk_ops.* charts");
  652. do_qops = 0;
  653. error("DISABLED: disk_qops.* charts");
  654. do_util = 0;
  655. error("DISABLED: disk_util.* charts");
  656. do_iotime = 0;
  657. error("DISABLED: disk_iotime.* charts");
  658. do_await = 0;
  659. error("DISABLED: disk_await.* charts");
  660. do_avagsz = 0;
  661. error("DISABLED: disk_avgsz.* charts");
  662. do_svctm = 0;
  663. error("DISABLED: disk_svctm.* charts");
  664. error("DISABLED: kern.devstat module");
  665. return 1;
  666. }
  667. } else {
  668. error("DISABLED: kern.devstat module");
  669. return 1;
  670. }
  671. disks_cleanup();
  672. return 0;
  673. }