@cryptotaxi247 / netdata-1 / commits / 7d8da98bc

Windows storage metrics (#18810)

* added disk.ops * claiming should wait for node id and status ONLINE only * fix compilation on linux * fix ops on windows * added disk.util * disk.busy * disk.iotime * disk.qops * added cleanup to windows disk metrics * updated cmake * remove duplicate cleanup * undo identation * do not repeateadly try to find non-existing metrics * log once the metrics perflib gives up

Costa Tsaousis committed Oct 19, 2024 at 15:20 UTC 7d8da98bc7481d56a3ad5b5203ad9ea1ee0313ab
12 files changed +530 -225
CMakeLists.txt
+5
@@ -1170,7 +1170,12 @@ endif()
1170
1171 set(INTERNAL_COLLECTORS_FILES
1172 src/collectors/common-contexts/common-contexts.h
1173 + src/collectors/common-contexts/disk-busy.h
1174 src/collectors/common-contexts/disk-io.h
1175 + src/collectors/common-contexts/disk-iotime.h
1176 + src/collectors/common-contexts/disk-ops.h
1177 + src/collectors/common-contexts/disk-qops.h
1178 + src/collectors/common-contexts/disk-util.h
1179 src/collectors/common-contexts/system-io.h
1180 src/collectors/common-contexts/system-interrupts.h
1181 src/collectors/common-contexts/system-processes.h
src/collectors/common-contexts/common-contexts.h
+5
@@ -27,5 +27,10 @@ typedef void (*instance_labels_cb_t)(RRDSET *st, void *data);
27 #include "mem-pgfaults.h"
28 #include "mem-available.h"
29 #include "disk-io.h"
30 +#include "disk-ops.h"
31 +#include "disk-qops.h"
32 +#include "disk-util.h"
33 +#include "disk-busy.h"
34 +#include "disk-iotime.h"
35
36 #endif //NETDATA_COMMON_CONTEXTS_H
src/collectors/common-contexts/disk-busy.h new
+43
@@ -0,0 +1,43 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_DISK_BUSY_H
4 +#define NETDATA_DISK_BUSY_H
5 +
6 +#include "common-contexts.h"
7 +
8 +typedef struct {
9 + RRDSET *st_busy;
10 + RRDDIM *rd_busy;
11 +} ND_DISK_BUSY;
12 +
13 +static inline void common_disk_busy(ND_DISK_BUSY *d, const char *id, const char *name, uint64_t busy_ms, int update_every, instance_labels_cb_t cb, void *data) {
14 + if(unlikely(!d->st_busy)) {
15 + d->st_busy = rrdset_create_localhost(
16 + "disk_busy"
17 + , id
18 + , name
19 + , "utilization"
20 + , "disk.busy"
21 + , "Disk Busy Time"
22 + , "milliseconds"
23 + , _COMMON_PLUGIN_NAME
24 + , _COMMON_PLUGIN_MODULE_NAME
25 + , NETDATA_CHART_PRIO_DISK_BUSY
26 + , update_every
27 + , RRDSET_TYPE_AREA
28 + );
29 +
30 + rrdset_flag_set(d->st_busy, RRDSET_FLAG_DETAIL);
31 +
32 + d->rd_busy = rrddim_add(d->st_busy, "busy", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
33 +
34 + if(cb)
35 + cb(d->st_busy, data);
36 + }
37 +
38 + // this always have to be in base units, so that exporting sends base units to other time-series db
39 + rrddim_set_by_pointer(d->st_busy, d->rd_busy, (collected_number)busy_ms);
40 + rrdset_done(d->st_busy);
41 +}
42 +
43 +#endif //NETDATA_DISK_BUSY_H
src/collectors/common-contexts/disk-iotime.h new
+46
@@ -0,0 +1,46 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_DISK_IOTIME_H
4 +#define NETDATA_DISK_IOTIME_H
5 +
6 +#include "common-contexts.h"
7 +
8 +typedef struct {
9 + RRDSET *st_iotime;
10 + RRDDIM *rd_reads_ms;
11 + RRDDIM *rd_writes_ms;
12 +} ND_DISK_IOTIME;
13 +
14 +static inline void common_disk_iotime(ND_DISK_IOTIME *d, const char *id, const char *name, uint64_t reads_ms, uint64_t writes_ms, int update_every, instance_labels_cb_t cb, void *data) {
15 + if(unlikely(!d->st_iotime)) {
16 + d->st_iotime = rrdset_create_localhost(
17 + "disk_iotime"
18 + , id
19 + , name
20 + , "utilization"
21 + , "disk.iotime"
22 + , "Disk Total I/O Time"
23 + , "milliseconds/s"
24 + , _COMMON_PLUGIN_NAME
25 + , _COMMON_PLUGIN_MODULE_NAME
26 + , NETDATA_CHART_PRIO_DISK_IOTIME
27 + , update_every
28 + , RRDSET_TYPE_AREA
29 + );
30 +
31 + rrdset_flag_set(d->st_iotime, RRDSET_FLAG_DETAIL);
32 +
33 + d->rd_reads_ms = rrddim_add(d->st_iotime, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
34 + d->rd_writes_ms = rrddim_add(d->st_iotime, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
35 +
36 + if(cb)
37 + cb(d->st_iotime, data);
38 + }
39 +
40 + // this always have to be in base units, so that exporting sends base units to other time-series db
41 + rrddim_set_by_pointer(d->st_iotime, d->rd_reads_ms, (collected_number)reads_ms);
42 + rrddim_set_by_pointer(d->st_iotime, d->rd_writes_ms, (collected_number)writes_ms);
43 + rrdset_done(d->st_iotime);
44 +}
45 +
46 +#endif //NETDATA_DISK_IOTIME_H
src/collectors/common-contexts/disk-ops.h new
+44
@@ -0,0 +1,44 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_DISK_OPS_H
4 +#define NETDATA_DISK_OPS_H
5 +
6 +#include "common-contexts.h"
7 +
8 +typedef struct {
9 + RRDSET *st_ops;
10 + RRDDIM *rd_ops_reads;
11 + RRDDIM *rd_ops_writes;
12 +} ND_DISK_OPS;
13 +
14 +static inline void common_disk_ops(ND_DISK_OPS *d, const char *id, const char *name, uint64_t ops_read, uint64_t ops_write, int update_every, instance_labels_cb_t cb, void *data) {
15 + if(unlikely(!d->st_ops)) {
16 + d->st_ops = rrdset_create_localhost(
17 + "disk_ops"
18 + , id
19 + , name
20 + , "ops"
21 + , "disk.ops"
22 + , "Disk Completed I/O Operations"
23 + , "operations/s"
24 + , _COMMON_PLUGIN_NAME
25 + , _COMMON_PLUGIN_MODULE_NAME
26 + , NETDATA_CHART_PRIO_DISK_OPS
27 + , update_every
28 + , RRDSET_TYPE_LINE
29 + );
30 +
31 + d->rd_ops_reads = rrddim_add(d->st_ops, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
32 + d->rd_ops_writes = rrddim_add(d->st_ops, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
33 +
34 + if(cb)
35 + cb(d->st_ops, data);
36 + }
37 +
38 + // this always have to be in base units, so that exporting sends base units to other time-series db
39 + rrddim_set_by_pointer(d->st_ops, d->rd_ops_reads, (collected_number)ops_read);
40 + rrddim_set_by_pointer(d->st_ops, d->rd_ops_writes, (collected_number)ops_write);
41 + rrdset_done(d->st_ops);
42 +}
43 +
44 +#endif //NETDATA_DISK_OPS_H
src/collectors/common-contexts/disk-qops.h new
+41
@@ -0,0 +1,41 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_DISK_QOPS_H
4 +#define NETDATA_DISK_QOPS_H
5 +
6 +#include "common-contexts.h"
7 +
8 +typedef struct {
9 + RRDSET *st_qops;
10 + RRDDIM *rd_qops;
11 +} ND_DISK_QOPS;
12 +
13 +static inline void common_disk_qops(ND_DISK_QOPS *d, const char *id, const char *name, uint64_t queued_ops, int update_every, instance_labels_cb_t cb, void *data) {
14 + if(unlikely(!d->st_qops)) {
15 + d->st_qops = rrdset_create_localhost(
16 + "disk_qops"
17 + , id
18 + , name
19 + , "ops"
20 + , "disk.qops"
21 + , "Disk Current I/O Operations"
22 + , "operations"
23 + , _COMMON_PLUGIN_NAME
24 + , _COMMON_PLUGIN_MODULE_NAME
25 + , NETDATA_CHART_PRIO_DISK_QOPS
26 + , update_every
27 + , RRDSET_TYPE_LINE
28 + );
29 +
30 + d->rd_qops = rrddim_add(d->st_qops, "operations", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
31 +
32 + if(cb)
33 + cb(d->st_qops, data);
34 + }
35 +
36 + // this always have to be in base units, so that exporting sends base units to other time-series db
37 + rrddim_set_by_pointer(d->st_qops, d->rd_qops, (collected_number)queued_ops);
38 + rrdset_done(d->st_qops);
39 +}
40 +
41 +#endif //NETDATA_DISK_QOPS_H
src/collectors/common-contexts/disk-util.h new
+43
@@ -0,0 +1,43 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#ifndef NETDATA_DISK_UTIL_H
4 +#define NETDATA_DISK_UTIL_H
5 +
6 +#include "common-contexts.h"
7 +
8 +typedef struct {
9 + RRDSET *st_util;
10 + RRDDIM *rd_util;
11 +} ND_DISK_UTIL;
12 +
13 +static inline void common_disk_util(ND_DISK_UTIL *d, const char *id, const char *name, uint64_t percent, int update_every, instance_labels_cb_t cb, void *data) {
14 + if(unlikely(!d->st_util)) {
15 + d->st_util = rrdset_create_localhost(
16 + "disk_util"
17 + , id
18 + , name
19 + , "utilization"
20 + , "disk.util"
21 + , "Disk Utilization Time"
22 + , "% of time working"
23 + , _COMMON_PLUGIN_NAME
24 + , _COMMON_PLUGIN_MODULE_NAME
25 + , NETDATA_CHART_PRIO_DISK_UTIL
26 + , update_every
27 + , RRDSET_TYPE_AREA
28 + );
29 +
30 + rrdset_flag_set(d->st_util, RRDSET_FLAG_DETAIL);
31 +
32 + d->rd_util = rrddim_add(d->st_util, "utilization", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
33 +
34 + if(cb)
35 + cb(d->st_util, data);
36 + }
37 +
38 + // this always have to be in base units, so that exporting sends base units to other time-series db
39 + rrddim_set_by_pointer(d->st_util, d->rd_util, (collected_number)percent);
40 + rrdset_done(d->st_util);
41 +}
42 +
43 +#endif //NETDATA_DISK_UTIL_H
src/collectors/proc.plugin/proc_diskstats.c
+76 -170
@@ -81,30 +81,22 @@ static struct disk {
81 usec_t bcache_priority_stats_elapsed_usec;
82
83 ND_DISK_IO disk_io;
84 + ND_DISK_OPS disk_ops;
85 + ND_DISK_QOPS disk_qops;
86 + ND_DISK_UTIL disk_util;
87 + ND_DISK_BUSY disk_busy;
88 + ND_DISK_IOTIME disk_iotime;
89
90 RRDSET *st_ext_io;
91 RRDDIM *rd_io_discards;
92
88 - RRDSET *st_ops;
89 - RRDDIM *rd_ops_reads;
90 - RRDDIM *rd_ops_writes;
91 -
93 RRDSET *st_ext_ops;
94 RRDDIM *rd_ops_discards;
95 RRDDIM *rd_ops_flushes;
96
96 - RRDSET *st_qops;
97 - RRDDIM *rd_qops_operations;
98 -
97 RRDSET *st_backlog;
98 RRDDIM *rd_backlog_backlog;
99
102 - RRDSET *st_busy;
103 - RRDDIM *rd_busy_busy;
104 -
105 - RRDSET *st_util;
106 - RRDDIM *rd_util_utilization;
107 -
100 RRDSET *st_mops;
101 RRDDIM *rd_mops_reads;
102 RRDDIM *rd_mops_writes;
@@ -112,10 +104,6 @@ static struct disk {
104 RRDSET *st_ext_mops;
105 RRDDIM *rd_mops_discards;
106
115 - RRDSET *st_iotime;
116 - RRDDIM *rd_iotime_reads;
117 - RRDDIM *rd_iotime_writes;
118 -
107 RRDSET *st_ext_iotime;
108 RRDDIM *rd_iotime_discards;
109 RRDDIM *rd_iotime_flushes;
@@ -1049,15 +1037,15 @@ static int diskstats_function_block_devices(BUFFER *wb, const char *function __m
1037 max_io = MAX(max_io, io_total);
1038 }
1039 // Backlog and Busy Time
1052 - double busy_perc = rrddim_get_last_stored_value(d->rd_util_utilization, &max_busy_perc, 1);
1053 - double busy_time = rrddim_get_last_stored_value(d->rd_busy_busy, &max_busy_time, 1);
1040 + double busy_perc = rrddim_get_last_stored_value(d->disk_util.rd_util, &max_busy_perc, 1);
1041 + double busy_time = rrddim_get_last_stored_value(d->disk_busy.rd_busy, &max_busy_time, 1);
1042 double backlog_time = rrddim_get_last_stored_value(d->rd_backlog_backlog, &max_backlog_time, 1);
1043 // IOPS
1056 - double iops_reads = rrddim_get_last_stored_value(d->rd_ops_reads, &max_iops_reads, 1);
1057 - double iops_writes = rrddim_get_last_stored_value(d->rd_ops_writes, &max_iops_writes, 1);
1044 + double iops_reads = rrddim_get_last_stored_value(d->disk_ops.rd_ops_reads, &max_iops_reads, 1);
1045 + double iops_writes = rrddim_get_last_stored_value(d->disk_ops.rd_ops_writes, &max_iops_writes, 1);
1046 // IO Time
1059 - double iops_time_reads = rrddim_get_last_stored_value(d->rd_iotime_reads, &max_iops_time_reads, 1);
1060 - double iops_time_writes = rrddim_get_last_stored_value(d->rd_iotime_writes, &max_iops_time_writes, 1);
1047 + double iops_time_reads = rrddim_get_last_stored_value(d->disk_iotime.rd_reads_ms, &max_iops_time_reads, 1);
1048 + double iops_time_writes = rrddim_get_last_stored_value(d->disk_iotime.rd_writes_ms, &max_iops_time_writes, 1);
1049 // Avg IO Time
1050 double iops_avg_time_read = rrddim_get_last_stored_value(d->rd_await_reads, &max_iops_avg_time_read, 1);
1051 double iops_avg_time_write = rrddim_get_last_stored_value(d->rd_await_writes, &max_iops_avg_time_write, 1);
@@ -1287,23 +1275,25 @@ static void diskstats_cleanup_disks() {
1275 if (unlikely(global_cleanup_removed_disks && !d->updated)) {
1276 struct disk *t = d;
1277
1278 + rrdset_obsolete_and_pointer_null(d->disk_io.st_io);
1279 + rrdset_obsolete_and_pointer_null(d->disk_ops.st_ops);
1280 + rrdset_obsolete_and_pointer_null(d->disk_qops.st_qops);
1281 + rrdset_obsolete_and_pointer_null(d->disk_util.st_util);
1282 + rrdset_obsolete_and_pointer_null(d->disk_busy.st_busy);
1283 + rrdset_obsolete_and_pointer_null(d->disk_iotime.st_iotime);
1284 +
1285 rrdset_obsolete_and_pointer_null(d->st_avgsz);
1286 rrdset_obsolete_and_pointer_null(d->st_ext_avgsz);
1287 rrdset_obsolete_and_pointer_null(d->st_await);
1288 rrdset_obsolete_and_pointer_null(d->st_ext_await);
1289 rrdset_obsolete_and_pointer_null(d->st_backlog);
1295 - rrdset_obsolete_and_pointer_null(d->st_busy);
1290 rrdset_obsolete_and_pointer_null(d->disk_io.st_io);
1291 rrdset_obsolete_and_pointer_null(d->st_ext_io);
1298 - rrdset_obsolete_and_pointer_null(d->st_iotime);
1292 rrdset_obsolete_and_pointer_null(d->st_ext_iotime);
1293 rrdset_obsolete_and_pointer_null(d->st_mops);
1294 rrdset_obsolete_and_pointer_null(d->st_ext_mops);
1302 - rrdset_obsolete_and_pointer_null(d->st_ops);
1295 rrdset_obsolete_and_pointer_null(d->st_ext_ops);
1304 - rrdset_obsolete_and_pointer_null(d->st_qops);
1296 rrdset_obsolete_and_pointer_null(d->st_svctm);
1306 - rrdset_obsolete_and_pointer_null(d->st_util);
1297 rrdset_obsolete_and_pointer_null(d->st_bcache);
1298 rrdset_obsolete_and_pointer_null(d->st_bcache_bypass);
1299 rrdset_obsolete_and_pointer_null(d->st_bcache_rates);
@@ -1453,18 +1443,17 @@ int do_proc_diskstats(int update_every, usec_t dt) {
1443 char *disk;
1444 unsigned long major = 0, minor = 0;
1445
1456 - collected_number reads = 0, mreads = 0, readsectors = 0, readms = 0,
1457 - writes = 0, mwrites = 0, writesectors = 0, writems = 0,
1446 + collected_number rd_ios = 0, mreads = 0, readsectors = 0, readms = 0, wr_ios = 0, mwrites = 0, writesectors = 0, writems = 0,
1447 queued_ios = 0, busy_ms = 0, backlog_ms = 0,
1448 discards = 0, mdiscards = 0, discardsectors = 0, discardms = 0,
1449 flushes = 0, flushms = 0;
1450
1451
1463 - collected_number last_reads = 0, last_readsectors = 0, last_readms = 0,
1464 - last_writes = 0, last_writesectors = 0, last_writems = 0,
1465 - last_busy_ms = 0,
1466 - last_discards = 0, last_discardsectors = 0, last_discardms = 0,
1467 - last_flushes = 0, last_flushms = 0;
1452 + collected_number last_rd_ios = 0, last_readsectors = 0, last_readms = 0,
1453 + last_wr_ios = 0, last_writesectors = 0, last_writems = 0,
1454 + last_busy_ms = 0,
1455 + last_discards = 0, last_discardsectors = 0, last_discardms = 0,
1456 + last_flushes = 0, last_flushms = 0;
1457
1458 size_t words = procfile_linewords(ff, l);
1459 if(unlikely(words < 14)) continue;
@@ -1475,8 +1464,8 @@ int do_proc_diskstats(int update_every, usec_t dt) {
1464
1465 // # of reads completed # of writes completed
1466 // This is the total number of reads or writes completed successfully.
1478 - reads = str2ull(procfile_lineword(ff, l, 3), NULL); // rd_ios
1479 - writes = str2ull(procfile_lineword(ff, l, 7), NULL); // wr_ios
1467 + rd_ios = str2ull(procfile_lineword(ff, l, 3), NULL); // rd_ios
1468 + wr_ios = str2ull(procfile_lineword(ff, l, 7), NULL); // wr_ios
1469
1470 // # of reads merged # of writes merged
1471 // Reads and writes which are adjacent to each other may be merged for
@@ -1615,33 +1604,15 @@ int do_proc_diskstats(int update_every, usec_t dt) {
1604 if (d->do_ops == CONFIG_BOOLEAN_YES || d->do_ops == CONFIG_BOOLEAN_AUTO) {
1605 d->do_ops = CONFIG_BOOLEAN_YES;
1606
1618 - if(unlikely(!d->st_ops)) {
1619 - d->st_ops = rrdset_create_localhost(
1620 - "disk_ops"
1621 - , d->chart_id
1622 - , d->disk
1623 - , family
1624 - , "disk.ops"
1625 - , "Disk Completed I/O Operations"
1626 - , "operations/s"
1627 - , PLUGIN_PROC_NAME
1628 - , PLUGIN_PROC_MODULE_DISKSTATS_NAME
1629 - , NETDATA_CHART_PRIO_DISK_OPS
1630 - , update_every
1631 - , RRDSET_TYPE_LINE
1632 - );
1633 -
1634 - rrdset_flag_set(d->st_ops, RRDSET_FLAG_DETAIL);
1635 -
1636 - d->rd_ops_reads = rrddim_add(d->st_ops, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1637 - d->rd_ops_writes = rrddim_add(d->st_ops, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
1638 -
1639 - add_labels_to_disk(d, d->st_ops);
1640 - }
1607 + last_rd_ios = d->disk_ops.rd_ops_reads ? d->disk_ops.rd_ops_reads->collector.last_collected_value : 0;
1608 + last_wr_ios = d->disk_ops.rd_ops_writes ? d->disk_ops.rd_ops_writes->collector.last_collected_value : 0;
1609
1642 - last_reads = rrddim_set_by_pointer(d->st_ops, d->rd_ops_reads, reads);
1643 - last_writes = rrddim_set_by_pointer(d->st_ops, d->rd_ops_writes, writes);
1644 - rrdset_done(d->st_ops);
1610 + common_disk_ops(&d->disk_ops,
1611 + d->chart_id,
1612 + d->disk, rd_ios, wr_ios,
1613 + update_every,
1614 + disk_labels_cb,
1615 + d);
1616 }
1617
1618 if (do_dc_stats && d->do_ops == CONFIG_BOOLEAN_YES && d->do_ext != CONFIG_BOOLEAN_NO) {
@@ -1679,31 +1650,14 @@ int do_proc_diskstats(int update_every, usec_t dt) {
1650 if (d->do_qops == CONFIG_BOOLEAN_YES || d->do_qops == CONFIG_BOOLEAN_AUTO) {
1651 d->do_qops = CONFIG_BOOLEAN_YES;
1652
1682 - if(unlikely(!d->st_qops)) {
1683 - d->st_qops = rrdset_create_localhost(
1684 - "disk_qops"
1685 - , d->chart_id
1686 - , d->disk
1687 - , family
1688 - , "disk.qops"
1689 - , "Disk Current I/O Operations"
1690 - , "operations"
1691 - , PLUGIN_PROC_NAME
1692 - , PLUGIN_PROC_MODULE_DISKSTATS_NAME
1693 - , NETDATA_CHART_PRIO_DISK_QOPS
1694 - , update_every
1695 - , RRDSET_TYPE_LINE
1696 - );
1697 -
1698 - rrdset_flag_set(d->st_qops, RRDSET_FLAG_DETAIL);
1699 -
1700 - d->rd_qops_operations = rrddim_add(d->st_qops, "operations", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
1701 -
1702 - add_labels_to_disk(d, d->st_qops);
1703 - }
1704 -
1705 - rrddim_set_by_pointer(d->st_qops, d->rd_qops_operations, queued_ios);
1706 - rrdset_done(d->st_qops);
1653 + common_disk_qops(
1654 + &d->disk_qops,
1655 + d->chart_id,
1656 + d->disk,
1657 + queued_ios,
1658 + update_every,
1659 + disk_labels_cb,
1660 + d);
1661 }
1662
1663 if (d->do_backlog == CONFIG_BOOLEAN_YES || d->do_backlog == CONFIG_BOOLEAN_AUTO) {
@@ -1739,61 +1693,28 @@ int do_proc_diskstats(int update_every, usec_t dt) {
1693 if (d->do_util == CONFIG_BOOLEAN_YES || d->do_util == CONFIG_BOOLEAN_AUTO) {
1694 d->do_util = CONFIG_BOOLEAN_YES;
1695
1742 - if(unlikely(!d->st_busy)) {
1743 - d->st_busy = rrdset_create_localhost(
1744 - "disk_busy"
1745 - , d->chart_id
1746 - , d->disk
1747 - , family
1748 - , "disk.busy"
1749 - , "Disk Busy Time"
1750 - , "milliseconds"
1751 - , PLUGIN_PROC_NAME
1752 - , PLUGIN_PROC_MODULE_DISKSTATS_NAME
1753 - , NETDATA_CHART_PRIO_DISK_BUSY
1754 - , update_every
1755 - , RRDSET_TYPE_AREA
1756 - );
1757 -
1758 - rrdset_flag_set(d->st_busy, RRDSET_FLAG_DETAIL);
1759 -
1760 - d->rd_busy_busy = rrddim_add(d->st_busy, "busy", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1761 -
1762 - add_labels_to_disk(d, d->st_busy);
1763 - }
1764 -
1765 - last_busy_ms = rrddim_set_by_pointer(d->st_busy, d->rd_busy_busy, busy_ms);
1766 - rrdset_done(d->st_busy);
1696 + last_busy_ms = d->disk_busy.rd_busy ? d->disk_busy.rd_busy->collector.last_collected_value : 0;
1697
1768 - if(unlikely(!d->st_util)) {
1769 - d->st_util = rrdset_create_localhost(
1770 - "disk_util"
1771 - , d->chart_id
1772 - , d->disk
1773 - , family
1774 - , "disk.util"
1775 - , "Disk Utilization Time"
1776 - , "% of time working"
1777 - , PLUGIN_PROC_NAME
1778 - , PLUGIN_PROC_MODULE_DISKSTATS_NAME
1779 - , NETDATA_CHART_PRIO_DISK_UTIL
1780 - , update_every
1781 - , RRDSET_TYPE_AREA
1782 - );
1783 -
1784 - rrdset_flag_set(d->st_util, RRDSET_FLAG_DETAIL);
1785 -
1786 - d->rd_util_utilization = rrddim_add(d->st_util, "utilization", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
1787 -
1788 - add_labels_to_disk(d, d->st_util);
1789 - }
1698 + common_disk_busy(&d->disk_busy,
1699 + d->chart_id,
1700 + d->disk,
1701 + busy_ms,
1702 + update_every,
1703 + disk_labels_cb,
1704 + d);
1705
1706 collected_number disk_utilization = (busy_ms - last_busy_ms) / (10 * update_every);
1707 if (disk_utilization > 100)
1708 disk_utilization = 100;
1709
1795 - rrddim_set_by_pointer(d->st_util, d->rd_util_utilization, disk_utilization);
1796 - rrdset_done(d->st_util);
1710 + common_disk_util(&d->disk_util,
1711 + d->chart_id,
1712 + d->disk,
1713 + disk_utilization,
1714 + update_every,
1715 + disk_labels_cb,
1716 + d);
1717 +
1718 }
1719
1720 if (d->do_mops == CONFIG_BOOLEAN_YES || d->do_mops == CONFIG_BOOLEAN_AUTO) {
@@ -1861,33 +1782,18 @@ int do_proc_diskstats(int update_every, usec_t dt) {
1782 if (d->do_iotime == CONFIG_BOOLEAN_YES || d->do_iotime == CONFIG_BOOLEAN_AUTO) {
1783 d->do_iotime = CONFIG_BOOLEAN_YES;
1784
1864 - if(unlikely(!d->st_iotime)) {
1865 - d->st_iotime = rrdset_create_localhost(
1866 - "disk_iotime"
1867 - , d->chart_id
1868 - , d->disk
1869 - , family
1870 - , "disk.iotime"
1871 - , "Disk Total I/O Time"
1872 - , "milliseconds/s"
1873 - , PLUGIN_PROC_NAME
1874 - , PLUGIN_PROC_MODULE_DISKSTATS_NAME
1875 - , NETDATA_CHART_PRIO_DISK_IOTIME
1876 - , update_every
1877 - , RRDSET_TYPE_LINE
1878 - );
1879 -
1880 - rrdset_flag_set(d->st_iotime, RRDSET_FLAG_DETAIL);
1881 -
1882 - d->rd_iotime_reads = rrddim_add(d->st_iotime, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1883 - d->rd_iotime_writes = rrddim_add(d->st_iotime, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
1884 -
1885 - add_labels_to_disk(d, d->st_iotime);
1886 - }
1887 -
1888 - last_readms = rrddim_set_by_pointer(d->st_iotime, d->rd_iotime_reads, readms);
1889 - last_writems = rrddim_set_by_pointer(d->st_iotime, d->rd_iotime_writes, writems);
1890 - rrdset_done(d->st_iotime);
1785 + last_readms = d->disk_iotime.rd_reads_ms ? d->disk_iotime.rd_reads_ms->collector.last_collected_value : 0;
1786 + last_writems = d->disk_iotime.rd_writes_ms ? d->disk_iotime.rd_writes_ms->collector.last_collected_value : 0;
1787 +
1788 + common_disk_iotime(
1789 + &d->disk_iotime,
1790 + d->chart_id,
1791 + d->disk,
1792 + readms,
1793 + writems,
1794 + update_every,
1795 + disk_labels_cb,
1796 + d);
1797 }
1798
1799 if(do_dc_stats && d->do_iotime == CONFIG_BOOLEAN_YES && d->do_ext != CONFIG_BOOLEAN_NO) {
@@ -1952,8 +1858,8 @@ int do_proc_diskstats(int update_every, usec_t dt) {
1858 add_labels_to_disk(d, d->st_await);
1859 }
1860
1955 - double read_avg = (reads - last_reads) ? (double)(readms - last_readms) / (reads - last_reads) : 0;
1956 - double write_avg = (writes - last_writes) ? (double)(writems - last_writems) / (writes - last_writes) : 0;
1861 + double read_avg = (rd_ios - last_rd_ios) ? (double)(readms - last_readms) / (rd_ios - last_rd_ios) : 0;
1862 + double write_avg = (wr_ios - last_wr_ios) ? (double)(writems - last_writems) / (wr_ios - last_wr_ios) : 0;
1863
1864 rrddim_set_by_pointer(d->st_await, d->rd_await_reads, (collected_number)(read_avg * 1000));
1865 rrddim_set_by_pointer(d->st_await, d->rd_await_writes, (collected_number)(write_avg * 1000));
@@ -2025,8 +1931,8 @@ int do_proc_diskstats(int update_every, usec_t dt) {
1931 add_labels_to_disk(d, d->st_avgsz);
1932 }
1933
2028 - rrddim_set_by_pointer(d->st_avgsz, d->rd_avgsz_reads, (reads - last_reads) ? (readsectors - last_readsectors) / (reads - last_reads) : 0);
2029 - rrddim_set_by_pointer(d->st_avgsz, d->rd_avgsz_writes, (writes - last_writes) ? (writesectors - last_writesectors) / (writes - last_writes) : 0);
1934 + rrddim_set_by_pointer(d->st_avgsz, d->rd_avgsz_reads, (rd_ios - last_rd_ios) ? (readsectors - last_readsectors) / (rd_ios - last_rd_ios) : 0);
1935 + rrddim_set_by_pointer(d->st_avgsz, d->rd_avgsz_writes, (wr_ios - last_wr_ios) ? (writesectors - last_writesectors) / (wr_ios - last_wr_ios) : 0);
1936 rrdset_done(d->st_avgsz);
1937 }
1938
@@ -2087,8 +1993,8 @@ int do_proc_diskstats(int update_every, usec_t dt) {
1993 }
1994
1995 double svctm_avg =
2090 - ((reads - last_reads) + (writes - last_writes)) ?
2091 - (double)(busy_ms - last_busy_ms) / ((reads - last_reads) + (writes - last_writes)) :
1996 + ((rd_ios - last_rd_ios) + (wr_ios - last_wr_ios)) ?
1997 + (double)(busy_ms - last_busy_ms) / ((rd_ios - last_rd_ios) + (wr_ios - last_wr_ios)) :
1998 0;
1999
2000 rrddim_set_by_pointer(d->st_svctm, d->rd_svctm_svctm, (collected_number)(svctm_avg * 1000));
src/collectors/windows.plugin/perflib-storage.c
+190 -50
@@ -8,6 +8,7 @@
8 #include "../common-contexts/common-contexts.h"
9
10 struct logical_disk {
11 + usec_t last_collected;
12 bool collected_metadata;
13
14 STRING *filesystem;
@@ -21,6 +22,7 @@ struct logical_disk {
22 };
23
24 struct physical_disk {
25 + usec_t last_collected;
26 bool collected_metadata;
27
28 STRING *device;
@@ -30,11 +32,23 @@ struct physical_disk {
32 COUNTER_DATA diskReadBytesPerSec;
33 COUNTER_DATA diskWriteBytesPerSec;
34
35 + ND_DISK_OPS disk_ops;
36 + COUNTER_DATA diskReadsPerSec;
37 + COUNTER_DATA diskWritesPerSec;
38 +
39 + ND_DISK_UTIL disk_util;
40 COUNTER_DATA percentIdleTime;
41 +
42 + ND_DISK_BUSY disk_busy;
43 COUNTER_DATA percentDiskTime;
44 +
45 + ND_DISK_IOTIME disk_iotime;
46 COUNTER_DATA percentDiskReadTime;
47 COUNTER_DATA percentDiskWriteTime;
48 +
49 + ND_DISK_QOPS disk_qops;
50 COUNTER_DATA currentDiskQueueLength;
51 +
52 COUNTER_DATA averageDiskQueueLength;
53 COUNTER_DATA averageDiskReadQueueLength;
54 COUNTER_DATA averageDiskWriteQueueLength;
@@ -42,8 +56,6 @@ struct physical_disk {
56 COUNTER_DATA averageDiskSecondsPerRead;
57 COUNTER_DATA averageDiskSecondsPerWrite;
58 COUNTER_DATA diskTransfersPerSec;
45 - COUNTER_DATA diskReadsPerSec;
46 - COUNTER_DATA diskWritesPerSec;
59 COUNTER_DATA diskBytesPerSec;
60 COUNTER_DATA averageDiskBytesPerTransfer;
61 COUNTER_DATA averageDiskBytesPerRead;
@@ -55,45 +67,61 @@ struct physical_disk system_physical_total = {
67 .collected_metadata = true,
68 };
69
58 -void dict_logical_disk_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
59 - struct logical_disk *ld = value;
70 +static void dict_logical_disk_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
71 + struct logical_disk *d = value;
72 +
73 + d->percentDiskFree.key = "% Free Space";
74 + // d->freeMegabytes.key = "Free Megabytes";
75 +}
76 +
77 +static void logical_disk_cleanup(struct logical_disk *d) {
78 + rrdset_is_obsolete___safe_from_collector_thread(d->st_disk_space);
79 +}
80
61 - ld->percentDiskFree.key = "% Free Space";
62 - // ld->freeMegabytes.key = "Free Megabytes";
81 +static void physical_disk_initialize(struct physical_disk *d) {
82 + d->percentIdleTime.key = "% Idle Time";
83 + d->percentDiskTime.key = "% Disk Time";
84 + d->percentDiskReadTime.key = "% Disk Read Time";
85 + d->percentDiskWriteTime.key = "% Disk Write Time";
86 + d->currentDiskQueueLength.key = "Current Disk Queue Length";
87 + d->averageDiskQueueLength.key = "Avg. Disk Queue Length";
88 + d->averageDiskReadQueueLength.key = "Avg. Disk Read Queue Length";
89 + d->averageDiskWriteQueueLength.key = "Avg. Disk Write Queue Length";
90 + d->averageDiskSecondsPerTransfer.key = "Avg. Disk sec/Transfer";
91 + d->averageDiskSecondsPerRead.key = "Avg. Disk sec/Read";
92 + d->averageDiskSecondsPerWrite.key = "Avg. Disk sec/Write";
93 + d->diskTransfersPerSec.key = "Disk Transfers/sec";
94 + d->diskReadsPerSec.key = "Disk Reads/sec";
95 + d->diskWritesPerSec.key = "Disk Writes/sec";
96 + d->diskBytesPerSec.key = "Disk Bytes/sec";
97 + d->diskReadBytesPerSec.key = "Disk Read Bytes/sec";
98 + d->diskWriteBytesPerSec.key = "Disk Write Bytes/sec";
99 + d->averageDiskBytesPerTransfer.key = "Avg. Disk Bytes/Transfer";
100 + d->averageDiskBytesPerRead.key = "Avg. Disk Bytes/Read";
101 + d->averageDiskBytesPerWrite.key = "Avg. Disk Bytes/Write";
102 + d->splitIoPerSec.key = "Split IO/Sec";
103 }
104
65 -void initialize_physical_disk(struct physical_disk *pd) {
66 - pd->percentIdleTime.key = "% Idle Time";
67 - pd->percentDiskTime.key = "% Disk Time";
68 - pd->percentDiskReadTime.key = "% Disk Read Time";
69 - pd->percentDiskWriteTime.key = "% Disk Write Time";
70 - pd->currentDiskQueueLength.key = "Current Disk Queue Length";
71 - pd->averageDiskQueueLength.key = "Avg. Disk Queue Length";
72 - pd->averageDiskReadQueueLength.key = "Avg. Disk Read Queue Length";
73 - pd->averageDiskWriteQueueLength.key = "Avg. Disk Write Queue Length";
74 - pd->averageDiskSecondsPerTransfer.key = "Avg. Disk sec/Transfer";
75 - pd->averageDiskSecondsPerRead.key = "Avg. Disk sec/Read";
76 - pd->averageDiskSecondsPerWrite.key = "Avg. Disk sec/Write";
77 - pd->diskTransfersPerSec.key = "Disk Transfers/sec";
78 - pd->diskReadsPerSec.key = "Disk Reads/sec";
79 - pd->diskWritesPerSec.key = "Disk Writes/sec";
80 - pd->diskBytesPerSec.key = "Disk Bytes/sec";
81 - pd->diskReadBytesPerSec.key = "Disk Read Bytes/sec";
82 - pd->diskWriteBytesPerSec.key = "Disk Write Bytes/sec";
83 - pd->averageDiskBytesPerTransfer.key = "Avg. Disk Bytes/Transfer";
84 - pd->averageDiskBytesPerRead.key = "Avg. Disk Bytes/Read";
85 - pd->averageDiskBytesPerWrite.key = "Avg. Disk Bytes/Write";
86 - pd->splitIoPerSec.key = "Split IO/Sec";
105 +static void physical_disk_cleanup(struct physical_disk *d) {
106 + string_freez(d->device);
107 + string_freez(d->mount_point);
108 +
109 + rrdset_is_obsolete___safe_from_collector_thread(d->disk_io.st_io);
110 + rrdset_is_obsolete___safe_from_collector_thread(d->disk_ops.st_ops);
111 + rrdset_is_obsolete___safe_from_collector_thread(d->disk_util.st_util);
112 + rrdset_is_obsolete___safe_from_collector_thread(d->disk_busy.st_busy);
113 + rrdset_is_obsolete___safe_from_collector_thread(d->disk_iotime.st_iotime);
114 + rrdset_is_obsolete___safe_from_collector_thread(d->disk_qops.st_qops);
115 }
116
117 void dict_physical_disk_insert_cb(const DICTIONARY_ITEM *item __maybe_unused, void *value, void *data __maybe_unused) {
118 struct physical_disk *pd = value;
91 - initialize_physical_disk(pd);
119 + physical_disk_initialize(pd);
120 }
121
122 static DICTIONARY *logicalDisks = NULL, *physicalDisks = NULL;
123 static void initialize(void) {
96 - initialize_physical_disk(&system_physical_total);
124 + physical_disk_initialize(&system_physical_total);
125
126 logicalDisks = dictionary_create_advanced(DICT_OPTION_DONT_OVERWRITE_VALUE |
127 DICT_OPTION_FIXED_SIZE, NULL, sizeof(struct logical_disk));
@@ -144,7 +172,7 @@ static STRING *getFileSystemType(const char* diskName) {
172 return NULL;
173 }
174
147 -static bool do_logical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
175 +static bool do_logical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every, usec_t now_ut) {
176 DICTIONARY *dict = logicalDisks;
177
178 PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, "LogicalDisk");
@@ -162,6 +190,7 @@ static bool do_logical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
190 continue;
191
192 struct logical_disk *d = dictionary_set(dict, windows_shared_buffer, NULL, sizeof(*d));
193 + d->last_collected = now_ut;
194
195 if(!d->collected_metadata) {
196 d->filesystem = getFileSystemType(windows_shared_buffer);
@@ -174,8 +203,10 @@ static bool do_logical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
203 if(!d->st_disk_space) {
204 d->st_disk_space = rrdset_create_localhost(
205 "disk_space"
177 - , windows_shared_buffer, NULL
178 - , windows_shared_buffer, "disk.space"
206 + , windows_shared_buffer
207 + , NULL
208 + , windows_shared_buffer
209 + , "disk.space"
210 , "Disk Space Usage"
211 , "GiB"
212 , PLUGIN_WINDOWS_NAME
@@ -201,6 +232,19 @@ static bool do_logical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
232 rrdset_done(d->st_disk_space);
233 }
234
235 + // cleanup
236 + {
237 + struct logical_disk *d;
238 + dfe_start_write(dict, d) {
239 + if(d->last_collected < now_ut) {
240 + logical_disk_cleanup(d);
241 + dictionary_del(dict, d_dfe.name);
242 + }
243 + }
244 + dfe_done(d);
245 + dictionary_garbage_collect(dict);
246 + }
247 +
248 return true;
249 }
250
@@ -214,7 +258,12 @@ static void physical_disk_labels(RRDSET *st, void *data) {
258 rrdlabels_add(st->rrdlabels, "mount_point", string2str(d->mount_point), RRDLABEL_SRC_AUTO);
259 }
260
217 -static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
261 +static bool str_is_numeric(const char *s) {
262 + while(*s) if(!isdigit((uint8_t)*s++)) return false;
263 + return true;
264 +}
265 +
266 +static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every, usec_t now_ut) {
267 DICTIONARY *dict = physicalDisks;
268
269 PERF_OBJECT_TYPE *pObjectType = perflibFindObjectTypeByName(pDataBlock, "PhysicalDisk");
@@ -230,12 +279,7 @@ static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
279 strncpyz(windows_shared_buffer, "[unknown]", sizeof(windows_shared_buffer) - 1);
280
281 char *device = windows_shared_buffer;
233 - char *mount_point = NULL;
234 -
235 - if((mount_point = strchr(device, ' '))) {
236 - *mount_point = '\0';
237 - mount_point++;
238 - }
282 + char mount_point[128]; mount_point[0] = '\0';
283
284 struct physical_disk *d;
285 bool is_system;
@@ -244,9 +288,22 @@ static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
288 is_system = true;
289 }
290 else {
291 + char *space;
292 + if((space = strchr(windows_shared_buffer, ' '))) {
293 + *space++ = '\0';
294 + strncpyz(mount_point, space, sizeof(mount_point) - 1);
295 + }
296 +
297 + if(str_is_numeric(windows_shared_buffer)) {
298 + uint64_t n = str2ull(device, NULL);
299 + snprintfz(windows_shared_buffer, sizeof(windows_shared_buffer), "Disk %" PRIu64, n);
300 + device = windows_shared_buffer;
301 + }
302 +
303 d = dictionary_set(dict, device, NULL, sizeof(*d));
304 is_system = false;
305 }
306 + d->last_collected = now_ut;
307
308 if (!d->collected_metadata) {
309 // TODO collect metadata - device_type, serial, id
@@ -258,7 +315,10 @@ static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
315 if (perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskReadBytesPerSec) &&
316 perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskWriteBytesPerSec)) {
317 if(is_system)
261 - common_system_io(d->diskReadBytesPerSec.current.Data, d->diskWriteBytesPerSec.current.Data, update_every);
318 + common_system_io(
319 + d->diskReadBytesPerSec.current.Data,
320 + d->diskWriteBytesPerSec.current.Data,
321 + update_every);
322 else
323 common_disk_io(
324 &d->disk_io,
@@ -271,11 +331,79 @@ static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
331 d);
332 }
333
274 - perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentIdleTime);
275 - perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentDiskTime);
276 - perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentDiskReadTime);
277 - perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentDiskWriteTime);
278 - perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->currentDiskQueueLength);
334 + if(is_system) continue;
335 +
336 + if (perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskReadsPerSec) &&
337 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskWritesPerSec)) {
338 +
339 + common_disk_ops(
340 + &d->disk_ops,
341 + device,
342 + NULL,
343 + d->diskReadBytesPerSec.current.Data,
344 + d->diskWriteBytesPerSec.current.Data,
345 + update_every,
346 + physical_disk_labels,
347 + d);
348 + }
349 +
350 + if (perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentIdleTime)) {
351 + if (d->percentIdleTime.previous.Data && d->percentIdleTime.previous.Time &&
352 + d->percentIdleTime.current.Time > d->percentIdleTime.previous.Time) {
353 + collected_number idle_percentage =
354 + 100 * (d->percentIdleTime.current.Data - d->percentIdleTime.previous.Data)
355 + / (d->percentIdleTime.current.Time - d->percentIdleTime.previous.Time);
356 +
357 + if (idle_percentage > 100)
358 + idle_percentage = 100;
359 +
360 + common_disk_util(
361 + &d->disk_util,
362 + device,
363 + NULL,
364 + 100 - idle_percentage,
365 + update_every,
366 + physical_disk_labels,
367 + d);
368 + }
369 + }
370 +
371 + if (perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentDiskTime)) {
372 + common_disk_busy(
373 + &d->disk_busy,
374 + device,
375 + NULL,
376 + d->percentDiskTime.current.Data / NS100_PER_MS,
377 + update_every,
378 + physical_disk_labels,
379 + d);
380 + }
381 +
382 + if (perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentDiskReadTime) &&
383 + perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->percentDiskWriteTime)) {
384 +
385 + common_disk_iotime(
386 + &d->disk_iotime,
387 + device,
388 + NULL,
389 + d->percentDiskReadTime.current.Data / NS100_PER_MS,
390 + d->percentDiskWriteTime.current.Data / NS100_PER_MS,
391 + update_every,
392 + physical_disk_labels,
393 + d);
394 + }
395 +
396 + if(perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->currentDiskQueueLength)) {
397 + common_disk_qops(
398 + &d->disk_qops,
399 + device,
400 + NULL,
401 + d->currentDiskQueueLength.current.Data,
402 + update_every,
403 + physical_disk_labels,
404 + d);
405 + }
406 +
407 perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskQueueLength);
408 perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskReadQueueLength);
409 perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskWriteQueueLength);
@@ -283,8 +411,6 @@ static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
411 perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskSecondsPerRead);
412 perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskSecondsPerWrite);
413 perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskTransfersPerSec);
286 - perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskReadsPerSec);
287 - perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskWritesPerSec);
414 perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->diskBytesPerSec);
415 perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskBytesPerTransfer);
416 perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->averageDiskBytesPerRead);
@@ -292,6 +418,19 @@ static bool do_physical_disk(PERF_DATA_BLOCK *pDataBlock, int update_every) {
418 perflibGetInstanceCounter(pDataBlock, pObjectType, pi, &d->splitIoPerSec);
419 }
420
421 + // cleanup
422 + {
423 + struct physical_disk *d;
424 + dfe_start_write(dict, d) {
425 + if(d->last_collected < now_ut) {
426 + physical_disk_cleanup(d);
427 + dictionary_del(dict, d_dfe.name);
428 + }
429 + }
430 + dfe_done(d);
431 + dictionary_garbage_collect(dict);
432 + }
433 +
434 return true;
435 }
436
@@ -310,8 +449,9 @@ int do_PerflibStorage(int update_every, usec_t dt __maybe_unused) {
449 PERF_DATA_BLOCK *pDataBlock = perflibGetPerformanceData(id);
450 if(!pDataBlock) return -1;
451
313 - do_logical_disk(pDataBlock, update_every);
314 - do_physical_disk(pDataBlock, update_every);
452 + usec_t now_ut = now_monotonic_usec();
453 + do_logical_disk(pDataBlock, update_every, now_ut);
454 + do_physical_disk(pDataBlock, update_every, now_ut);
455
456 return 0;
457 }
src/libnetdata/clocks/clocks.h
+2
@@ -77,6 +77,8 @@ typedef struct heartbeat {
77 #define MSEC_PER_SEC 1000ULL
78 #endif
79
80 +#define NS100_PER_MS 10000ULL
81 +
82 #define USEC_PER_MS 1000ULL
83
84 #ifndef HAVE_CLOCK_GETTIME
src/libnetdata/os/windows-perflib/perflib.c
+32 -5
@@ -454,6 +454,26 @@ PERF_INSTANCE_DEFINITION *perflibForEachInstance(PERF_DATA_BLOCK *pDataBlock, PE
454 }
455
456 bool perflibGetInstanceCounter(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *pInstance, COUNTER_DATA *cd) {
457 + DWORD id = cd->id;
458 + const char *key = cd->key;
459 + internal_fatal(key == NULL, "You have to set a key for this call.");
460 +
461 + if(unlikely(cd->failures >= PERFLIB_MAX_FAILURES_TO_FIND_METRIC)) {
462 + // we don't want to lookup and compare strings all the time
463 + // when a metric is not there, so we try to find it for
464 + // XX times, and then we give up.
465 +
466 + if(cd->failures == PERFLIB_MAX_FAILURES_TO_FIND_METRIC) {
467 + nd_log(NDLS_COLLECTORS, NDLP_ERR,
468 + "WINDOWS: PERFLIB: Giving up on metric '%s' (tried to find it %u times).",
469 + cd->key, cd->failures);
470 +
471 + cd->failures++; // increment it once, so that we will not log this again
472 + }
473 +
474 + goto failed;
475 + }
476 +
477 PERF_COUNTER_DEFINITION *pCounterDefinition = NULL;
478 for(DWORD c = 0; c < pObjectType->NumCounters ;c++) {
479 pCounterDefinition = getCounterDefinition(pDataBlock, pObjectType, pCounterDefinition);
@@ -464,12 +484,13 @@ bool perflibGetInstanceCounter(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pO
484 break;
485 }
486
467 - if(cd->id) {
468 - if(cd->id != pCounterDefinition->CounterNameTitleIndex)
487 + if(id) {
488 + if(id != pCounterDefinition->CounterNameTitleIndex)
489 continue;
490 }
491 else {
472 - if(strcmp(RegistryFindNameByID(pCounterDefinition->CounterNameTitleIndex), cd->key) != 0)
492 + const char *name = RegistryFindNameByID(pCounterDefinition->CounterNameTitleIndex);
493 + if(strcmp(name, key) != 0)
494 continue;
495
496 cd->id = pCounterDefinition->CounterNameTitleIndex;
@@ -479,10 +500,16 @@ bool perflibGetInstanceCounter(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pO
500 PERF_COUNTER_BLOCK *pCounterBlock = getInstanceCounterBlock(pDataBlock, pObjectType, pInstance);
501
502 cd->previous = cd->current;
482 - cd->updated = getCounterData(pDataBlock, pObjectType, pCounterDefinition, pCounterBlock, &cd->current);
483 - return cd->updated;
503 + if(likely(getCounterData(pDataBlock, pObjectType, pCounterDefinition, pCounterBlock, &cd->current))) {
504 + cd->updated = true;
505 + cd->failures = 0;
506 + return true;
507 + }
508 }
509
510 + cd->failures++;
511 +
512 +failed:
513 cd->previous = cd->current;
514 cd->current = RAW_DATA_EMPTY;
515 cd->updated = false;
src/libnetdata/os/windows-perflib/perflib.h
+3
@@ -43,12 +43,15 @@ typedef struct _rawdata {
43 typedef struct _counterdata {
44 DWORD id;
45 bool updated;
46 + uint8_t failures; // counts the number of failures to find this key
47 const char *key;
48 DWORD OverwriteCounterType; // if set, the counter type will be overwritten once read
49 RAW_DATA current;
50 RAW_DATA previous;
51 } COUNTER_DATA;
52
53 +#define PERFLIB_MAX_FAILURES_TO_FIND_METRIC 10
54 +
55 #define RAW_DATA_EMPTY (RAW_DATA){ 0 }
56
57 bool perflibGetInstanceCounter(PERF_DATA_BLOCK *pDataBlock, PERF_OBJECT_TYPE *pObjectType, PERF_INSTANCE_DEFINITION *pInstance, COUNTER_DATA *cd);