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