Add disk charts to macOS plugin
Vladimir Kobal committed
Jan 12, 2017 at 17:50 UTC
33b65ce0e50c4cdac647d3adbb80518b7624ade5
1 file changed
+217
-20
src/macos_fw.c
+217
-20
@@ -2,6 +2,9 @@
2
#include <CoreFoundation/CoreFoundation.h>
3
#include <IOKit/IOKitLib.h>
4
#include <IOKit/storage/IOBlockStorageDriver.h>
5
+#include <IOKit/IOBSD.h>
6
+
7
+#define MAXDRIVENAME 31
8
9
int do_macos_iokit(int update_every, usec_t dt) {
10
(void)dt;
@@ -15,54 +18,248 @@ int do_macos_iokit(int update_every, usec_t dt) {
18
RRDSET *st;
19
20
mach_port_t master_port;
18
- io_registry_entry_t drive;
21
+ io_registry_entry_t drive, drive_media;
22
io_iterator_t drive_list;
20
- CFNumberRef number;
23
CFDictionaryRef properties, statistics;
22
- UInt64 value;
24
+ CFStringRef name;
25
+ CFNumberRef number;
26
+ kern_return_t status;
27
collected_number total_disk_reads = 0;
28
collected_number total_disk_writes = 0;
29
+ struct diskstat {
30
+ char name[MAXDRIVENAME];
31
+ collected_number bytes_read;
32
+ collected_number bytes_write;
33
+ collected_number reads;
34
+ collected_number writes;
35
+ collected_number time_read;
36
+ collected_number time_write;
37
+ collected_number latency_read;
38
+ collected_number latency_write;
39
+ } diskstat;
40
+ struct cur_diskstat {
41
+ collected_number duration_read_ns;
42
+ collected_number duration_write_ns;
43
+ collected_number busy_time_ns;
44
+ } cur_diskstat;
45
+ struct prev_diskstat {
46
+ collected_number bytes_read;
47
+ collected_number bytes_write;
48
+ collected_number operations_read;
49
+ collected_number operations_write;
50
+ collected_number duration_read_ns;
51
+ collected_number duration_write_ns;
52
+ collected_number busy_time_ns;
53
+ } prev_diskstat;
54
55
/* Get ports and services for drive statistics. */
27
- if (IOMasterPort(bootstrap_port, &master_port)) {
56
+ if (unlikely(IOMasterPort(bootstrap_port, &master_port))) {
57
error("MACOS: IOMasterPort() failed");
58
do_io = 0;
59
error("DISABLED: system.io");
60
/* Get the list of all drive objects. */
32
- } else if (IOServiceGetMatchingServices(master_port, IOServiceMatching("IOBlockStorageDriver"), &drive_list)) {
61
+ } else if (unlikely(IOServiceGetMatchingServices(master_port, IOServiceMatching("IOBlockStorageDriver"), &drive_list))) {
62
error("MACOS: IOServiceGetMatchingServices() failed");
63
do_io = 0;
64
error("DISABLED: system.io");
65
} else {
66
while ((drive = IOIteratorNext(drive_list)) != 0) {
38
- number = 0;
67
properties = 0;
68
statistics = 0;
41
- value = 0;
69
+ number = 0;
70
+ bzero(&diskstat, sizeof(diskstat));
71
+
72
+ /* Get drive media object. */
73
+ status = IORegistryEntryGetChildEntry(drive, kIOServicePlane, &drive_media);
74
+ if (unlikely(status != KERN_SUCCESS)) {
75
+ IOObjectRelease(drive);
76
+ continue;
77
+ }
78
+
79
+ /* Get drive media properties. */
80
+ if (likely(!IORegistryEntryCreateCFProperties(drive_media, (CFMutableDictionaryRef *)&properties, kCFAllocatorDefault, 0))) {
81
+ /* Get disk name. */
82
+ if (likely(name = (CFStringRef)CFDictionaryGetValue(properties, CFSTR(kIOBSDNameKey)))) {
83
+ CFStringGetCString(name, diskstat.name, MAXDRIVENAME, kCFStringEncodingUTF8);
84
+ }
85
+ }
86
+
87
+ /* Release. */
88
+ CFRelease(properties);
89
+ IOObjectRelease(drive_media);
90
91
/* Obtain the properties for this drive object. */
44
- if (IORegistryEntryCreateCFProperties(drive, (CFMutableDictionaryRef *)&properties, kCFAllocatorDefault, 0)) {
92
+ if (unlikely(IORegistryEntryCreateCFProperties(drive, (CFMutableDictionaryRef *)&properties, kCFAllocatorDefault, 0))) {
93
error("MACOS: IORegistryEntryCreateCFProperties() failed");
94
do_io = 0;
95
error("DISABLED: system.io");
96
break;
49
- } else if (properties != 0) {
97
+ } else if (likely(properties)) {
98
/* Obtain the statistics from the drive properties. */
51
- statistics = (CFDictionaryRef)CFDictionaryGetValue(properties, CFSTR(kIOBlockStorageDriverStatisticsKey));
99
+ if (likely(statistics = (CFDictionaryRef)CFDictionaryGetValue(properties, CFSTR(kIOBlockStorageDriverStatisticsKey)))) {
100
+
101
+ // --------------------------------------------------------------------
102
53
- if (statistics != 0) {
103
/* Get bytes read. */
55
- number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey));
56
- if (number != 0) {
57
- CFNumberGetValue(number, kCFNumberSInt64Type, &value);
58
- total_disk_reads += value;
104
+ if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey)))) {
105
+ CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.bytes_read);
106
+ total_disk_reads += diskstat.bytes_read;
107
}
108
109
/* Get bytes written. */
62
- number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey));
63
- if (number != 0) {
64
- CFNumberGetValue(number, kCFNumberSInt64Type, &value);
65
- total_disk_writes += value;
110
+ if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey)))) {
111
+ CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.bytes_write);
112
+ total_disk_writes += diskstat.bytes_write;
113
+ }
114
+
115
+ st = rrdset_find_bytype("disk", diskstat.name);
116
+ if (unlikely(!st)) {
117
+ st = rrdset_create("disk", diskstat.name, NULL, diskstat.name, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA);
118
+
119
+ rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_INCREMENTAL);
120
+ rrddim_add(st, "writes", NULL, -1, 1024, RRDDIM_INCREMENTAL);
121
+ }
122
+ else rrdset_next(st);
123
+
124
+ prev_diskstat.bytes_read = rrddim_set(st, "reads", diskstat.bytes_read);
125
+ prev_diskstat.bytes_write = rrddim_set(st, "writes", diskstat.bytes_write);
126
+ rrdset_done(st);
127
+
128
+ // --------------------------------------------------------------------
129
+
130
+ /* Get number of reads. */
131
+ if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsReadsKey)))) {
132
+ CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.reads);
133
+ }
134
+
135
+ /* Get number of writes. */
136
+ if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsWritesKey)))) {
137
+ CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.writes);
138
+ }
139
+
140
+ st = rrdset_find_bytype("disk_ops", diskstat.name);
141
+ if (unlikely(!st)) {
142
+ st = rrdset_create("disk_ops", diskstat.name, NULL, diskstat.name, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE);
143
+ st->isdetail = 1;
144
+
145
+ rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
146
+ rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
147
+ }
148
+ else rrdset_next(st);
149
+
150
+ prev_diskstat.operations_read = rrddim_set(st, "reads", diskstat.reads);
151
+ prev_diskstat.operations_write = rrddim_set(st, "writes", diskstat.writes);
152
+ rrdset_done(st);
153
+
154
+ // --------------------------------------------------------------------
155
+
156
+ /* Get reads time. */
157
+ if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsTotalReadTimeKey)))) {
158
+ CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.time_read);
159
+ }
160
+
161
+ /* Get writes time. */
162
+ if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsTotalWriteTimeKey)))) {
163
+ CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.time_write);
164
+ }
165
+
166
+ st = rrdset_find_bytype("disk_util", diskstat.name);
167
+ if (unlikely(!st)) {
168
+ st = rrdset_create("disk_util", diskstat.name, NULL, diskstat.name, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA);
169
+ st->isdetail = 1;
170
+
171
+ rrddim_add(st, "utilization", NULL, 1, 10000000, RRDDIM_INCREMENTAL);
172
+ }
173
+ else rrdset_next(st);
174
+
175
+ cur_diskstat.busy_time_ns = (diskstat.time_read + diskstat.time_write);
176
+ prev_diskstat.busy_time_ns = rrddim_set(st, "utilization", cur_diskstat.busy_time_ns);
177
+ rrdset_done(st);
178
+
179
+ // --------------------------------------------------------------------
180
+
181
+ /* Get reads latency. */
182
+ if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsLatentReadTimeKey)))) {
183
+ CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.latency_read);
184
+ }
185
+
186
+ /* Get writes latency. */
187
+ if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsLatentWriteTimeKey)))) {
188
+ CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.latency_write);
189
+ }
190
+
191
+ st = rrdset_find_bytype("disk_iotime", diskstat.name);
192
+ if (unlikely(!st)) {
193
+ st = rrdset_create("disk_iotime", diskstat.name, NULL, diskstat.name, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE);
194
+ st->isdetail = 1;
195
+
196
+ rrddim_add(st, "reads", NULL, 1, 1000000, RRDDIM_INCREMENTAL);
197
+ rrddim_add(st, "writes", NULL, -1, 1000000, RRDDIM_INCREMENTAL);
198
+ }
199
+ else rrdset_next(st);
200
+
201
+ cur_diskstat.duration_read_ns = diskstat.time_read + diskstat.latency_read;
202
+ cur_diskstat.duration_write_ns = diskstat.time_write + diskstat.latency_write;
203
+ prev_diskstat.duration_read_ns = rrddim_set(st, "reads", cur_diskstat.duration_read_ns);
204
+ prev_diskstat.duration_write_ns = rrddim_set(st, "writes", cur_diskstat.duration_write_ns);
205
+ rrdset_done(st);
206
+
207
+ // --------------------------------------------------------------------
208
+ // calculate differential charts
209
+ // only if this is not the first time we run
210
+
211
+ if (likely(dt)) {
212
+
213
+ // --------------------------------------------------------------------
214
+
215
+ st = rrdset_find_bytype("disk_await", diskstat.name);
216
+ if (unlikely(!st)) {
217
+ st = rrdset_create("disk_await", diskstat.name, NULL, diskstat.name, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE);
218
+ st->isdetail = 1;
219
+
220
+ rrddim_add(st, "reads", NULL, 1, 1000000, RRDDIM_ABSOLUTE);
221
+ rrddim_add(st, "writes", NULL, -1, 1000000, RRDDIM_ABSOLUTE);
222
+ }
223
+ else rrdset_next(st);
224
+
225
+ rrddim_set(st, "reads", (diskstat.reads - prev_diskstat.operations_read) ?
226
+ (cur_diskstat.duration_read_ns - prev_diskstat.duration_read_ns) / (diskstat.reads - prev_diskstat.operations_read) : 0);
227
+ rrddim_set(st, "writes", (diskstat.writes - prev_diskstat.operations_write) ?
228
+ (cur_diskstat.duration_write_ns - prev_diskstat.duration_write_ns) / (diskstat.writes - prev_diskstat.operations_write) : 0);
229
+ rrdset_done(st);
230
+
231
+ // --------------------------------------------------------------------
232
+
233
+ st = rrdset_find_bytype("disk_avgsz", diskstat.name);
234
+ if (unlikely(!st)) {
235
+ st = rrdset_create("disk_avgsz", diskstat.name, NULL, diskstat.name, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA);
236
+ st->isdetail = 1;
237
+
238
+ rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_ABSOLUTE);
239
+ rrddim_add(st, "writes", NULL, -1, 1024, RRDDIM_ABSOLUTE);
240
+ }
241
+ else rrdset_next(st);
242
+
243
+ rrddim_set(st, "reads", (diskstat.reads - prev_diskstat.operations_read) ?
244
+ (diskstat.bytes_read - prev_diskstat.bytes_read) / (diskstat.reads - prev_diskstat.operations_read) : 0);
245
+ rrddim_set(st, "writes", (diskstat.writes - prev_diskstat.operations_write) ?
246
+ (diskstat.bytes_write - prev_diskstat.bytes_write) / (diskstat.writes - prev_diskstat.operations_write) : 0);
247
+ rrdset_done(st);
248
+
249
+ // --------------------------------------------------------------------
250
+
251
+ st = rrdset_find_bytype("disk_svctm", diskstat.name);
252
+ if (unlikely(!st)) {
253
+ st = rrdset_create("disk_svctm", diskstat.name, NULL, diskstat.name, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE);
254
+ st->isdetail = 1;
255
+
256
+ rrddim_add(st, "svctm", NULL, 1, 1000000, RRDDIM_ABSOLUTE);
257
+ }
258
+ else rrdset_next(st);
259
+
260
+ rrddim_set(st, "svctm", ((diskstat.reads - prev_diskstat.operations_read) + (diskstat.writes - prev_diskstat.operations_write)) ?
261
+ (cur_diskstat.busy_time_ns - prev_diskstat.busy_time_ns) / ((diskstat.reads - prev_diskstat.operations_read) + (diskstat.writes - prev_diskstat.operations_write)) : 0);
262
+ rrdset_done(st);
263
}
264
}
265
@@ -79,7 +276,7 @@ int do_macos_iokit(int update_every, usec_t dt) {
276
IOObjectRelease(drive_list);
277
}
278
82
- if (do_io) {
279
+ if (likely(do_io)) {
280
st = rrdset_find_bytype("system", "io");
281
if (unlikely(!st)) {
282
st = rrdset_create("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150, update_every, RRDSET_TYPE_AREA);