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