@cryptotaxi247 / netdata-1 / commits / d93bfda9a

added IPC semaphores charts

Costa Tsaousis (ktsaou) committed Nov 13, 2016 at 01:49 UTC d93bfda9ac92f7ea2afc5fa820cfe9595cb27db6
6 files changed +258
CMakeLists.txt
+2
@@ -26,6 +26,8 @@ set(NETDATA_SOURCE_FILES
26 src/global_statistics.h
27 src/health.c
28 src/health.h
29 + src/ipc.c
30 + src/ipc.h
31 src/log.c
32 src/log.h
33 src/main.c
src/Makefile.am
+1
@@ -35,6 +35,7 @@ netdata_SOURCES = \
35 eval.c eval.h \
36 global_statistics.c global_statistics.h \
37 health.c health.h \
38 + ipc.c ipc.h \
39 log.c log.h \
40 main.c main.h \
41 plugin_checks.c plugin_checks.h \
src/common.h
+2
@@ -129,6 +129,8 @@
129 #include "main.h"
130 #include "unit_test.h"
131
132 +#include "ipc.h"
133 +
134 #ifdef abs
135 #undef abs
136 #endif
src/ipc.c new
+236
@@ -0,0 +1,236 @@
1 +#include "common.h"
2 +
3 +#include <sys/sem.h>
4 +#include <sys/msg.h>
5 +#include <sys/shm.h>
6 +
7 +
8 +#ifndef SEMVMX
9 +#define SEMVMX 32767 /* <= 32767 semaphore maximum value */
10 +#endif
11 +
12 +/* Some versions of libc only define IPC_INFO when __USE_GNU is defined. */
13 +#ifndef IPC_INFO
14 +#define IPC_INFO 3
15 +#endif
16 +
17 +struct ipc_limits {
18 + uint64_t shmmni; /* max number of segments */
19 + uint64_t shmmax; /* max segment size */
20 + uint64_t shmall; /* max total shared memory */
21 + uint64_t shmmin; /* min segment size */
22 +
23 + int semmni; /* max number of arrays */
24 + int semmsl; /* max semaphores per array */
25 + int semmns; /* max semaphores system wide */
26 + int semopm; /* max ops per semop call */
27 + unsigned int semvmx; /* semaphore max value (constant) */
28 +
29 + int msgmni; /* max queues system wide */
30 + size_t msgmax; /* max size of message */
31 + int msgmnb; /* default max size of queue */
32 +};
33 +
34 +struct ipc_status {
35 + int semusz; /* current number of arrays */
36 + int semaem; /* current semaphores system wide */
37 +};
38 +
39 +/*
40 + * The last arg of semctl is a union semun, but where is it defined? X/OPEN
41 + * tells us to define it ourselves, but until recently Linux include files
42 + * would also define it.
43 + */
44 +#ifndef HAVE_UNION_SEMUN
45 +/* according to X/OPEN we have to define it ourselves */
46 +union semun {
47 + int val;
48 + struct semid_ds *buf;
49 + unsigned short int *array;
50 + struct seminfo *__buf;
51 +};
52 +#endif
53 +
54 +static inline int ipc_sem_get_limits(struct ipc_limits *lim) {
55 + static procfile *ff = NULL;
56 + static int error_shown = 0;
57 + static char filename[FILENAME_MAX + 1] = "";
58 +
59 + if(unlikely(!filename[0]))
60 + snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/sem", global_host_prefix);
61 +
62 + if(unlikely(!ff)) {
63 + ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
64 + if(unlikely(!ff)) {
65 + if(unlikely(!error_shown)) {
66 + error("IPC: Cannot open file '%s'.", filename);
67 + error_shown = 1;
68 + }
69 + goto ipc;
70 + }
71 + }
72 +
73 + ff = procfile_readall(ff);
74 + if(unlikely(!ff)) {
75 + if(unlikely(!error_shown)) {
76 + error("IPC: Cannot read file '%s'.", filename);
77 + error_shown = 1;
78 + }
79 + goto ipc;
80 + }
81 +
82 + if(procfile_lines(ff) >= 1 && procfile_linewords(ff, 0) >= 4) {
83 + lim->semvmx = SEMVMX;
84 + lim->semmsl = atoi(procfile_lineword(ff, 0, 0));
85 + lim->semmns = atoi(procfile_lineword(ff, 0, 1));
86 + lim->semopm = atoi(procfile_lineword(ff, 0, 2));
87 + lim->semmni = atoi(procfile_lineword(ff, 0, 3));
88 + return 0;
89 + }
90 + else {
91 + if(unlikely(!error_shown)) {
92 + error("IPC: Invalid content in file '%s'.", filename);
93 + error_shown = 1;
94 + }
95 + goto ipc;
96 + }
97 +
98 +ipc:
99 + // cannot do it from the file
100 + // query IPC
101 + {
102 + struct seminfo seminfo = {.semmni = 0};
103 + union semun arg = {.array = (ushort *) &seminfo};
104 +
105 + if(unlikely(semctl(0, 0, IPC_INFO, arg) < 0)) {
106 + error("IPC: Failed to read '%s' and request IPC_INFO with semctl().", filename);
107 + goto error;
108 + }
109 +
110 + lim->semvmx = SEMVMX;
111 + lim->semmni = seminfo.semmni;
112 + lim->semmsl = seminfo.semmsl;
113 + lim->semmns = seminfo.semmns;
114 + lim->semopm = seminfo.semopm;
115 + return 0;
116 + }
117 +
118 +error:
119 + lim->semvmx = 0;
120 + lim->semmni = 0;
121 + lim->semmsl = 0;
122 + lim->semmns = 0;
123 + lim->semopm = 0;
124 + return -1;
125 +}
126 +
127 +/*
128 +printf ("------ Semaphore Limits --------\n");
129 +printf ("max number of arrays = %d\n", limits.semmni);
130 +printf ("max semaphores per array = %d\n", limits.semmsl);
131 +printf ("max semaphores system wide = %d\n", limits.semmns);
132 +printf ("max ops per semop call = %d\n", limits.semopm);
133 +printf ("semaphore max value = %u\n", limits.semvmx);
134 +
135 +printf ("------ Semaphore Status --------\n");
136 +printf ("used arrays = %d\n", status.semusz);
137 +printf ("allocated semaphores = %d\n", status.semaem);
138 +*/
139 +
140 +static inline int ipc_sem_get_status(struct ipc_status *st) {
141 + static int error_shown = 0;
142 + struct seminfo seminfo;
143 + union semun arg;
144 +
145 + arg.array = (ushort *) (void *) &seminfo;
146 +
147 + if(unlikely(semctl (0, 0, SEM_INFO, arg) < 0)) {
148 + /* kernel not configured for semaphores */
149 + if(unlikely(!error_shown)) {
150 + error("IPC: kernel is not configured for semaphores");
151 + error_shown = 1;
152 + }
153 + st->semusz = 0;
154 + st->semaem = 0;
155 + return -1;
156 + }
157 +
158 + st->semusz = seminfo.semusz;
159 + st->semaem = seminfo.semaem;
160 + return 0;
161 +}
162 +
163 +int do_ipc(int update_every, unsigned long long dt) {
164 + (void)dt;
165 +
166 + static int initialized = 0, read_limits_next = 0;
167 + static struct ipc_limits limits;
168 + static struct ipc_status status;
169 + static RRDVAR *arrays_max = NULL, *semaphores_max = NULL;
170 + static RRDSET *semaphores = NULL, *arrays = NULL;
171 +
172 + if(unlikely(!initialized)) {
173 + // make sure it works
174 + if(ipc_sem_get_limits(&limits) == -1) {
175 + error("unable to fetch semaphore limits");
176 + return 1;
177 + }
178 +
179 + // make sure it works
180 + if(ipc_sem_get_status(&status) == -1) {
181 + error("unable to fetch semaphore statistics");
182 + return 1;
183 + }
184 +
185 + arrays_max = rrdvar_custom_host_variable_create(&localhost, "ipc.semaphores.arrays.max");
186 + semaphores_max = rrdvar_custom_host_variable_create(&localhost, "ipc.semaphores.max");
187 +
188 + if(arrays_max) rrdvar_custom_host_variable_set(arrays_max, limits.semmni);
189 + if(semaphores_max) rrdvar_custom_host_variable_set(semaphores_max, limits.semmns);
190 +
191 + // create the charts
192 + semaphores = rrdset_find("system.ipc_semaphores");
193 + if(!semaphores) {
194 + semaphores = rrdset_create("system", "ipc_semaphores", NULL, "ipc semaphores", NULL, "IPC Semaphores", "semaphores", 1000, rrd_update_every, RRDSET_TYPE_AREA);
195 + rrddim_add(semaphores, "semaphores", NULL, 1, 1, RRDDIM_ABSOLUTE);
196 + }
197 +
198 + arrays = rrdset_find("system.ipc_semaphore_arrays");
199 + if(!arrays) {
200 + arrays = rrdset_create("system", "ipc_semaphore_arrays", NULL, "ipc semaphores", NULL, "IPC Semaphore Arrays", "arrays", 1000, rrd_update_every, RRDSET_TYPE_AREA);
201 + rrddim_add(arrays, "arrays", NULL, 1, 1, RRDDIM_ABSOLUTE);
202 + }
203 + }
204 +
205 + if(unlikely(read_limits_next < 0)) {
206 + if(unlikely(ipc_sem_get_limits(&limits) == -1)) {
207 + error("Unable to fetch semaphore limits.");
208 + }
209 + else {
210 + rrdvar_custom_host_variable_set(arrays_max, limits.semmni);
211 + rrdvar_custom_host_variable_set(semaphores_max, limits.semmns);
212 +
213 + arrays->red = limits.semmni;
214 + semaphores->red = limits.semmns;
215 +
216 + read_limits_next = 60 / update_every;
217 + }
218 + }
219 + else
220 + read_limits_next--;
221 +
222 + if(unlikely(ipc_sem_get_status(&status) == -1)) {
223 + error("Unable to get semaphore statistics");
224 + return 0;
225 + }
226 +
227 + if(semaphores->counter_done) rrdset_next(semaphores);
228 + rrddim_set(semaphores, "semaphores", status.semaem);
229 + rrdset_done(semaphores);
230 +
231 + if(arrays->counter_done) rrdset_next(arrays);
232 + rrddim_set(arrays, "arrays", status.semusz);
233 + rrdset_done(arrays);
234 +
235 + return 0;
236 +}
src/ipc.h new
+7
@@ -0,0 +1,7 @@
1 +#ifndef NETDATA_PLUGIN_IPC_H
2 +#define NETDATA_PLUGIN_IPC_H 1
3 +
4 +extern int do_ipc(int update_every, unsigned long long dt);
5 +
6 +#endif /* NETDATA_PLUGIN_IPC_H */
7 +
src/plugin_proc.c
+10
@@ -35,6 +35,7 @@ void *proc_main(void *ptr)
35 int vdo_proc_softirqs = !config_get_boolean("plugin:proc", "/proc/softirqs", 1);
36 int vdo_proc_net_softnet_stat = !config_get_boolean("plugin:proc", "/proc/net/softnet_stat", 1);
37 int vdo_proc_loadavg = !config_get_boolean("plugin:proc", "/proc/loadavg", 1);
38 + int vdo_ipc = !config_get_boolean("plugin:proc", "ipc", 1);
39 int vdo_sys_kernel_mm_ksm = !config_get_boolean("plugin:proc", "/sys/kernel/mm/ksm", 1);
40 int vdo_cpu_netdata = !config_get_boolean("plugin:proc", "netdata server resources", 1);
41
@@ -57,6 +58,7 @@ void *proc_main(void *ptr)
58 unsigned long long sutime_proc_softirqs = 0ULL;
59 unsigned long long sutime_proc_net_softnet_stat = 0ULL;
60 unsigned long long sutime_proc_loadavg = 0ULL;
61 + unsigned long long sutime_ipc = 0ULL;
62 unsigned long long sutime_sys_kernel_mm_ksm = 0ULL;
63
64 // the next time we will run - aligned properly
@@ -95,6 +97,14 @@ void *proc_main(void *ptr)
97 }
98 if(unlikely(netdata_exit)) break;
99
100 + if(!vdo_ipc) {
101 + debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_ipc().");
102 + sunow = time_usec();
103 + vdo_ipc = do_ipc(rrd_update_every, (sutime_ipc > 0)?sunow - sutime_ipc:0ULL);
104 + sutime_ipc = sunow;
105 + }
106 + if(unlikely(netdata_exit)) break;
107 +
108 if(!vdo_proc_interrupts) {
109 debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_interrupts().");
110 sunow = time_usec();