2 #include <CoreFoundation/CoreFoundation.h>
3 #include <IOKit/IOKitLib.h>
4 #include <IOKit/storage/IOBlockStorageDriver.h>
5 #include <IOKit/IOBSD.h>
7 #define MAXDRIVENAME 31
9 int do_macos_iokit(int update_every, usec_t dt) {
12 static int do_io = -1;
14 if (unlikely(do_io == -1)) {
15 do_io = config_get_boolean("plugin:macos:iokit", "disk i/o", 1);
20 mach_port_t master_port;
21 io_registry_entry_t drive, drive_media;
22 io_iterator_t drive_list;
23 CFDictionaryRef properties, statistics;
27 collected_number total_disk_reads = 0;
28 collected_number total_disk_writes = 0;
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;
41 collected_number duration_read_ns;
42 collected_number duration_write_ns;
43 collected_number busy_time_ns;
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;
55 /* Get ports and services for drive statistics. */
56 if (unlikely(IOMasterPort(bootstrap_port, &master_port))) {
57 error("MACOS: IOMasterPort() failed");
59 error("DISABLED: system.io");
60 /* Get the list of all drive objects. */
61 } else if (unlikely(IOServiceGetMatchingServices(master_port, IOServiceMatching("IOBlockStorageDriver"), &drive_list))) {
62 error("MACOS: IOServiceGetMatchingServices() failed");
64 error("DISABLED: system.io");
66 while ((drive = IOIteratorNext(drive_list)) != 0) {
70 bzero(&diskstat, sizeof(diskstat));
72 /* Get drive media object. */
73 status = IORegistryEntryGetChildEntry(drive, kIOServicePlane, &drive_media);
74 if (unlikely(status != KERN_SUCCESS)) {
75 IOObjectRelease(drive);
79 /* Get drive media properties. */
80 if (likely(!IORegistryEntryCreateCFProperties(drive_media, (CFMutableDictionaryRef *)&properties, kCFAllocatorDefault, 0))) {
82 if (likely(name = (CFStringRef)CFDictionaryGetValue(properties, CFSTR(kIOBSDNameKey)))) {
83 CFStringGetCString(name, diskstat.name, MAXDRIVENAME, kCFStringEncodingUTF8);
88 CFRelease(properties);
89 IOObjectRelease(drive_media);
91 /* Obtain the properties for this drive object. */
92 if (unlikely(IORegistryEntryCreateCFProperties(drive, (CFMutableDictionaryRef *)&properties, kCFAllocatorDefault, 0))) {
93 error("MACOS: IORegistryEntryCreateCFProperties() failed");
95 error("DISABLED: system.io");
97 } else if (likely(properties)) {
98 /* Obtain the statistics from the drive properties. */
99 if (likely(statistics = (CFDictionaryRef)CFDictionaryGetValue(properties, CFSTR(kIOBlockStorageDriverStatisticsKey)))) {
101 // --------------------------------------------------------------------
103 /* Get bytes read. */
104 if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey)))) {
105 CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.bytes_read);
106 total_disk_reads += diskstat.bytes_read;
109 /* Get bytes written. */
110 if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey)))) {
111 CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.bytes_write);
112 total_disk_writes += diskstat.bytes_write;
115 st = rrdset_find_bytype("disk", diskstat.name);
117 st = rrdset_create("disk", diskstat.name, NULL, diskstat.name, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA);
119 rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_INCREMENTAL);
120 rrddim_add(st, "writes", NULL, -1, 1024, RRDDIM_INCREMENTAL);
122 else rrdset_next(st);
124 prev_diskstat.bytes_read = rrddim_set(st, "reads", diskstat.bytes_read);
125 prev_diskstat.bytes_write = rrddim_set(st, "writes", diskstat.bytes_write);
128 // --------------------------------------------------------------------
130 /* Get number of reads. */
131 if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsReadsKey)))) {
132 CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.reads);
135 /* Get number of writes. */
136 if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsWritesKey)))) {
137 CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.writes);
140 st = rrdset_find_bytype("disk_ops", diskstat.name);
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);
145 rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
146 rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
148 else rrdset_next(st);
150 prev_diskstat.operations_read = rrddim_set(st, "reads", diskstat.reads);
151 prev_diskstat.operations_write = rrddim_set(st, "writes", diskstat.writes);
154 // --------------------------------------------------------------------
156 /* Get reads time. */
157 if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsTotalReadTimeKey)))) {
158 CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.time_read);
161 /* Get writes time. */
162 if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsTotalWriteTimeKey)))) {
163 CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.time_write);
166 st = rrdset_find_bytype("disk_util", diskstat.name);
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);
171 rrddim_add(st, "utilization", NULL, 1, 10000000, RRDDIM_INCREMENTAL);
173 else rrdset_next(st);
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);
179 // --------------------------------------------------------------------
181 /* Get reads latency. */
182 if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsLatentReadTimeKey)))) {
183 CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.latency_read);
186 /* Get writes latency. */
187 if (likely(number = (CFNumberRef)CFDictionaryGetValue(statistics, CFSTR(kIOBlockStorageDriverStatisticsLatentWriteTimeKey)))) {
188 CFNumberGetValue(number, kCFNumberSInt64Type, &diskstat.latency_write);
191 st = rrdset_find_bytype("disk_iotime", diskstat.name);
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);
196 rrddim_add(st, "reads", NULL, 1, 1000000, RRDDIM_INCREMENTAL);
197 rrddim_add(st, "writes", NULL, -1, 1000000, RRDDIM_INCREMENTAL);
199 else rrdset_next(st);
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);
207 // --------------------------------------------------------------------
208 // calculate differential charts
209 // only if this is not the first time we run
213 // --------------------------------------------------------------------
215 st = rrdset_find_bytype("disk_await", diskstat.name);
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);
220 rrddim_add(st, "reads", NULL, 1, 1000000, RRDDIM_ABSOLUTE);
221 rrddim_add(st, "writes", NULL, -1, 1000000, RRDDIM_ABSOLUTE);
223 else rrdset_next(st);
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);
231 // --------------------------------------------------------------------
233 st = rrdset_find_bytype("disk_avgsz", diskstat.name);
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);
238 rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_ABSOLUTE);
239 rrddim_add(st, "writes", NULL, -1, 1024, RRDDIM_ABSOLUTE);
241 else rrdset_next(st);
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);
249 // --------------------------------------------------------------------
251 st = rrdset_find_bytype("disk_svctm", diskstat.name);
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);
256 rrddim_add(st, "svctm", NULL, 1, 1000000, RRDDIM_ABSOLUTE);
258 else rrdset_next(st);
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);
267 CFRelease(properties);
271 IOObjectRelease(drive);
273 IOIteratorReset(drive_list);
276 IOObjectRelease(drive_list);
280 st = rrdset_find_bytype("system", "io");
282 st = rrdset_create("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150, update_every, RRDSET_TYPE_AREA);
283 rrddim_add(st, "in", NULL, 1, 1024, RRDDIM_INCREMENTAL);
284 rrddim_add(st, "out", NULL, -1, 1024, RRDDIM_INCREMENTAL);
286 else rrdset_next(st);
288 rrddim_set(st, "in", total_disk_reads);
289 rrddim_set(st, "out", total_disk_writes);