Add some basic system stats - load, cpu, interrupts, processes
Vladimir Kobal committed
Dec 3, 2016 at 23:17 UTC
2ebb9ab48f89c573ce4e051c42ef08c4200f686c
6 files changed
+379
-4
src/Makefile.am
+2
@@ -62,6 +62,8 @@ netdata_SOURCES = \
62
if FREEBSD
63
netdata_SOURCES += \
64
plugin_freebsd.c plugin_freebsd.h \
65
+ freebsd_loadavg.c \
66
+ freebsd_stat.c \
67
$(NULL)
68
else
69
netdata_SOURCES += \
src/freebsd_loadavg.c
new
+78
@@ -0,0 +1,78 @@
1
+#include "common.h"
2
+#include <sys/vmmeter.h>
3
+
4
+// FreeBSD calculates this once every 5 seconds
5
+#define MIN_LOADAVG_UPDATE_EVERY 5
6
+
7
+int do_proc_loadavg(int update_every, unsigned long long dt) {
8
+ (void)dt;
9
+
10
+ static int do_loadavg = -1, do_all_processes = -1;
11
+ static unsigned long long last_loadavg_usec = 0;
12
+ static RRDSET *load_chart = NULL, *processes_chart = NULL;
13
+
14
+ if(unlikely(do_loadavg == -1)) {
15
+ do_loadavg = config_get_boolean("plugin:proc:/proc/loadavg", "enable load average", 1);
16
+ do_all_processes = config_get_boolean("plugin:proc:/proc/loadavg", "enable total processes", 1);
17
+ }
18
+
19
+ struct loadavg sysload;
20
+
21
+ if (unlikely(GETSYSCTL("vm.loadavg", sysload)))
22
+ return 1;
23
+
24
+ double load1 = (double)sysload.ldavg[0] / sysload.fscale;
25
+ double load5 = (double)sysload.ldavg[1] / sysload.fscale;
26
+ double load15 = (double)sysload.ldavg[2] / sysload.fscale;
27
+
28
+ struct vmtotal total;
29
+
30
+ if (unlikely(GETSYSCTL("vm.vmtotal", total)))
31
+ return 1;
32
+
33
+ unsigned long long active_processes = total.t_rq + total.t_dw + total.t_pw + total.t_sl + total.t_sw;
34
+
35
+ // --------------------------------------------------------------------
36
+
37
+ if(last_loadavg_usec <= dt) {
38
+ if(likely(do_loadavg)) {
39
+ if(unlikely(!load_chart)) {
40
+ load_chart = rrdset_find_byname("system.load");
41
+ if(unlikely(!load_chart)) {
42
+ load_chart = 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);
43
+ rrddim_add(load_chart, "load1", NULL, 1, 1000, RRDDIM_ABSOLUTE);
44
+ rrddim_add(load_chart, "load5", NULL, 1, 1000, RRDDIM_ABSOLUTE);
45
+ rrddim_add(load_chart, "load15", NULL, 1, 1000, RRDDIM_ABSOLUTE);
46
+ }
47
+ }
48
+ else
49
+ rrdset_next(load_chart);
50
+
51
+ rrddim_set(load_chart, "load1", (collected_number) (load1 * 1000));
52
+ rrddim_set(load_chart, "load5", (collected_number) (load5 * 1000));
53
+ rrddim_set(load_chart, "load15", (collected_number) (load15 * 1000));
54
+ rrdset_done(load_chart);
55
+ }
56
+
57
+ last_loadavg_usec = load_chart->update_every * 1000000ULL;
58
+ }
59
+ else last_loadavg_usec -= dt;
60
+
61
+ // --------------------------------------------------------------------
62
+
63
+ if(likely(do_all_processes)) {
64
+ if(unlikely(!processes_chart)) {
65
+ processes_chart = rrdset_find_byname("system.active_processes");
66
+ if(unlikely(!processes_chart)) {
67
+ processes_chart = rrdset_create("system", "active_processes", NULL, "processes", NULL, "System Active Processes", "processes", 750, update_every, RRDSET_TYPE_LINE);
68
+ rrddim_add(processes_chart, "active", NULL, 1, 1, RRDDIM_ABSOLUTE);
69
+ }
70
+ }
71
+ else rrdset_next(processes_chart);
72
+
73
+ rrddim_set(processes_chart, "active", active_processes);
74
+ rrdset_done(processes_chart);
75
+ }
76
+
77
+ return 0;
78
+}
src/freebsd_stat.c
new
+254
@@ -0,0 +1,254 @@
1
+#include "common.h"
2
+#include <sys/vmmeter.h>
3
+
4
+int do_proc_stat(int update_every, unsigned long long dt) {
5
+ (void)dt;
6
+
7
+ static int do_cpu = -1, do_cpu_cores = -1, do_interrupts = -1, do_context = -1, do_forks = -1, do_processes = -1;
8
+
9
+ if(unlikely(do_cpu == -1)) {
10
+ do_cpu = config_get_boolean("plugin:proc:/proc/stat", "cpu utilization", 1);
11
+ do_cpu_cores = config_get_boolean("plugin:proc:/proc/stat", "per cpu core utilization", 1);
12
+ do_interrupts = config_get_boolean("plugin:proc:/proc/stat", "cpu interrupts", 1);
13
+ do_context = config_get_boolean("plugin:proc:/proc/stat", "context switches", 1);
14
+ do_forks = config_get_boolean("plugin:proc:/proc/stat", "processes started", 1);
15
+ do_processes = config_get_boolean("plugin:proc:/proc/stat", "processes running", 1);
16
+ }
17
+
18
+ RRDSET *st;
19
+
20
+ char cpuid[5] = "cpu0";
21
+ unsigned long long user = 0, nice = 0, system = 0, interrupt = 0, idle = 0;
22
+ u_int vm_stat;
23
+ size_t intrcnt_size;
24
+ unsigned long nintr = 0;
25
+ unsigned long *intrcnt;
26
+ unsigned long long totalintr = 0;
27
+ unsigned long long running = 0 , blocked = 0;
28
+
29
+ long multiplier = 1;
30
+ long divisor = 1; // sysconf(_SC_CLK_TCK);
31
+
32
+ long cp_time[CPUSTATES];
33
+ long *pcpu_cp_time;
34
+
35
+ int i, ncpus;
36
+
37
+ struct vmtotal total;
38
+
39
+ if(likely(do_cpu)) {
40
+ if (unlikely(CPUSTATES != 5)) {
41
+ error("There are %d CPU states (5 was expected)", CPUSTATES);
42
+ do_cpu = 0;
43
+ error("Total CPU utilization stats was switched off");
44
+ return 0;
45
+ }
46
+ if (unlikely(GETSYSCTL("kern.cp_time", cp_time))) {
47
+ do_cpu = 0;
48
+ error("Total CPU utilization stats was switched off");
49
+ return 0;
50
+ }
51
+ user = cp_time[0];
52
+ nice = cp_time[1];
53
+ system = cp_time[2];
54
+ interrupt = cp_time[3];
55
+ idle = cp_time[4];
56
+
57
+ st = rrdset_find_bytype("system", "cpu");
58
+ if(unlikely(!st)) {
59
+ st = rrdset_create("system", "cpu", NULL, "cpu", "system.cpu", "Total CPU utilization", "percentage", 100, update_every, RRDSET_TYPE_STACKED);
60
+
61
+ rrddim_add(st, "user", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
62
+ rrddim_add(st, "system", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
63
+ rrddim_add(st, "interrupt", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
64
+ rrddim_add(st, "nice", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
65
+ rrddim_add(st, "idle", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
66
+ rrddim_hide(st, "idle");
67
+ }
68
+ else rrdset_next(st);
69
+
70
+ rrddim_set(st, "user", user);
71
+ rrddim_set(st, "system", system);
72
+ rrddim_set(st, "interrupt", interrupt);
73
+ rrddim_set(st, "nice", nice);
74
+ rrddim_set(st, "idle", idle);
75
+ rrdset_done(st);
76
+ }
77
+
78
+ // --------------------------------------------------------------------
79
+
80
+ if(likely(do_cpu_cores)) {
81
+ if (unlikely(CPUSTATES != 5)) {
82
+ error("There are %d CPU states (5 was expected)", CPUSTATES);
83
+ do_cpu_cores = 0;
84
+ error("CPU cores utilization stats was switched off");
85
+ return 0;
86
+ }
87
+ if (unlikely(GETSYSCTL("kern.smp.cpus", ncpus))) {
88
+ do_cpu_cores = 0;
89
+ error("CPU cores utilization stats was switched off");
90
+ return 0;
91
+ }
92
+ pcpu_cp_time = malloc(sizeof(cp_time) * ncpus);
93
+
94
+ for (i = 0; i < ncpus; i++) {
95
+ if (unlikely(getsysctl("kern.cp_times", pcpu_cp_time, sizeof(cp_time) * ncpus))) {
96
+ do_cpu_cores = 0;
97
+ error("CPU cores utilization stats was switched off");
98
+ return 0;
99
+ }
100
+ cpuid[3] = '0' + i;
101
+ user = pcpu_cp_time[i * 5 + 0];
102
+ nice = pcpu_cp_time[i * 5 + 1];
103
+ system = pcpu_cp_time[i * 5 + 2];
104
+ interrupt = pcpu_cp_time[i * 5 + 3];
105
+ idle = pcpu_cp_time[i * 5 + 4];
106
+
107
+ st = rrdset_find_bytype("cpu", cpuid);
108
+ if(unlikely(!st)) {
109
+ st = rrdset_create("cpu", cpuid, NULL, "utilization", "cpu.cpu", "Core utilization", "percentage", 1000, update_every, RRDSET_TYPE_STACKED);
110
+
111
+ rrddim_add(st, "user", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
112
+ rrddim_add(st, "system", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
113
+ rrddim_add(st, "interrupt", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
114
+ rrddim_add(st, "nice", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
115
+ rrddim_add(st, "idle", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
116
+ rrddim_hide(st, "idle");
117
+ }
118
+ else rrdset_next(st);
119
+
120
+ rrddim_set(st, "user", user);
121
+ rrddim_set(st, "system", system);
122
+ rrddim_set(st, "interrupt", interrupt);
123
+ rrddim_set(st, "nice", nice);
124
+ rrddim_set(st, "idle", idle);
125
+ rrdset_done(st);
126
+ }
127
+ free(pcpu_cp_time);
128
+ }
129
+
130
+ // --------------------------------------------------------------------
131
+
132
+ if(likely(do_interrupts)) {
133
+ if (unlikely(sysctlbyname("hw.intrcnt", NULL, &intrcnt_size, NULL, 0) == -1)) {
134
+ error("sysctl(hw.intrcnt...) failed: %s", strerror(errno));
135
+ do_interrupts = 0;
136
+ error("Total device interrupts stats was switched off");
137
+ return 0;
138
+ }
139
+ nintr = intrcnt_size / sizeof(u_long);
140
+ intrcnt = malloc(nintr * sizeof(u_long));
141
+ if (unlikely(getsysctl("hw.intrcnt", intrcnt, nintr * sizeof(u_long)))){
142
+ do_interrupts = 0;
143
+ error("Total device interrupts stats was switched off");
144
+ return 0;
145
+ }
146
+ for (i = 0; i < nintr; i++)
147
+ totalintr += intrcnt[i];
148
+ free(intrcnt);
149
+
150
+ st = rrdset_find_bytype("system", "intr");
151
+ if(unlikely(!st)) {
152
+ st = rrdset_create("system", "intr", NULL, "interrupts", NULL, "Total Device Interrupts", "interrupts/s", 900, update_every, RRDSET_TYPE_LINE);
153
+ st->isdetail = 1;
154
+
155
+ rrddim_add(st, "interrupts", NULL, 1, 1, RRDDIM_INCREMENTAL);
156
+ }
157
+ else rrdset_next(st);
158
+
159
+ rrddim_set(st, "interrupts", totalintr);
160
+ rrdset_done(st);
161
+ }
162
+
163
+/* Temporarily switched off
164
+ if(likely(do_interrupts)) {
165
+ if (unlikely(GETSYSCTL("vm.stats.sys.v_intr", vm_stat))) {
166
+ do_interrupts = 0;
167
+ error("Device interrupts utilization stats was switched off");
168
+ return 0;
169
+ }
170
+
171
+ st = rrdset_find_bytype("system", "intr");
172
+ if(unlikely(!st)) {
173
+ st = rrdset_create("system", "intr", NULL, "interrupts", NULL, "Device Interrupts", "interrupts/s", 900, update_every, RRDSET_TYPE_LINE);
174
+ st->isdetail = 1;
175
+
176
+ rrddim_add(st, "interrupts", NULL, 1, 1, RRDDIM_INCREMENTAL);
177
+ }
178
+ else rrdset_next(st);
179
+
180
+ rrddim_set(st, "interrupts", vm_stat);
181
+ rrdset_done(st);
182
+ }
183
+*/
184
+ // --------------------------------------------------------------------
185
+
186
+ if(likely(do_context)) {
187
+ if (unlikely(GETSYSCTL("vm.stats.sys.v_swtch", vm_stat))) {
188
+ do_context = 0;
189
+ error("CPU context switches stats was switched off");
190
+ return 0;
191
+ }
192
+
193
+ st = rrdset_find_bytype("system", "ctxt");
194
+ if(unlikely(!st)) {
195
+ st = rrdset_create("system", "ctxt", NULL, "processes", NULL, "CPU Context Switches", "context switches/s", 800, update_every, RRDSET_TYPE_LINE);
196
+
197
+ rrddim_add(st, "switches", NULL, 1, 1, RRDDIM_INCREMENTAL);
198
+ }
199
+ else rrdset_next(st);
200
+
201
+ rrddim_set(st, "switches", vm_stat);
202
+ rrdset_done(st);
203
+ }
204
+
205
+ // --------------------------------------------------------------------
206
+
207
+ if(likely(do_forks)) {
208
+ if (unlikely(GETSYSCTL("vm.stats.vm.v_forks", vm_stat))) {
209
+ do_forks = 0;
210
+ error("Fork stats was switched off");
211
+ return 0;
212
+ }
213
+
214
+ st = rrdset_find_bytype("system", "forks");
215
+ if(unlikely(!st)) {
216
+ st = rrdset_create("system", "forks", NULL, "processes", NULL, "Started Processes", "processes/s", 700, update_every, RRDSET_TYPE_LINE);
217
+ st->isdetail = 1;
218
+
219
+ rrddim_add(st, "started", NULL, 1, 1, RRDDIM_INCREMENTAL);
220
+ }
221
+ else rrdset_next(st);
222
+
223
+ rrddim_set(st, "started", vm_stat);
224
+ rrdset_done(st);
225
+ }
226
+
227
+ // --------------------------------------------------------------------
228
+
229
+ if(likely(do_processes)) {
230
+ if (unlikely(GETSYSCTL("vm.vmtotal", total))) {
231
+ do_processes = 0;
232
+ error("System processes stats was switched off");
233
+ return 0;
234
+ }
235
+
236
+ running = total.t_rq;
237
+ blocked = total.t_dw + total.t_pw;
238
+
239
+ st = rrdset_find_bytype("system", "processes");
240
+ if(unlikely(!st)) {
241
+ st = rrdset_create("system", "processes", NULL, "processes", NULL, "System Processes", "processes", 600, update_every, RRDSET_TYPE_LINE);
242
+
243
+ rrddim_add(st, "running", NULL, 1, 1, RRDDIM_ABSOLUTE);
244
+ rrddim_add(st, "blocked", NULL, -1, 1, RRDDIM_ABSOLUTE);
245
+ }
246
+ else rrdset_next(st);
247
+
248
+ rrddim_set(st, "running", running);
249
+ rrddim_set(st, "blocked", blocked);
250
+ rrdset_done(st);
251
+ }
252
+
253
+ return 0;
254
+}
\ No newline at end of file
src/main.c
+1
-1
@@ -48,7 +48,7 @@ struct netdata_static_thread {
48
#ifndef __FreeBSD__
49
{"proc", "plugins", "proc", 1, NULL, NULL, proc_main},
50
#else
51
- {"freebsd", "plugins", "freebsd", 1, NULL, NULL, freebsd_main},
51
+ {"proc", "plugins", "proc", 1, NULL, NULL, freebsd_main},
52
#endif /* __FreeBSD__ */
53
54
{"cgroups", "plugins", "cgroups", 1, NULL, NULL, cgroups_main},
src/plugin_freebsd.c
+38
-2
@@ -42,7 +42,8 @@ void *freebsd_main(void *ptr)
42
int vdo_sys_kernel_mm_ksm = !config_get_boolean("plugin:proc", "/sys/kernel/mm/ksm", 1);
43
*/
44
int vdo_cpu_netdata = !config_get_boolean("plugin:proc", "netdata server resources", 1);
45
-
45
+ int vdo_proc_stat = !config_get_boolean("plugin:proc", "/proc/stat", 1);
46
+ int vdo_proc_loadavg = !config_get_boolean("plugin:proc", "/proc/loadavg", 1);
47
48
// keep track of the time each module was called
49
/*
@@ -67,6 +68,8 @@ void *freebsd_main(void *ptr)
68
unsigned long long sutime_ipc = 0ULL;
69
unsigned long long sutime_sys_kernel_mm_ksm = 0ULL;
70
*/
71
+ unsigned long long sutime_proc_stat = 0ULL;
72
+ unsigned long long sutime_proc_loadavg = 0ULL;
73
74
unsigned long long step = rrd_update_every * 1000000ULL;
75
for(;;) {
@@ -243,7 +246,23 @@ void *freebsd_main(void *ptr)
246
sutime_proc_net_rpc_nfs = now;
247
}
248
if(unlikely(netdata_exit)) break;
246
- */
249
+ */
250
+
251
+ if(!vdo_proc_stat) {
252
+ debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_stat().");
253
+ now = time_usec();
254
+ vdo_proc_stat = do_proc_stat(rrd_update_every, (sutime_proc_stat > 0)?now - sutime_proc_stat:0ULL);
255
+ sutime_proc_stat = now;
256
+ }
257
+ if(unlikely(netdata_exit)) break;
258
+
259
+ if(!vdo_proc_loadavg) {
260
+ debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_loadavg().");
261
+ now = time_usec();
262
+ vdo_proc_loadavg = do_proc_loadavg(rrd_update_every, (sutime_proc_loadavg > 0)?now - sutime_proc_loadavg:0ULL);
263
+ sutime_proc_loadavg = now;
264
+ }
265
+ if(unlikely(netdata_exit)) break;
266
267
// END -- the job is done
268
@@ -260,3 +279,20 @@ void *freebsd_main(void *ptr)
279
pthread_exit(NULL);
280
return NULL;
281
}
282
+
283
+int getsysctl(const char *name, void *ptr, size_t len)
284
+{
285
+ size_t nlen = len;
286
+
287
+ if (unlikely(sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)) {
288
+ error("FREEBSD: sysctl(%s...) failed: %s\n", name,
289
+ strerror(errno));
290
+ return 1;
291
+ }
292
+ if (unlikely(nlen != len)) {
293
+ error("FREEBSD: sysctl(%s...) expected %lu, got %lu\n",
294
+ name, (unsigned long)len, (unsigned long)nlen);
295
+ return 1;
296
+ }
297
+ return 0;
298
+}
\ No newline at end of file
src/plugin_freebsd.h
+6
-1
@@ -1,8 +1,12 @@
1
#ifndef NETDATA_PLUGIN_FREEBSD_H
2
#define NETDATA_PLUGIN_FREEBSD_H 1
3
4
+#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
5
+
6
void *freebsd_main(void *ptr);
7
8
+extern int getsysctl(const char *name, void *ptr, size_t len);
9
+
10
/*
11
extern int do_proc_net_dev(int update_every, unsigned long long dt);
12
extern int do_proc_diskstats(int update_every, unsigned long long dt);
@@ -11,7 +15,6 @@ extern int do_proc_net_snmp6(int update_every, unsigned long long dt);
15
extern int do_proc_net_netstat(int update_every, unsigned long long dt);
16
extern int do_proc_net_stat_conntrack(int update_every, unsigned long long dt);
17
extern int do_proc_net_ip_vs_stats(int update_every, unsigned long long dt);
14
-extern int do_proc_stat(int update_every, unsigned long long dt);
18
extern int do_proc_meminfo(int update_every, unsigned long long dt);
19
extern int do_proc_vmstat(int update_every, unsigned long long dt);
20
extern int do_proc_net_rpc_nfs(int update_every, unsigned long long dt);
@@ -24,5 +27,7 @@ extern int do_proc_loadavg(int update_every, unsigned long long dt);
27
extern int do_proc_net_stat_synproxy(int update_every, unsigned long long dt);
28
extern int do_proc_net_softnet_stat(int update_every, unsigned long long dt);
29
*/
30
+extern int do_proc_stat(int update_every, unsigned long long dt);
31
+extern int do_proc_loadavg(int update_every, unsigned long long dt);
32
33
#endif /* NETDATA_FREEBSD_PROC_H */