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