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);