@cryptotaxi247 / netdata-1 / commits / 33b65ce0e

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