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();