]> arthur.barton.de Git - netdata.git/blob - src/freebsd_sysctl.c
Add IPC semaphores stats to FreeBSD plugin
[netdata.git] / src / freebsd_sysctl.c
1 #include "common.h"
2
3 // NEEDED BY: struct vmtotal, struct vmmeter
4 #include <sys/vmmeter.h>
5 // NEEDED BY: struct devstat
6 #include <sys/devicestat.h>
7 // NEEDED BY: struct xswdev
8 #include <vm/vm_param.h>
9 // NEEDED BY: struct ipc_sem_data
10 #define _KERNEL
11 #include <sys/sem.h>
12 #undef _KERNEL
13 // NEEDED BY: do_disk_io
14 #define RRD_TYPE_DISK "disk"
15
16 // FreeBSD calculates load averages once every 5 seconds
17 #define MIN_LOADAVG_UPDATE_EVERY 5
18
19 int do_freebsd_sysctl(int update_every, usec_t dt) {
20     (void)dt;
21
22     static int do_cpu = -1, do_cpu_cores = -1, do_interrupts = -1, do_context = -1, do_forks = -1, do_processes = -1,
23         do_loadavg = -1, do_all_processes = -1, do_disk_io = -1, do_swap = -1, do_ram = -1, do_swapio = -1,
24         do_pgfaults = -1, do_committed = -1, do_ipc_semaphores = -1;
25
26     if (unlikely(do_cpu == -1)) {
27         do_cpu                  = config_get_boolean("plugin:freebsd:sysctl", "cpu utilization", 1);
28         do_cpu_cores            = config_get_boolean("plugin:freebsd:sysctl", "per cpu core utilization", 1);
29         do_interrupts           = config_get_boolean("plugin:freebsd:sysctl", "cpu interrupts", 1);
30         do_context              = config_get_boolean("plugin:freebsd:sysctl", "context switches", 1);
31         do_forks                = config_get_boolean("plugin:freebsd:sysctl", "processes started", 1);
32         do_processes            = config_get_boolean("plugin:freebsd:sysctl", "processes running", 1);
33         do_loadavg              = config_get_boolean("plugin:freebsd:sysctl", "enable load average", 1);
34         do_all_processes        = config_get_boolean("plugin:freebsd:sysctl", "enable total processes", 1);
35         do_disk_io              = config_get_boolean("plugin:freebsd:sysctl", "stats for all disks", 1);
36         do_swap                 = config_get_boolean("plugin:freebsd:sysctl", "system swap", 1);
37         do_ram                  = config_get_boolean("plugin:freebsd:sysctl", "system ram", 1);
38         do_swapio               = config_get_boolean("plugin:freebsd:sysctl", "swap i/o", 1);
39         do_pgfaults             = config_get_boolean("plugin:freebsd:sysctl", "memory page faults", 1);
40         do_committed            = config_get_boolean("plugin:freebsd:sysctl", "committed memory", 1);
41         do_ipc_semaphores       = config_get_boolean("plugin:freebsd:sysctl", "ipc semaphores", 1);
42     }
43
44     RRDSET *st;
45
46     int system_pagesize = getpagesize(); // wouldn't it be better to get value directly from hw.pagesize?
47     int i;
48
49 // NEEDED BY: do_loadavg
50     static usec_t last_loadavg_usec = 0;
51     struct loadavg sysload;
52
53 // NEEDED BY: do_cpu, do_cpu_cores
54     long cp_time[CPUSTATES];
55
56 // NEEDED BY: do_cpu_cores
57     int ncpus;
58     static long *pcpu_cp_time = NULL;
59     char cpuid[8]; // no more than 4 digits expected
60
61 // NEEDED BY: do_all_processes, do_processes
62     struct vmtotal vmtotal_data;
63
64 // NEEDED BY: do_context, do_forks
65     u_int u_int_data;
66
67 // NEEDED BY: do_interrupts
68     size_t intrcnt_size;
69     unsigned long nintr = 0;
70     static unsigned long *intrcnt = NULL;
71     unsigned long long totalintr = 0;
72
73 // NEEDED BY: do_disk_io
74     #define BINTIME_SCALE 5.42101086242752217003726400434970855712890625e-17 // this is 1000/2^64
75     int numdevs;
76     static void *devstat_data = NULL;
77     struct devstat *dstat;
78     struct cur_dstat {
79         collected_number duration_read_ms;
80         collected_number duration_write_ms;
81         collected_number busy_time_ms;
82     } cur_dstat;
83     struct prev_dstat {
84         collected_number bytes_read;
85         collected_number bytes_write;
86         collected_number operations_read;
87         collected_number operations_write;
88         collected_number duration_read_ms;
89         collected_number duration_write_ms;
90         collected_number busy_time_ms;
91     } prev_dstat;
92
93     // NEEDED BY: do_swap
94     size_t mibsize, size;
95     int mib[3]; // CTL_MAXNAME = 24 maximum mib components (sysctl.h)
96     struct xswdev xsw;
97     struct total_xsw {
98         collected_number bytes_used;
99         collected_number bytes_total;
100     } total_xsw = {0, 0};
101
102     // NEEDED BY: do_swapio, do_ram
103     struct vmmeter vmmeter_data;
104
105     // NEEDED BY: do_ram
106     int vfs_bufspace_count;
107
108     // NEEDED BY: do_ipc_semaphores
109     struct ipc_sem {
110         int semmni;
111         collected_number sets;
112         collected_number semaphores;
113     } ipc_sem = {0, 0, 0};
114     static struct semid_kernel *ipc_sem_data = NULL;
115
116
117     // --------------------------------------------------------------------
118
119     if (last_loadavg_usec <= dt) {
120         if (likely(do_loadavg)) {
121             if (unlikely(GETSYSCTL("vm.loadavg", sysload))) {
122                 do_loadavg = 0;
123                 error("DISABLED: system.load");
124             } else {
125
126                 st = rrdset_find_bytype("system", "load");
127                 if (unlikely(!st)) {
128                     st = rrdset_create("system", "load", NULL, "load", NULL, "System Load Average", "load", 100, (update_every < MIN_LOADAVG_UPDATE_EVERY) ? MIN_LOADAVG_UPDATE_EVERY : update_every, RRDSET_TYPE_LINE);
129                     rrddim_add(st, "load1", NULL, 1, 1000, RRDDIM_ABSOLUTE);
130                     rrddim_add(st, "load5", NULL, 1, 1000, RRDDIM_ABSOLUTE);
131                     rrddim_add(st, "load15", NULL, 1, 1000, RRDDIM_ABSOLUTE);
132                 }
133                 else rrdset_next(st);
134
135                 rrddim_set(st, "load1", (collected_number) ((double)sysload.ldavg[0] / sysload.fscale * 1000));
136                 rrddim_set(st, "load5", (collected_number) ((double)sysload.ldavg[1] / sysload.fscale * 1000));
137                 rrddim_set(st, "load15", (collected_number) ((double)sysload.ldavg[2] / sysload.fscale * 1000));
138                 rrdset_done(st);
139             }
140         }
141
142         last_loadavg_usec = st->update_every * USEC_PER_SEC;
143     }
144     else last_loadavg_usec -= dt;
145
146     // --------------------------------------------------------------------
147
148     if (likely(do_all_processes | do_processes | do_committed)) {
149         if (unlikely(GETSYSCTL("vm.vmtotal", vmtotal_data))) {
150             do_all_processes = 0;
151             error("DISABLED: system.active_processes");
152             do_processes = 0;
153             error("DISABLED: system.processes");
154             do_committed = 0;
155             error("DISABLED: mem.committed");
156         } else {
157             if (likely(do_all_processes)) {
158
159                 st = rrdset_find_bytype("system", "active_processes");
160                 if (unlikely(!st)) {
161                     st = rrdset_create("system", "active_processes", NULL, "processes", NULL, "System Active Processes", "processes", 750, update_every, RRDSET_TYPE_LINE);
162                     rrddim_add(st, "active", NULL, 1, 1, RRDDIM_ABSOLUTE);
163                 }
164                 else rrdset_next(st);
165
166                 rrddim_set(st, "active", (vmtotal_data.t_rq + vmtotal_data.t_dw + vmtotal_data.t_pw + vmtotal_data.t_sl + vmtotal_data.t_sw));
167                 rrdset_done(st);
168             }
169
170             // --------------------------------------------------------------------
171
172             if (likely(do_processes)) {
173
174                 st = rrdset_find_bytype("system", "processes");
175                 if (unlikely(!st)) {
176                     st = rrdset_create("system", "processes", NULL, "processes", NULL, "System Processes", "processes", 600, update_every, RRDSET_TYPE_LINE);
177
178                     rrddim_add(st, "running", NULL, 1, 1, RRDDIM_ABSOLUTE);
179                     rrddim_add(st, "blocked", NULL, -1, 1, RRDDIM_ABSOLUTE);
180                 }
181                 else rrdset_next(st);
182
183                 rrddim_set(st, "running", vmtotal_data.t_rq);
184                 rrddim_set(st, "blocked", (vmtotal_data.t_dw + vmtotal_data.t_pw));
185                 rrdset_done(st);
186             }
187
188             // --------------------------------------------------------------------
189
190             if (likely(do_committed)) {
191                 st = rrdset_find("mem.committed");
192                 if (unlikely(!st)) {
193                     st = rrdset_create("mem", "committed", NULL, "system", NULL, "Committed (Allocated) Memory", "MB", 5000, update_every, RRDSET_TYPE_AREA);
194                     st->isdetail = 1;
195
196                     rrddim_add(st, "Committed_AS", NULL, system_pagesize, 1024, RRDDIM_ABSOLUTE);
197                 }
198                 else rrdset_next(st);
199
200                 rrddim_set(st, "Committed_AS", vmtotal_data.t_rm);
201                 rrdset_done(st);
202             }
203         }
204     }
205
206     // --------------------------------------------------------------------
207
208     if (likely(do_cpu)) {
209         if (unlikely(CPUSTATES != 5)) {
210             error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
211             do_cpu = 0;
212             error("DISABLED: system.cpu");
213         } else {
214             if (unlikely(GETSYSCTL("kern.cp_time", cp_time))) {
215                 do_cpu = 0;
216                 error("DISABLED: system.cpu");
217             } else {
218
219                 st = rrdset_find_bytype("system", "cpu");
220                 if (unlikely(!st)) {
221                     st = rrdset_create("system", "cpu", NULL, "cpu", "system.cpu", "Total CPU utilization", "percentage", 100, update_every, RRDSET_TYPE_STACKED);
222
223                     rrddim_add(st, "user", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
224                     rrddim_add(st, "nice", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
225                     rrddim_add(st, "system", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
226                     rrddim_add(st, "interrupt", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
227                     rrddim_add(st, "idle", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
228                     rrddim_hide(st, "idle");
229                 }
230                 else rrdset_next(st);
231
232                 rrddim_set(st, "user", cp_time[0]);
233                 rrddim_set(st, "nice", cp_time[1]);
234                 rrddim_set(st, "system", cp_time[2]);
235                 rrddim_set(st, "interrupt", cp_time[3]);
236                 rrddim_set(st, "idle", cp_time[4]);
237                 rrdset_done(st);
238             }
239         }
240     }
241
242     // --------------------------------------------------------------------
243
244     if (likely(do_cpu_cores)) {
245         if (unlikely(CPUSTATES != 5)) {
246             error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
247             do_cpu_cores = 0;
248             error("DISABLED: cpu.cpuXX");
249         } else {
250             if (unlikely(GETSYSCTL("kern.smp.cpus", ncpus))) {
251                 do_cpu_cores = 0;
252                 error("DISABLED: cpu.cpuXX");
253             } else {
254                 pcpu_cp_time = reallocz(pcpu_cp_time, sizeof(cp_time) * ncpus);
255
256                 for (i = 0; i < ncpus; i++) {
257                     if (unlikely(getsysctl("kern.cp_times", pcpu_cp_time, sizeof(cp_time) * ncpus))) {
258                         do_cpu_cores = 0;
259                         error("DISABLED: cpu.cpuXX");
260                         break;
261                     }
262                     if (unlikely(ncpus > 9999)) {
263                         error("FREEBSD: There are more than 4 digits in cpu cores number");
264                         do_cpu_cores = 0;
265                         error("DISABLED: cpu.cpuXX");
266                         break;
267                     }
268                     snprintfz(cpuid, 8, "cpu%d", i);
269
270                     st = rrdset_find_bytype("cpu", cpuid);
271                     if (unlikely(!st)) {
272                         st = rrdset_create("cpu", cpuid, NULL, "utilization", "cpu.cpu", "Core utilization", "percentage", 1000, update_every, RRDSET_TYPE_STACKED);
273
274                         rrddim_add(st, "user", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
275                         rrddim_add(st, "nice", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
276                         rrddim_add(st, "system", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
277                         rrddim_add(st, "interrupt", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
278                         rrddim_add(st, "idle", NULL, 1, 1, RRDDIM_PCENT_OVER_DIFF_TOTAL);
279                         rrddim_hide(st, "idle");
280                     }
281                     else rrdset_next(st);
282
283                     rrddim_set(st, "user", pcpu_cp_time[i * 5 + 0]);
284                     rrddim_set(st, "nice", pcpu_cp_time[i * 5 + 1]);
285                     rrddim_set(st, "system", pcpu_cp_time[i * 5 + 2]);
286                     rrddim_set(st, "interrupt", pcpu_cp_time[i * 5 + 3]);
287                     rrddim_set(st, "idle", pcpu_cp_time[i * 5 + 4]);
288                     rrdset_done(st);
289                 }
290             }
291         }
292     }
293
294     // --------------------------------------------------------------------
295
296     if (likely(do_interrupts)) {
297         if (unlikely(sysctlbyname("hw.intrcnt", NULL, &intrcnt_size, NULL, 0) == -1)) {
298             error("FREEBSD: sysctl(hw.intrcnt...) failed: %s", strerror(errno));
299             do_interrupts = 0;
300             error("DISABLED: system.intr");
301         } else {
302             nintr = intrcnt_size / sizeof(u_long);
303             intrcnt = reallocz(intrcnt, nintr * sizeof(u_long));
304             if (unlikely(getsysctl("hw.intrcnt", intrcnt, nintr * sizeof(u_long)))){
305                 do_interrupts = 0;
306                 error("DISABLED: system.intr");
307             } else {
308                 for (i = 0; i < nintr; i++)
309                     totalintr += intrcnt[i];
310
311                 st = rrdset_find_bytype("system", "intr");
312                 if (unlikely(!st)) {
313                     st = rrdset_create("system", "intr", NULL, "interrupts", NULL, "Total Device Interrupts", "interrupts/s", 900, update_every, RRDSET_TYPE_LINE);
314                     st->isdetail = 1;
315
316                     rrddim_add(st, "interrupts", NULL, 1, 1, RRDDIM_INCREMENTAL);
317                 }
318                 else rrdset_next(st);
319
320                 rrddim_set(st, "interrupts", totalintr);
321                 rrdset_done(st);
322             }
323         }
324     }
325
326     // --------------------------------------------------------------------
327
328     if (likely(do_context)) {
329         if (unlikely(GETSYSCTL("vm.stats.sys.v_swtch", u_int_data))) {
330             do_context = 0;
331             error("DISABLED: system.ctxt");
332         } else {
333
334             st = rrdset_find_bytype("system", "ctxt");
335             if (unlikely(!st)) {
336                 st = rrdset_create("system", "ctxt", NULL, "processes", NULL, "CPU Context Switches", "context switches/s", 800, update_every, RRDSET_TYPE_LINE);
337
338                 rrddim_add(st, "switches", NULL, 1, 1, RRDDIM_INCREMENTAL);
339             }
340             else rrdset_next(st);
341
342             rrddim_set(st, "switches", u_int_data);
343             rrdset_done(st);
344         }
345     }
346
347     // --------------------------------------------------------------------
348
349     if (likely(do_forks)) {
350         if (unlikely(GETSYSCTL("vm.stats.vm.v_forks", u_int_data))) {
351             do_forks = 0;
352             error("DISABLED: system.forks");
353         } else {
354
355             st = rrdset_find_bytype("system", "forks");
356             if (unlikely(!st)) {
357                 st = rrdset_create("system", "forks", NULL, "processes", NULL, "Started Processes", "processes/s", 700, update_every, RRDSET_TYPE_LINE);
358                 st->isdetail = 1;
359
360                 rrddim_add(st, "started", NULL, 1, 1, RRDDIM_INCREMENTAL);
361             }
362             else rrdset_next(st);
363
364             rrddim_set(st, "started", u_int_data);
365             rrdset_done(st);
366         }
367     }
368
369     // --------------------------------------------------------------------
370
371     if (likely(do_disk_io)) {
372         if (unlikely(GETSYSCTL("kern.devstat.numdevs", numdevs))) {
373             do_disk_io = 0;
374             error("DISABLED: disk.io");
375         } else {
376             devstat_data = reallocz(devstat_data, sizeof(long) + sizeof(struct devstat) * numdevs); // there is generation number before devstat structures
377             if (unlikely(getsysctl("kern.devstat.all", devstat_data, sizeof(long) + sizeof(struct devstat) * numdevs))) {
378                 do_disk_io = 0;
379                 error("DISABLED: disk.io");
380             } else {
381                 dstat = devstat_data + sizeof(long); // skip generation number
382                 collected_number total_disk_reads = 0;
383                 collected_number total_disk_writes = 0;
384
385                 for (i = 0; i < numdevs; i++) {
386                     if ((dstat[i].device_type == (DEVSTAT_TYPE_IF_SCSI | DEVSTAT_TYPE_DIRECT)) || (dstat[i].device_type == (DEVSTAT_TYPE_IF_IDE | DEVSTAT_TYPE_DIRECT))) {
387
388                         // --------------------------------------------------------------------
389
390                         st = rrdset_find_bytype(RRD_TYPE_DISK, dstat[i].device_name);
391                         if (unlikely(!st)) {
392                             st = rrdset_create(RRD_TYPE_DISK, dstat[i].device_name, NULL, dstat[i].device_name, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA);
393
394                             rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_INCREMENTAL);
395                             rrddim_add(st, "writes", NULL, -1, 1024, RRDDIM_INCREMENTAL);
396                         }
397                         else rrdset_next(st);
398
399                         total_disk_reads += dstat[i].bytes[DEVSTAT_READ];
400                         total_disk_writes += dstat[i].bytes[DEVSTAT_WRITE];
401                         prev_dstat.bytes_read = rrddim_set(st, "reads", dstat[i].bytes[DEVSTAT_READ]);
402                         prev_dstat.bytes_write = rrddim_set(st, "writes", dstat[i].bytes[DEVSTAT_WRITE]);
403                         rrdset_done(st);
404
405                         // --------------------------------------------------------------------
406
407                         st = rrdset_find_bytype("disk_ops", dstat[i].device_name);
408                         if (unlikely(!st)) {
409                             st = rrdset_create("disk_ops", dstat[i].device_name, NULL, dstat[i].device_name, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE);
410                             st->isdetail = 1;
411
412                             rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
413                             rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
414                         }
415                         else rrdset_next(st);
416
417                         prev_dstat.operations_read = rrddim_set(st, "reads", dstat[i].operations[DEVSTAT_READ]);
418                         prev_dstat.operations_write = rrddim_set(st, "writes", dstat[i].operations[DEVSTAT_WRITE]);
419                         rrdset_done(st);
420
421                         // --------------------------------------------------------------------
422
423                         st = rrdset_find_bytype("disk_qops", dstat[i].device_name);
424                         if (unlikely(!st)) {
425                             st = rrdset_create("disk_qops", dstat[i].device_name, NULL, dstat[i].device_name, "disk.qops", "Disk Current I/O Operations", "operations", 2002, update_every, RRDSET_TYPE_LINE);
426                             st->isdetail = 1;
427
428                             rrddim_add(st, "operations", NULL, 1, 1, RRDDIM_ABSOLUTE);
429                         }
430                         else rrdset_next(st);
431
432                         rrddim_set(st, "operations", dstat[i].start_count - dstat[i].end_count);
433                         rrdset_done(st);
434
435                         // --------------------------------------------------------------------
436
437                         st = rrdset_find_bytype("disk_util", dstat[i].device_name);
438                         if (unlikely(!st)) {
439                             st = rrdset_create("disk_util", dstat[i].device_name, NULL, dstat[i].device_name, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA);
440                             st->isdetail = 1;
441
442                             rrddim_add(st, "utilization", NULL, 1, 10, RRDDIM_INCREMENTAL);
443                         }
444                         else rrdset_next(st);
445
446                         cur_dstat.busy_time_ms = dstat[i].busy_time.sec * 1000 + dstat[i].busy_time.frac * BINTIME_SCALE;
447                         prev_dstat.busy_time_ms = rrddim_set(st, "utilization", cur_dstat.busy_time_ms);
448                         rrdset_done(st);
449
450                         // --------------------------------------------------------------------
451
452                         st = rrdset_find_bytype("disk_iotime", dstat[i].device_name);
453                         if (unlikely(!st)) {
454                             st = rrdset_create("disk_iotime", dstat[i].device_name, NULL, dstat[i].device_name, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE);
455                             st->isdetail = 1;
456
457                             rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_INCREMENTAL);
458                             rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_INCREMENTAL);
459                         }
460                         else rrdset_next(st);
461
462                         cur_dstat.duration_read_ms = dstat[i].duration[DEVSTAT_READ].sec * 1000 + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
463                         cur_dstat.duration_write_ms = dstat[i].duration[DEVSTAT_WRITE].sec * 1000 + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
464                         prev_dstat.duration_read_ms = rrddim_set(st, "reads", cur_dstat.duration_read_ms);
465                         prev_dstat.duration_write_ms = rrddim_set(st, "writes", cur_dstat.duration_write_ms);
466                         rrdset_done(st);
467
468                         // --------------------------------------------------------------------
469                         // calculate differential charts
470                         // only if this is not the first time we run
471
472                         if (likely(dt)) {
473
474                             // --------------------------------------------------------------------
475
476                             st = rrdset_find_bytype("disk_await", dstat[i].device_name);
477                             if (unlikely(!st)) {
478                                 st = rrdset_create("disk_await", dstat[i].device_name, NULL, dstat[i].device_name, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE);
479                                 st->isdetail = 1;
480
481                                 rrddim_add(st, "reads", NULL, 1, 1, RRDDIM_ABSOLUTE);
482                                 rrddim_add(st, "writes", NULL, -1, 1, RRDDIM_ABSOLUTE);
483                             }
484                             else rrdset_next(st);
485
486                             rrddim_set(st, "reads", (dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) ? 
487                                 (cur_dstat.duration_read_ms - prev_dstat.duration_read_ms) / (dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) : 0);
488                             rrddim_set(st, "writes", (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write) ?
489                                 (cur_dstat.duration_write_ms - prev_dstat.duration_write_ms) / (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write) : 0);
490                             rrdset_done(st);
491
492                             // --------------------------------------------------------------------
493
494                             st = rrdset_find_bytype("disk_avgsz", dstat[i].device_name);
495                             if (unlikely(!st)) {
496                                 st = rrdset_create("disk_avgsz", dstat[i].device_name, NULL, dstat[i].device_name, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA);
497                                 st->isdetail = 1;
498
499                                 rrddim_add(st, "reads", NULL, 1, 1024, RRDDIM_ABSOLUTE);
500                                 rrddim_add(st, "writes", NULL, -1, 1024, RRDDIM_ABSOLUTE);
501                             }
502                             else rrdset_next(st);
503
504                             rrddim_set(st, "reads", (dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) ?
505                                 (dstat[i].bytes[DEVSTAT_READ] - prev_dstat.bytes_read) / (dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) : 0);
506                             rrddim_set(st, "writes", (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write) ?
507                                 (dstat[i].bytes[DEVSTAT_WRITE] - prev_dstat.bytes_write) / (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write) : 0);
508                             rrdset_done(st);
509
510                             // --------------------------------------------------------------------
511
512                             st = rrdset_find_bytype("disk_svctm", dstat[i].device_name);
513                             if (unlikely(!st)) {
514                                 st = rrdset_create("disk_svctm", dstat[i].device_name, NULL, dstat[i].device_name, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE);
515                                 st->isdetail = 1;
516
517                                 rrddim_add(st, "svctm", NULL, 1, 1, RRDDIM_ABSOLUTE);
518                             }
519                             else rrdset_next(st);
520
521                             rrddim_set(st, "svctm", ((dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) + (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write)) ?
522                                 (cur_dstat.busy_time_ms - prev_dstat.busy_time_ms) / ((dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) + (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write)) : 0);
523                             rrdset_done(st);
524                         }
525                     }
526
527                     // --------------------------------------------------------------------
528
529                     st = rrdset_find_bytype("system", "io");
530                     if (unlikely(!st)) {
531                         st = rrdset_create("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150, update_every, RRDSET_TYPE_AREA);
532                         rrddim_add(st, "in",  NULL,  1, 1024, RRDDIM_INCREMENTAL);
533                         rrddim_add(st, "out", NULL, -1, 1024, RRDDIM_INCREMENTAL);
534                     }
535                     else rrdset_next(st);
536
537                     rrddim_set(st, "in", total_disk_reads);
538                     rrddim_set(st, "out", total_disk_writes);
539                     rrdset_done(st);
540                 }
541             }
542         }
543     }
544
545     // --------------------------------------------------------------------
546
547
548     if (likely(do_swap)) {
549         mibsize = sizeof mib / sizeof mib[0];
550         if (unlikely(sysctlnametomib("vm.swap_info", mib, &mibsize) == -1)) {
551             error("FREEBSD: sysctl(%s...) failed: %s", "vm.swap_info", strerror(errno));
552             do_swap = 0;
553             error("DISABLED: disk.io");
554         } else {
555             for (i = 0; ; i++) {
556                 mib[mibsize] = i;
557                 size = sizeof(xsw);
558                 if (unlikely(sysctl(mib, mibsize + 1, &xsw, &size, NULL, 0) == -1 )) {
559                     if (unlikely(errno != ENOENT)) {
560                         error("FREEBSD: sysctl(%s...) failed: %s", "vm.swap_info", strerror(errno));
561                         do_swap = 0;
562                         error("DISABLED: disk.io");
563                     } else {
564                         if (unlikely(size != sizeof(xsw))) {
565                             error("FREEBSD: sysctl(%s...) expected %lu, got %lu", "vm.swap_info", (unsigned long)sizeof(xsw), (unsigned long)size);
566                             do_swap = 0;
567                             error("DISABLED: disk.io");
568                         } else break;
569                     }
570                 }
571                 total_xsw.bytes_used += xsw.xsw_used * system_pagesize;
572                 total_xsw.bytes_total += xsw.xsw_nblks * system_pagesize;
573             }
574
575             if (likely(do_swap)) {
576                 st = rrdset_find("system.swap");
577                 if (unlikely(!st)) {
578                     st = rrdset_create("system", "swap", NULL, "swap", NULL, "System Swap", "MB", 201, update_every, RRDSET_TYPE_STACKED);
579                     st->isdetail = 1;
580
581                     rrddim_add(st, "free",    NULL, 1, 1048576, RRDDIM_ABSOLUTE);
582                     rrddim_add(st, "used",    NULL, 1, 1048576, RRDDIM_ABSOLUTE);
583                 }
584                 else rrdset_next(st);
585
586                 rrddim_set(st, "used", total_xsw.bytes_used);
587                 rrddim_set(st, "free", total_xsw.bytes_total - total_xsw.bytes_used);
588                 rrdset_done(st);
589             }
590         }
591     }
592
593     // --------------------------------------------------------------------
594
595     if (likely(do_ram)) {
596         if (unlikely(GETSYSCTL("vm.stats.vm.v_active_count",    vmmeter_data.v_active_count) ||
597                      GETSYSCTL("vm.stats.vm.v_inactive_count",  vmmeter_data.v_inactive_count) ||
598                      GETSYSCTL("vm.stats.vm.v_wire_count",      vmmeter_data.v_wire_count) ||
599                      GETSYSCTL("vm.stats.vm.v_cache_count",     vmmeter_data.v_cache_count) ||
600                      GETSYSCTL("vfs.bufspace",                  vfs_bufspace_count) ||
601                      GETSYSCTL("vm.stats.vm.v_free_count",      vmmeter_data.v_free_count))) {
602             do_swapio = 0;
603             error("DISABLED: system.swapio");
604         } else {
605             st = rrdset_find("system.ram");
606             if (unlikely(!st)) {
607                 st = rrdset_create("system", "ram", NULL, "ram", NULL, "System RAM", "MB", 200, update_every, RRDSET_TYPE_STACKED);
608
609                 rrddim_add(st, "active",    NULL, system_pagesize, 1024, RRDDIM_ABSOLUTE);
610                 rrddim_add(st, "inactive",  NULL, system_pagesize, 1024, RRDDIM_ABSOLUTE);
611                 rrddim_add(st, "wired",     NULL, system_pagesize, 1024, RRDDIM_ABSOLUTE);
612                 rrddim_add(st, "cache",     NULL, system_pagesize, 1024, RRDDIM_ABSOLUTE);
613                 rrddim_add(st, "buffers",   NULL, 1, 1024, RRDDIM_ABSOLUTE);
614                 rrddim_add(st, "free",      NULL, system_pagesize, 1024, RRDDIM_ABSOLUTE);
615             }
616             else rrdset_next(st);
617
618             rrddim_set(st, "active",    vmmeter_data.v_active_count);
619             rrddim_set(st, "inactive",  vmmeter_data.v_inactive_count);
620             rrddim_set(st, "wired",     vmmeter_data.v_wire_count);
621             rrddim_set(st, "cache",     vmmeter_data.v_cache_count);
622             rrddim_set(st, "buffers",   vfs_bufspace_count);
623             rrddim_set(st, "free",      vmmeter_data.v_free_count);
624             rrdset_done(st);
625         }
626     }
627
628     // --------------------------------------------------------------------
629
630     if (likely(do_swapio)) {
631         if (unlikely(GETSYSCTL("vm.stats.vm.v_swappgsin", vmmeter_data.v_swappgsin) || GETSYSCTL("vm.stats.vm.v_vnodepgsout", vmmeter_data.v_swappgsout))) {
632             do_swapio = 0;
633             error("DISABLED: system.swapio");
634         } else {
635             st = rrdset_find("system.swapio");
636             if (unlikely(!st)) {
637                 st = rrdset_create("system", "swapio", NULL, "swap", NULL, "Swap I/O", "kilobytes/s", 250, update_every, RRDSET_TYPE_AREA);
638
639                 rrddim_add(st, "in",  NULL, system_pagesize, 1024, RRDDIM_INCREMENTAL);
640                 rrddim_add(st, "out", NULL, -system_pagesize, 1024, RRDDIM_INCREMENTAL);
641             }
642             else rrdset_next(st);
643
644             rrddim_set(st, "in", vmmeter_data.v_swappgsin);
645             rrddim_set(st, "out", vmmeter_data.v_swappgsout);
646             rrdset_done(st);
647         }
648     }
649
650     // --------------------------------------------------------------------
651
652     if (likely(do_pgfaults)) {
653         if (unlikely(GETSYSCTL("vm.stats.vm.v_vm_faults",   vmmeter_data.v_vm_faults) ||
654                      GETSYSCTL("vm.stats.vm.v_io_faults",   vmmeter_data.v_io_faults) ||
655                      GETSYSCTL("vm.stats.vm.v_cow_faults",  vmmeter_data.v_cow_faults) ||
656                      GETSYSCTL("vm.stats.vm.v_cow_optim",   vmmeter_data.v_cow_optim) ||
657                      GETSYSCTL("vm.stats.vm.v_intrans",     vmmeter_data.v_intrans))) {
658             do_pgfaults = 0;
659             error("DISABLED: mem.pgfaults");
660         } else {
661             st = rrdset_find("mem.pgfaults");
662             if (unlikely(!st)) {
663                 st = rrdset_create("mem", "pgfaults", NULL, "system", NULL, "Memory Page Faults", "page faults/s", 500, update_every, RRDSET_TYPE_LINE);
664                 st->isdetail = 1;
665
666                 rrddim_add(st, "memory", NULL, 1, 1, RRDDIM_INCREMENTAL);
667                 rrddim_add(st, "io_requiring", NULL, 1, 1, RRDDIM_INCREMENTAL);
668                 rrddim_add(st, "cow", NULL, 1, 1, RRDDIM_INCREMENTAL);
669                 rrddim_add(st, "cow_optimized", NULL, 1, 1, RRDDIM_INCREMENTAL);
670                 rrddim_add(st, "in_transit", NULL, 1, 1, RRDDIM_INCREMENTAL);
671             }
672             else rrdset_next(st);
673
674             rrddim_set(st, "memory", vmmeter_data.v_vm_faults);
675             rrddim_set(st, "io_requiring", vmmeter_data.v_io_faults);
676             rrddim_set(st, "cow", vmmeter_data.v_cow_faults);
677             rrddim_set(st, "cow_optimized", vmmeter_data.v_cow_optim);
678             rrddim_set(st, "in_transit", vmmeter_data.v_intrans);
679             rrdset_done(st);
680         }
681     }
682
683     // --------------------------------------------------------------------
684
685     if (likely(do_ipc_semaphores)) {
686         if (unlikely(GETSYSCTL("kern.ipc.semmni", ipc_sem.semmni))) {
687             do_ipc_semaphores = 0;
688             error("DISABLED: system.ipc_semaphores");
689             error("DISABLED: system.ipc_semaphore_arrays");
690         } else {
691             ipc_sem_data = reallocz(ipc_sem_data, sizeof(struct semid_kernel) * ipc_sem.semmni);
692             if (unlikely(getsysctl("kern.ipc.sema", ipc_sem_data, sizeof(struct semid_kernel) * ipc_sem.semmni))) {
693                 do_ipc_semaphores = 0;
694                 error("DISABLED: system.ipc_semaphores");
695                 error("DISABLED: system.ipc_semaphore_arrays");;
696             } else {
697                 for (i = 0; i < ipc_sem.semmni; i++) {
698                     if (unlikely(ipc_sem_data[i].u.sem_perm.mode & SEM_ALLOC)) {
699                         ipc_sem.sets += 1;
700                         ipc_sem.semaphores += ipc_sem_data[i].u.sem_nsems;
701                     }
702                 }
703
704                 // --------------------------------------------------------------------
705
706                 st = rrdset_find("system.ipc_semaphores");
707                 if (unlikely(!st)) {
708                     st = rrdset_create("system", "ipc_semaphores", NULL, "ipc semaphores", NULL, "IPC Semaphores", "semaphores", 1000, rrd_update_every, RRDSET_TYPE_AREA);
709                     rrddim_add(st, "semaphores", NULL, 1, 1, RRDDIM_ABSOLUTE);
710                 }
711                 else rrdset_next(st);
712
713                 rrddim_set(st, "semaphores", ipc_sem.semaphores);
714                 rrdset_done(st);
715
716                 // --------------------------------------------------------------------
717
718                 st = rrdset_find("system.ipc_semaphore_arrays");
719                 if (unlikely(!st)) {
720                     st = rrdset_create("system", "ipc_semaphore_arrays", NULL, "ipc semaphores", NULL, "IPC Semaphore Arrays", "arrays", 1000, rrd_update_every, RRDSET_TYPE_AREA);
721                     rrddim_add(st, "arrays", NULL, 1, 1, RRDDIM_ABSOLUTE);
722                 }
723                 else rrdset_next(st);
724
725                 rrddim_set(st, "arrays", ipc_sem.sets);
726                 rrdset_done(st);
727             }
728         }
729     }
730
731     return 0;
732 }