@cryptotaxi247 / netdata-1 / commits / 4e6883b88

cgroup-top function (#16314)

* split cgroups discovery to a separate file * base for implementing cgroup-top * working cgtop * removed off_t casting * update * fix cpu_full_pressure_stall_time ctx * check disk read/write dims is not NULL in functions * fixes * fix traffic * fix codacy warnings * upd --------- Co-authored-by: ilyam8 <ilya@netdata.cloud>

Costa Tsaousis committed Nov 2, 2023 at 14:27 UTC 4e6883b881081adfaf40c9f132773c46f7590a81
9 files changed +4073 -3298
Makefile.am
+4
@@ -280,6 +280,10 @@ IDLEJITTER_PLUGIN_FILES = \
280 $(NULL)
281
282 CGROUPS_PLUGIN_FILES = \
283 + collectors/cgroups.plugin/cgroup-internals.h \
284 + collectors/cgroups.plugin/cgroup-discovery.c \
285 + collectors/cgroups.plugin/cgroup-charts.c \
286 + collectors/cgroups.plugin/cgroup-top.c \
287 collectors/cgroups.plugin/sys_fs_cgroup.c \
288 collectors/cgroups.plugin/sys_fs_cgroup.h \
289 $(NULL)
collectors/cgroups.plugin/cgroup-charts.c new
+1486
@@ -0,0 +1,1486 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "cgroup-internals.h"
4 +
5 +void update_cpu_utilization_chart(struct cgroup *cg) {
6 + RRDSET *chart = cg->st_cpu;
7 +
8 + if (unlikely(!cg->st_cpu)) {
9 + char *title;
10 + char *context;
11 + int prio;
12 +
13 + if (is_cgroup_systemd_service(cg)) {
14 + title = "Systemd Services CPU utilization (100%% = 1 core)";
15 + context = "systemd.service.cpu.utilization";
16 + prio = NETDATA_CHART_PRIO_CGROUPS_SYSTEMD;
17 + } else {
18 + title = k8s_is_kubepod(cg) ? "CPU Usage (100%% = 1000 mCPU)" : "CPU Usage (100%% = 1 core)";
19 + context = k8s_is_kubepod(cg) ? "k8s.cgroup.cpu" : "cgroup.cpu";
20 + prio = cgroup_containers_chart_priority;
21 + }
22 +
23 + char buff[RRD_ID_LENGTH_MAX + 1];
24 + chart = cg->st_cpu = rrdset_create_localhost(
25 + cgroup_chart_type(buff, cg),
26 + "cpu",
27 + NULL,
28 + "cpu",
29 + context,
30 + title,
31 + "percentage",
32 + PLUGIN_CGROUPS_NAME,
33 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
34 + prio,
35 + cgroup_update_every,
36 + RRDSET_TYPE_STACKED);
37 +
38 + rrdset_update_rrdlabels(chart, cg->chart_labels);
39 +
40 + if (!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
41 + cg->st_cpu_rd_user = rrddim_add(chart, "user", NULL, 100, system_hz, RRD_ALGORITHM_INCREMENTAL);
42 + cg->st_cpu_rd_system = rrddim_add(chart, "system", NULL, 100, system_hz, RRD_ALGORITHM_INCREMENTAL);
43 + } else {
44 + cg->st_cpu_rd_user = rrddim_add(chart, "user", NULL, 100, 1000000, RRD_ALGORITHM_INCREMENTAL);
45 + cg->st_cpu_rd_system = rrddim_add(chart, "system", NULL, 100, 1000000, RRD_ALGORITHM_INCREMENTAL);
46 + }
47 + }
48 +
49 + rrddim_set_by_pointer(chart, cg->st_cpu_rd_user, (collected_number)cg->cpuacct_stat.user);
50 + rrddim_set_by_pointer(chart, cg->st_cpu_rd_system, (collected_number)cg->cpuacct_stat.system);
51 + rrdset_done(chart);
52 +}
53 +
54 +void update_cpu_utilization_limit_chart(struct cgroup *cg, NETDATA_DOUBLE cpu_limit) {
55 + if (is_cgroup_systemd_service(cg))
56 + return;
57 +
58 + RRDSET *chart = cg->st_cpu_limit;
59 +
60 + if (unlikely(!cg->st_cpu_limit)) {
61 + char *title = "CPU Usage within the limits";
62 + char *context = k8s_is_kubepod(cg) ? "k8s.cgroup.cpu_limit" : "cgroup.cpu_limit";
63 + int prio = cgroup_containers_chart_priority - 1;
64 +
65 + char buff[RRD_ID_LENGTH_MAX + 1];
66 + chart = cg->st_cpu_limit = rrdset_create_localhost(
67 + cgroup_chart_type(buff, cg),
68 + "cpu_limit",
69 + NULL,
70 + "cpu",
71 + context,
72 + title,
73 + "percentage",
74 + PLUGIN_CGROUPS_NAME,
75 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
76 + prio,
77 + cgroup_update_every,
78 + RRDSET_TYPE_LINE);
79 +
80 + rrdset_update_rrdlabels(chart, cg->chart_labels);
81 +
82 + if (!(cg->options & CGROUP_OPTIONS_IS_UNIFIED))
83 + rrddim_add(chart, "used", NULL, 1, system_hz, RRD_ALGORITHM_ABSOLUTE);
84 + else
85 + rrddim_add(chart, "used", NULL, 1, 1000000, RRD_ALGORITHM_ABSOLUTE);
86 + cg->prev_cpu_usage = (NETDATA_DOUBLE)(cg->cpuacct_stat.user + cg->cpuacct_stat.system) * 100;
87 + }
88 +
89 + NETDATA_DOUBLE cpu_usage = 0;
90 + cpu_usage = (NETDATA_DOUBLE)(cg->cpuacct_stat.user + cg->cpuacct_stat.system) * 100;
91 + NETDATA_DOUBLE cpu_used = 100 * (cpu_usage - cg->prev_cpu_usage) / (cpu_limit * cgroup_update_every);
92 +
93 + rrdset_isnot_obsolete___safe_from_collector_thread(chart);
94 +
95 + rrddim_set(chart, "used", (cpu_used > 0) ? (collected_number)cpu_used : 0);
96 +
97 + cg->prev_cpu_usage = cpu_usage;
98 +
99 + rrdsetvar_custom_chart_variable_set(cg->st_cpu, cg->chart_var_cpu_limit, cpu_limit);
100 + rrdset_done(chart);
101 +}
102 +
103 +void update_cpu_throttled_chart(struct cgroup *cg) {
104 + if (is_cgroup_systemd_service(cg))
105 + return;
106 +
107 + RRDSET *chart = cg->st_cpu_nr_throttled;
108 +
109 + if (unlikely(!cg->st_cpu_nr_throttled)) {
110 + char *title = "CPU Throttled Runnable Periods";
111 + char *context = k8s_is_kubepod(cg) ? "k8s.cgroup.throttled" : "cgroup.throttled";
112 + int prio = cgroup_containers_chart_priority + 10;
113 +
114 + char buff[RRD_ID_LENGTH_MAX + 1];
115 + chart = cg->st_cpu_nr_throttled = rrdset_create_localhost(
116 + cgroup_chart_type(buff, cg),
117 + "throttled",
118 + NULL,
119 + "cpu",
120 + context,
121 + title,
122 + "percentage",
123 + PLUGIN_CGROUPS_NAME,
124 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
125 + prio,
126 + cgroup_update_every,
127 + RRDSET_TYPE_LINE);
128 +
129 + rrdset_update_rrdlabels(chart, cg->chart_labels);
130 + rrddim_add(chart, "throttled", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
131 + }
132 +
133 + rrddim_set(chart, "throttled", (collected_number)cg->cpuacct_cpu_throttling.nr_throttled_perc);
134 + rrdset_done(chart);
135 +}
136 +
137 +void update_cpu_throttled_duration_chart(struct cgroup *cg) {
138 + if (is_cgroup_systemd_service(cg))
139 + return;
140 +
141 + RRDSET *chart = cg->st_cpu_throttled_time;
142 +
143 + if (unlikely(!cg->st_cpu_throttled_time)) {
144 + char *title = "CPU Throttled Time Duration";
145 + char *context = k8s_is_kubepod(cg) ? "k8s.cgroup.throttled" : "cgroup.throttled";
146 + int prio = cgroup_containers_chart_priority + 15;
147 +
148 + char buff[RRD_ID_LENGTH_MAX + 1];
149 + chart = cg->st_cpu_throttled_time = rrdset_create_localhost(
150 + cgroup_chart_type(buff, cg),
151 + "throttled_duration",
152 + NULL,
153 + "cpu",
154 + context,
155 + title,
156 + "ms",
157 + PLUGIN_CGROUPS_NAME,
158 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
159 + prio,
160 + cgroup_update_every,
161 + RRDSET_TYPE_LINE);
162 +
163 + rrdset_update_rrdlabels(chart, cg->chart_labels);
164 + rrddim_add(chart, "duration", NULL, 1, 1000000, RRD_ALGORITHM_INCREMENTAL);
165 + }
166 +
167 + rrddim_set(chart, "duration", (collected_number)cg->cpuacct_cpu_throttling.throttled_time);
168 + rrdset_done(chart);
169 +}
170 +
171 +void update_cpu_shares_chart(struct cgroup *cg) {
172 + if (is_cgroup_systemd_service(cg))
173 + return;
174 +
175 + RRDSET *chart = cg->st_cpu_shares;
176 +
177 + if (unlikely(!cg->st_cpu_shares)) {
178 + char *title = "CPU Time Relative Share";
179 + char *context = k8s_is_kubepod(cg) ? "k8s.cgroup.cpu_shares" : "cgroup.cpu_shares";
180 + int prio = cgroup_containers_chart_priority + 20;
181 +
182 + char buff[RRD_ID_LENGTH_MAX + 1];
183 + chart = cg->st_cpu_shares = rrdset_create_localhost(
184 + cgroup_chart_type(buff, cg),
185 + "cpu_shares",
186 + NULL,
187 + "cpu",
188 + context,
189 + title,
190 + "shares",
191 + PLUGIN_CGROUPS_NAME,
192 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
193 + prio,
194 + cgroup_update_every,
195 + RRDSET_TYPE_LINE);
196 +
197 + rrdset_update_rrdlabels(chart, cg->chart_labels);
198 + rrddim_add(chart, "shares", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
199 + }
200 +
201 + rrddim_set(chart, "shares", (collected_number)cg->cpuacct_cpu_shares.shares);
202 + rrdset_done(chart);
203 +}
204 +
205 +void update_cpu_per_core_usage_chart(struct cgroup *cg) {
206 + if (is_cgroup_systemd_service(cg))
207 + return;
208 +
209 + char id[RRD_ID_LENGTH_MAX + 1];
210 + unsigned int i;
211 +
212 + if (unlikely(!cg->st_cpu_per_core)) {
213 + char *title = k8s_is_kubepod(cg) ? "CPU Usage (100%% = 1000 mCPU) Per Core" : "CPU Usage (100%% = 1 core) Per Core";
214 + char *context = k8s_is_kubepod(cg) ? "k8s.cgroup.cpu_per_core" : "cgroup.cpu_per_core";
215 + int prio = cgroup_containers_chart_priority + 100;
216 +
217 + char buff[RRD_ID_LENGTH_MAX + 1];
218 + cg->st_cpu_per_core = rrdset_create_localhost(
219 + cgroup_chart_type(buff, cg),
220 + "cpu_per_core",
221 + NULL,
222 + "cpu",
223 + context,
224 + title,
225 + "percentage",
226 + PLUGIN_CGROUPS_NAME,
227 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
228 + prio,
229 + cgroup_update_every,
230 + RRDSET_TYPE_STACKED);
231 +
232 + rrdset_update_rrdlabels(cg->st_cpu_per_core, cg->chart_labels);
233 +
234 + for (i = 0; i < cg->cpuacct_usage.cpus; i++) {
235 + snprintfz(id, RRD_ID_LENGTH_MAX, "cpu%u", i);
236 + rrddim_add(cg->st_cpu_per_core, id, NULL, 100, 1000000000, RRD_ALGORITHM_INCREMENTAL);
237 + }
238 + }
239 +
240 + for (i = 0; i < cg->cpuacct_usage.cpus; i++) {
241 + snprintfz(id, RRD_ID_LENGTH_MAX, "cpu%u", i);
242 + rrddim_set(cg->st_cpu_per_core, id, (collected_number)cg->cpuacct_usage.cpu_percpu[i]);
243 + }
244 + rrdset_done(cg->st_cpu_per_core);
245 +}
246 +
247 +void update_mem_usage_detailed_chart(struct cgroup *cg) {
248 + RRDSET *chart = cg->st_mem;
249 +
250 + if (unlikely(!cg->st_mem)) {
251 + char *title;
252 + char *context;
253 + int prio;
254 + if (is_cgroup_systemd_service(cg)) {
255 + title = "Systemd Services Memory";
256 + context = "systemd.service.memory.ram.usage";
257 + prio = NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 15;
258 + } else {
259 + title = "Memory Usage";
260 + context = k8s_is_kubepod(cg) ? "k8s.cgroup.mem" : "cgroup.mem";
261 + prio = cgroup_containers_chart_priority + 220;
262 + }
263 +
264 + char buff[RRD_ID_LENGTH_MAX + 1];
265 +
266 + chart = cg->st_mem = rrdset_create_localhost(
267 + cgroup_chart_type(buff, cg),
268 + "mem",
269 + NULL,
270 + "mem",
271 + context,
272 + title,
273 + "MiB",
274 + PLUGIN_CGROUPS_NAME,
275 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
276 + prio,
277 + cgroup_update_every,
278 + RRDSET_TYPE_STACKED);
279 +
280 + rrdset_update_rrdlabels(chart, cg->chart_labels);
281 +
282 + if (!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
283 + rrddim_add(chart, "cache", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
284 + rrddim_add(chart, "rss", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
285 +
286 + if (cg->memory.detailed_has_swap)
287 + rrddim_add(chart, "swap", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
288 +
289 + rrddim_add(chart, "rss_huge", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
290 + rrddim_add(chart, "mapped_file", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
291 + } else {
292 + rrddim_add(chart, "anon", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
293 + rrddim_add(chart, "kernel_stack", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
294 + rrddim_add(chart, "slab", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
295 + rrddim_add(chart, "sock", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
296 + rrddim_add(chart, "anon_thp", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
297 + rrddim_add(chart, "file", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
298 + }
299 + }
300 +
301 + if (!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
302 + rrddim_set(chart, "cache", (collected_number)cg->memory.total_cache);
303 + collected_number rss = (collected_number)(cg->memory.total_rss - cg->memory.total_rss_huge);
304 + if (rss < 0)
305 + rss = 0;
306 + rrddim_set(chart, "rss", rss);
307 + if (cg->memory.detailed_has_swap)
308 + rrddim_set(chart, "swap", (collected_number)cg->memory.total_swap);
309 + rrddim_set(chart, "rss_huge", (collected_number)cg->memory.total_rss_huge);
310 + rrddim_set(chart, "mapped_file", (collected_number)cg->memory.total_mapped_file);
311 + } else {
312 + rrddim_set(chart, "anon", (collected_number)cg->memory.anon);
313 + rrddim_set(chart, "kernel_stack", (collected_number)cg->memory.kernel_stack);
314 + rrddim_set(chart, "slab", (collected_number)cg->memory.slab);
315 + rrddim_set(chart, "sock", (collected_number)cg->memory.sock);
316 + rrddim_set(chart, "anon_thp", (collected_number)cg->memory.anon_thp);
317 + rrddim_set(chart, "file", (collected_number)cg->memory.total_mapped_file);
318 + }
319 + rrdset_done(chart);
320 +}
321 +
322 +void update_mem_writeback_chart(struct cgroup *cg) {
323 + RRDSET *chart = cg->st_writeback;
324 +
325 + if (unlikely(!cg->st_writeback)) {
326 + char *title;
327 + char *context;
328 + int prio;
329 + if (is_cgroup_systemd_service(cg)) {
330 + title = "Systemd Services Writeback Memory";
331 + context = "systemd.service.memory.writeback";
332 + prio = NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 20;
333 + } else {
334 + title = "Writeback Memory";
335 + context = k8s_is_kubepod(cg) ? "k8s.cgroup.writeback" : "cgroup.writeback";
336 + prio = cgroup_containers_chart_priority + 300;
337 + }
338 +
339 + char buff[RRD_ID_LENGTH_MAX + 1];
340 + chart = cg->st_writeback = rrdset_create_localhost(
341 + cgroup_chart_type(buff, cg),
342 + "writeback",
343 + NULL,
344 + "mem",
345 + context,
346 + title,
347 + "MiB",
348 + PLUGIN_CGROUPS_NAME,
349 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
350 + prio,
351 + cgroup_update_every,
352 + RRDSET_TYPE_AREA);
353 +
354 + rrdset_update_rrdlabels(chart, cg->chart_labels);
355 + if (cg->memory.detailed_has_dirty)
356 + rrddim_add(chart, "dirty", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
357 + rrddim_add(chart, "writeback", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
358 + }
359 +
360 + if (cg->memory.detailed_has_dirty)
361 + rrddim_set(chart, "dirty", (collected_number)cg->memory.total_dirty);
362 + rrddim_set(chart, "writeback", (collected_number)cg->memory.total_writeback);
363 + rrdset_done(chart);
364 +}
365 +
366 +void update_mem_activity_chart(struct cgroup *cg) {
367 + RRDSET *chart = cg->st_mem_activity;
368 +
369 + if (unlikely(!cg->st_mem_activity)) {
370 + char *title;
371 + char *context;
372 + int prio;
373 + if (is_cgroup_systemd_service(cg)) {
374 + title = "Systemd Services Memory Paging IO";
375 + context = "systemd.service.memory.paging.io";
376 + prio = NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 30;
377 + } else {
378 + title = "Memory Activity";
379 + context = k8s_is_kubepod(cg) ? "k8s.cgroup.mem_activity" : "cgroup.mem_activity";
380 + prio = cgroup_containers_chart_priority + 400;
381 + }
382 +
383 + char buff[RRD_ID_LENGTH_MAX + 1];
384 + chart = cg->st_mem_activity = rrdset_create_localhost(
385 + cgroup_chart_type(buff, cg),
386 + "mem_activity",
387 + NULL,
388 + "mem",
389 + context,
390 + title,
391 + "MiB/s",
392 + PLUGIN_CGROUPS_NAME,
393 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
394 + prio,
395 + cgroup_update_every,
396 + RRDSET_TYPE_LINE);
397 +
398 + rrdset_update_rrdlabels(chart, cg->chart_labels);
399 + // FIXME: systemd just in, out
400 + rrddim_add(chart, "pgpgin", "in", system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
401 + rrddim_add(chart, "pgpgout", "out", -system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
402 + }
403 +
404 + rrddim_set(chart, "pgpgin", (collected_number)cg->memory.total_pgpgin);
405 + rrddim_set(chart, "pgpgout", (collected_number)cg->memory.total_pgpgout);
406 + rrdset_done(chart);
407 +}
408 +
409 +void update_mem_pgfaults_chart(struct cgroup *cg) {
410 + RRDSET *chart = cg->st_pgfaults;
411 +
412 + if (unlikely(!cg->st_pgfaults)) {
413 + char *title;
414 + char *context;
415 + int prio;
416 + if (is_cgroup_systemd_service(cg)) {
417 + title = "Systemd Services Memory Page Faults";
418 + context = "systemd.service.memory.paging.faults";
419 + prio = NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 25;
420 + } else {
421 + title = "Memory Page Faults";
422 + context = k8s_is_kubepod(cg) ? "k8s.cgroup.pgfaults" : "cgroup.pgfaults";
423 + prio = cgroup_containers_chart_priority + 500;
424 + }
425 +
426 + char buff[RRD_ID_LENGTH_MAX + 1];
427 + chart = cg->st_pgfaults = rrdset_create_localhost(
428 + cgroup_chart_type(buff, cg),
429 + "pgfaults",
430 + NULL,
431 + "mem",
432 + context,
433 + title,
434 + "MiB/s",
435 + PLUGIN_CGROUPS_NAME,
436 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
437 + prio,
438 + cgroup_update_every,
439 + RRDSET_TYPE_LINE);
440 +
441 + rrdset_update_rrdlabels(chart, cg->chart_labels);
442 + rrddim_add(chart, "pgfault", NULL, system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
443 + rrddim_add(chart, "pgmajfault", "swap", -system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
444 + }
445 +
446 + rrddim_set(chart, "pgfault", (collected_number)cg->memory.total_pgfault);
447 + rrddim_set(chart, "pgmajfault", (collected_number)cg->memory.total_pgmajfault);
448 + rrdset_done(chart);
449 +}
450 +
451 +void update_mem_usage_limit_chart(struct cgroup *cg, unsigned long long memory_limit) {
452 + if (is_cgroup_systemd_service(cg))
453 + return;
454 +
455 + RRDSET *chart = cg->st_mem_usage_limit;
456 +
457 + if (unlikely(!cg->st_mem_usage_limit)) {
458 + char *title = "Used RAM within the limits";
459 + char *context = k8s_is_kubepod(cg) ? "k8s.cgroup.mem_usage_limit" : "cgroup.mem_usage_limit";
460 + int prio = cgroup_containers_chart_priority + 200;
461 +
462 + char buff[RRD_ID_LENGTH_MAX + 1];
463 + chart = cg->st_mem_usage_limit = rrdset_create_localhost(
464 + cgroup_chart_type(buff, cg),
465 + "mem_usage_limit",
466 + NULL,
467 + "mem",
468 + context,
469 + title,
470 + "MiB",
471 + PLUGIN_CGROUPS_NAME,
472 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
473 + prio,
474 + cgroup_update_every,
475 + RRDSET_TYPE_STACKED);
476 +
477 + rrdset_update_rrdlabels(chart, cg->chart_labels);
478 +
479 + rrddim_add(chart, "available", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
480 + rrddim_add(chart, "used", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
481 + }
482 +
483 + rrdset_isnot_obsolete___safe_from_collector_thread(chart);
484 +
485 + rrddim_set(chart, "available", (collected_number)(memory_limit - cg->memory.usage_in_bytes));
486 + rrddim_set(chart, "used", (collected_number)cg->memory.usage_in_bytes);
487 + rrdset_done(chart);
488 +}
489 +
490 +void update_mem_utilization_chart(struct cgroup *cg, unsigned long long memory_limit) {
491 + if (is_cgroup_systemd_service(cg))
492 + return;
493 +
494 + RRDSET *chart = cg->st_mem_utilization;
495 +
496 + if (unlikely(!cg->st_mem_utilization)) {
497 + char *title = "Memory Utilization";
498 + char *context = k8s_is_kubepod(cg) ? "k8s.cgroup.mem_utilization" : "cgroup.mem_utilization";
499 + int prio = cgroup_containers_chart_priority + 199;
500 +
501 + char buff[RRD_ID_LENGTH_MAX + 1];
502 + chart = cg->st_mem_utilization = rrdset_create_localhost(
503 + cgroup_chart_type(buff, cg),
504 + "mem_utilization",
505 + NULL,
506 + "mem",
507 + context,
508 + title,
509 + "percentage",
510 + PLUGIN_CGROUPS_NAME,
511 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
512 + prio,
513 + cgroup_update_every,
514 + RRDSET_TYPE_AREA);
515 +
516 + rrdset_update_rrdlabels(chart, cg->chart_labels);
517 +
518 + rrddim_add(chart, "utilization", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
519 + }
520 +
521 + rrdset_isnot_obsolete___safe_from_collector_thread(chart);
522 + collected_number util = (collected_number)(cg->memory.usage_in_bytes * 100 / memory_limit);
523 + rrddim_set(chart, "utilization", util);
524 + rrdset_done(chart);
525 +}
526 +
527 +void update_mem_failcnt_chart(struct cgroup *cg) {
528 + RRDSET *chart = cg->st_mem_failcnt;
529 +
530 + if (unlikely(!cg->st_mem_failcnt)) {
531 + char *title;
532 + char *context;
533 + int prio;
534 + if (is_cgroup_systemd_service(cg)) {
535 + title = "Systemd Services Memory Limit Failures";
536 + context = "systemd.service.memory.failcnt";
537 + prio = NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 10;
538 + } else {
539 + title = "Memory Limit Failures";
540 + context = k8s_is_kubepod(cg) ? "k8s.cgroup.mem_failcnt" : "cgroup.mem_failcnt";
541 + prio = cgroup_containers_chart_priority + 250;
542 + }
543 +
544 + char buff[RRD_ID_LENGTH_MAX + 1];
545 + chart = cg->st_mem_failcnt = rrdset_create_localhost(
546 + cgroup_chart_type(buff, cg),
547 + "mem_failcnt",
548 + NULL,
549 + "mem",
550 + context,
551 + title,
552 + "count",
553 + PLUGIN_CGROUPS_NAME,
554 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
555 + prio,
556 + cgroup_update_every,
557 + RRDSET_TYPE_LINE);
558 +
559 + rrdset_update_rrdlabels(chart, cg->chart_labels);
560 + rrddim_add(chart, "failures", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
561 + }
562 +
563 + rrddim_set(chart, "failures", (collected_number)cg->memory.failcnt);
564 + rrdset_done(chart);
565 +}
566 +
567 +void update_mem_usage_chart(struct cgroup *cg) {
568 + RRDSET *chart = cg->st_mem_usage;
569 +
570 + if (unlikely(!cg->st_mem_usage)) {
571 + char *title;
572 + char *context;
573 + int prio;
574 + if (is_cgroup_systemd_service(cg)) {
575 + title = "Systemd Services Used Memory";
576 + context = "systemd.service.memory.usage";
577 + prio = NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 5;
578 + } else {
579 + title = "Used Memory";
580 + context = k8s_is_kubepod(cg) ? "k8s.cgroup.mem_usage" : "cgroup.mem_usage";
581 + prio = cgroup_containers_chart_priority + 210;
582 + }
583 +
584 + char buff[RRD_ID_LENGTH_MAX + 1];
585 + chart = cg->st_mem_usage = rrdset_create_localhost(
586 + cgroup_chart_type(buff, cg),
587 + "mem_usage",
588 + NULL,
589 + "mem",
590 + context,
591 + title,
592 + "MiB",
593 + PLUGIN_CGROUPS_NAME,
594 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
595 + prio,
596 + cgroup_update_every,
597 + RRDSET_TYPE_STACKED);
598 +
599 + rrdset_update_rrdlabels(chart, cg->chart_labels);
600 +
601 + cg->st_mem_rd_ram = rrddim_add(chart, "ram", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
602 + cg->st_mem_rd_swap = rrddim_add(chart, "swap", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
603 + }
604 +
605 + rrddim_set_by_pointer(chart, cg->st_mem_rd_ram, (collected_number)cg->memory.usage_in_bytes);
606 +
607 + if (!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
608 + rrddim_set_by_pointer(
609 + chart,
610 + cg->st_mem_rd_swap,
611 + cg->memory.msw_usage_in_bytes > (cg->memory.usage_in_bytes + cg->memory.total_inactive_file) ?
612 + (collected_number)(cg->memory.msw_usage_in_bytes -
613 + (cg->memory.usage_in_bytes + cg->memory.total_inactive_file)) :
614 + 0);
615 + } else {
616 + rrddim_set_by_pointer(chart, cg->st_mem_rd_swap, (collected_number)cg->memory.msw_usage_in_bytes);
617 + }
618 +
619 + rrdset_done(chart);
620 +}
621 +
622 +void update_io_serviced_bytes_chart(struct cgroup *cg) {
623 + RRDSET *chart = cg->st_io;
624 +
625 + if (unlikely(!cg->st_io)) {
626 + char *title;
627 + char *context;
628 + int prio;
629 + if (is_cgroup_systemd_service(cg)) {
630 + title = "Systemd Services Disk Read/Write Bandwidth";
631 + context = "systemd.service.disk.io";
632 + prio = NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 35;
633 + } else {
634 + title = "I/O Bandwidth (all disks)";
635 + context = k8s_is_kubepod(cg) ? "k8s.cgroup.io" : "cgroup.io";
636 + prio = cgroup_containers_chart_priority + 1200;
637 + }
638 +
639 + char buff[RRD_ID_LENGTH_MAX + 1];
640 + chart = cg->st_io = rrdset_create_localhost(
641 + cgroup_chart_type(buff, cg),
642 + "io",
643 + NULL,
644 + "disk",
645 + context,
646 + title,
647 + "KiB/s",
648 + PLUGIN_CGROUPS_NAME,
649 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
650 + prio,
651 + cgroup_update_every,
652 + RRDSET_TYPE_AREA);
653 +
654 + rrdset_update_rrdlabels(chart, cg->chart_labels);
655 + cg->st_io_rd_read = rrddim_add(chart, "read", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
656 + cg->st_io_rd_written = rrddim_add(cg->st_io, "write", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
657 + }
658 +
659 + rrddim_set_by_pointer(chart, cg->st_io_rd_read, (collected_number)cg->io_service_bytes.Read);
660 + rrddim_set_by_pointer(chart, cg->st_io_rd_written, (collected_number)cg->io_service_bytes.Write);
661 + rrdset_done(chart);
662 +}
663 +
664 +void update_io_serviced_ops_chart(struct cgroup *cg) {
665 + RRDSET *chart = cg->st_serviced_ops;
666 +
667 + if (unlikely(!cg->st_serviced_ops)) {
668 + char *title;
669 + char *context;
670 + int prio;
671 + if (is_cgroup_systemd_service(cg)) {
672 + title = "Systemd Services Disk Read/Write Operations";
673 + context = "systemd.service.disk.iops";
674 + prio = NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 40;
675 + } else {
676 + title = "Serviced I/O Operations (all disks)";
677 + context = k8s_is_kubepod(cg) ? "k8s.cgroup.serviced_ops" : "cgroup.serviced_ops";
678 + prio = cgroup_containers_chart_priority + 1200;
679 + }
680 +
681 + char buff[RRD_ID_LENGTH_MAX + 1];
682 + chart = cg->st_serviced_ops = rrdset_create_localhost(
683 + cgroup_chart_type(buff, cg),
684 + "serviced_ops",
685 + NULL,
686 + "disk",
687 + context,
688 + title,
689 + "operations/s",
690 + PLUGIN_CGROUPS_NAME,
691 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
692 + prio,
693 + cgroup_update_every,
694 + RRDSET_TYPE_LINE);
695 +
696 + rrdset_update_rrdlabels(chart, cg->chart_labels);
697 + rrddim_add(chart, "read", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
698 + rrddim_add(chart, "write", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
699 + }
700 +
701 + rrddim_set(chart, "read", (collected_number)cg->io_serviced.Read);
702 + rrddim_set(chart, "write", (collected_number)cg->io_serviced.Write);
703 + rrdset_done(chart);
704 +}
705 +
706 +void update_throttle_io_serviced_bytes_chart(struct cgroup *cg) {
707 + RRDSET *chart = cg->st_throttle_io;
708 +
709 + if (unlikely(!cg->st_throttle_io)) {
710 + char *title;
711 + char *context;
712 + int prio;
713 + if (is_cgroup_systemd_service(cg)) {
714 + title = "Systemd Services Throttle Disk Read/Write Bandwidth";
715 + context = "systemd.service.disk.throttle.io";
716 + prio = NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 45;
717 + } else {
718 + title = "Throttle I/O Bandwidth (all disks)";
719 + context = k8s_is_kubepod(cg) ? "k8s.cgroup.throttle_io" : "cgroup.throttle_io";
720 + prio = cgroup_containers_chart_priority + 1200;
721 + }
722 +
723 + char buff[RRD_ID_LENGTH_MAX + 1];
724 + chart = cg->st_throttle_io = rrdset_create_localhost(
725 + cgroup_chart_type(buff, cg),
726 + "throttle_io",
727 + NULL,
728 + "disk",
729 + context,
730 + title,
731 + "KiB/s",
732 + PLUGIN_CGROUPS_NAME,
733 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
734 + prio,
735 + cgroup_update_every,
736 + RRDSET_TYPE_AREA);
737 +
738 + rrdset_update_rrdlabels(chart, cg->chart_labels);
739 +
740 + cg->st_throttle_io_rd_read = rrddim_add(chart, "read", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
741 + cg->st_throttle_io_rd_written = rrddim_add(chart, "write", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
742 + }
743 +
744 + rrddim_set_by_pointer(chart, cg->st_throttle_io_rd_read, (collected_number)cg->throttle_io_service_bytes.Read);
745 + rrddim_set_by_pointer(chart, cg->st_throttle_io_rd_written, (collected_number)cg->throttle_io_service_bytes.Write);
746 + rrdset_done(chart);
747 +}
748 +
749 +void update_throttle_io_serviced_ops_chart(struct cgroup *cg) {
750 + RRDSET *chart = cg->st_throttle_serviced_ops;
751 +
752 + if (unlikely(!cg->st_throttle_serviced_ops)) {
753 + char *title;
754 + char *context;
755 + int prio;
756 + if (is_cgroup_systemd_service(cg)) {
757 + title = "Systemd Services Throttle Disk Read/Write Operations";
758 + context = "systemd.service.disk.throttle.iops";
759 + prio = NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 50;
760 + } else {
761 + title = "Throttle Serviced I/O Operations (all disks)";
762 + context = k8s_is_kubepod(cg) ? "k8s.cgroup.throttle_serviced_ops" : "cgroup.throttle_serviced_ops";
763 + prio = cgroup_containers_chart_priority + 1200;
764 + }
765 +
766 + char buff[RRD_ID_LENGTH_MAX + 1];
767 + chart = cg->st_throttle_serviced_ops = rrdset_create_localhost(
768 + cgroup_chart_type(buff, cg),
769 + "throttle_serviced_ops",
770 + NULL,
771 + "disk",
772 + context,
773 + title,
774 + "operations/s",
775 + PLUGIN_CGROUPS_NAME,
776 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
777 + prio,
778 + cgroup_update_every,
779 + RRDSET_TYPE_LINE);
780 +
781 + rrdset_update_rrdlabels(chart, cg->chart_labels);
782 + rrddim_add(chart, "read", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
783 + rrddim_add(chart, "write", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
784 + }
785 +
786 + rrddim_set(chart, "read", (collected_number)cg->throttle_io_serviced.Read);
787 + rrddim_set(chart, "write", (collected_number)cg->throttle_io_serviced.Write);
788 + rrdset_done(chart);
789 +}
790 +
791 +void update_io_queued_ops_chart(struct cgroup *cg) {
792 + RRDSET *chart = cg->st_queued_ops;
793 +
794 + if (unlikely(!cg->st_queued_ops)) {
795 + char *title;
796 + char *context;
797 + int prio;
798 + if (is_cgroup_systemd_service(cg)) {
799 + title = "Systemd Services Queued Disk Read/Write Operations";
800 + context = "systemd.service.disk.queued_iops";
801 + prio = NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 55;
802 + } else {
803 + title = "Queued I/O Operations (all disks)";
804 + context = k8s_is_kubepod(cg) ? "k8s.cgroup.queued_ops" : "cgroup.queued_ops";
805 + prio = cgroup_containers_chart_priority + 2000;
806 + }
807 +
808 + char buff[RRD_ID_LENGTH_MAX + 1];
809 + chart = cg->st_queued_ops = rrdset_create_localhost(
810 + cgroup_chart_type(buff, cg),
811 + "queued_ops",
812 + NULL,
813 + "disk",
814 + context,
815 + title,
816 + "operations",
817 + PLUGIN_CGROUPS_NAME,
818 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
819 + prio,
820 + cgroup_update_every,
821 + RRDSET_TYPE_LINE);
822 +
823 + rrdset_update_rrdlabels(chart, cg->chart_labels);
824 + rrddim_add(chart, "read", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
825 + rrddim_add(chart, "write", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE);
826 + }
827 +
828 + rrddim_set(chart, "read", (collected_number)cg->io_queued.Read);
829 + rrddim_set(chart, "write", (collected_number)cg->io_queued.Write);
830 + rrdset_done(chart);
831 +}
832 +
833 +void update_io_merged_ops_chart(struct cgroup *cg) {
834 + RRDSET *chart = cg->st_merged_ops;
835 +
836 + if (unlikely(!cg->st_merged_ops)) {
837 + char *title;
838 + char *context;
839 + int prio;
840 + if (is_cgroup_systemd_service(cg)) {
841 + title = "Systemd Services Merged Disk Read/Write Operations";
842 + context = "systemd.service.disk.merged_iops";
843 + prio = NETDATA_CHART_PRIO_CGROUPS_SYSTEMD + 60;
844 + } else {
845 + title = "Merged I/O Operations (all disks)";
846 + context = k8s_is_kubepod(cg) ? "k8s.cgroup.merged_ops" : "cgroup.merged_ops";
847 + prio = cgroup_containers_chart_priority + 2100;
848 + }
849 +
850 + char buff[RRD_ID_LENGTH_MAX + 1];
851 + chart = cg->st_merged_ops = rrdset_create_localhost(
852 + cgroup_chart_type(buff, cg),
853 + "merged_ops",
854 + NULL,
855 + "disk",
856 + context,
857 + title,
858 + "operations/s",
859 + PLUGIN_CGROUPS_NAME,
860 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
861 + prio,
862 + cgroup_update_every,
863 + RRDSET_TYPE_LINE);
864 +
865 + rrdset_update_rrdlabels(chart, cg->chart_labels);
866 + rrddim_add(chart, "read", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
867 + rrddim_add(chart, "write", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
868 + }
869 +
870 + rrddim_set(chart, "read", (collected_number)cg->io_merged.Read);
871 + rrddim_set(chart, "write", (collected_number)cg->io_merged.Write);
872 + rrdset_done(chart);
873 +}
874 +
875 +void update_cpu_some_pressure_chart(struct cgroup *cg) {
876 + if (is_cgroup_systemd_service(cg))
877 + return;
878 +
879 + struct pressure *res = &cg->cpu_pressure;
880 + struct pressure_charts *pcs = &res->some;
881 + RRDSET *chart = pcs->share_time.st;
882 +
883 + if (unlikely(!pcs->share_time.st)) {
884 + char *title = "CPU some pressure";
885 + char *context = k8s_is_kubepod(cg) ? "k8s.cgroup.cpu_some_pressure" : "cgroup.cpu_some_pressure";
886 + int prio = cgroup_containers_chart_priority + 2200;
887 +
888 + char buff[RRD_ID_LENGTH_MAX + 1];
889 + chart = pcs->share_time.st = rrdset_create_localhost(
890 + cgroup_chart_type(buff, cg),
891 + "cpu_some_pressure",
892 + NULL,
893 + "cpu",
894 + context,
895 + title,
896 + "percentage",
897 + PLUGIN_CGROUPS_NAME,
898 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
899 + prio,
900 + cgroup_update_every,
901 + RRDSET_TYPE_LINE);
902 +
903 + rrdset_update_rrdlabels(chart, cg->chart_labels);
904 + pcs->share_time.rd10 = rrddim_add(chart, "some 10", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
905 + pcs->share_time.rd60 = rrddim_add(chart, "some 60", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
906 + pcs->share_time.rd300 = rrddim_add(chart, "some 300", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
907 + }
908 +
909 + rrddim_set_by_pointer(chart, pcs->share_time.rd10, (collected_number)(pcs->share_time.value10 * 100));
910 + rrddim_set_by_pointer(chart, pcs->share_time.rd60, (collected_number)(pcs->share_time.value60 * 100));
911 + rrddim_set_by_pointer(chart, pcs->share_time.rd300, (collected_number)(pcs->share_time.value300 * 100));
912 + rrdset_done(chart);
913 +}
914 +
915 +void update_cpu_some_pressure_stall_time_chart(struct cgroup *cg) {
916 + if (is_cgroup_systemd_service(cg))
917 + return;
918 +
919 + struct pressure *res = &cg->cpu_pressure;
920 + struct pressure_charts *pcs = &res->some;
921 + RRDSET *chart = pcs->total_time.st;
922 +
923 + if (unlikely(!pcs->total_time.st)) {
924 + char *title = "CPU some pressure stall time";
925 + char *context =
926 + k8s_is_kubepod(cg) ? "k8s.cgroup.cpu_some_pressure_stall_time" : "cgroup.cpu_some_pressure_stall_time";
927 + int prio = cgroup_containers_chart_priority + 2220;
928 +
929 + char buff[RRD_ID_LENGTH_MAX + 1];
930 + chart = pcs->total_time.st = rrdset_create_localhost(
931 + cgroup_chart_type(buff, cg),
932 + "cpu_some_pressure_stall_time",
933 + NULL,
934 + "cpu",
935 + context,
936 + title,
937 + "ms",
938 + PLUGIN_CGROUPS_NAME,
939 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
940 + prio,
941 + cgroup_update_every,
942 + RRDSET_TYPE_LINE);
943 + rrdset_update_rrdlabels(chart, cg->chart_labels);
944 + pcs->total_time.rdtotal = rrddim_add(chart, "time", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
945 + }
946 +
947 + rrddim_set_by_pointer(chart, pcs->total_time.rdtotal, (collected_number)(pcs->total_time.value_total));
948 + rrdset_done(chart);
949 +}
950 +
951 +void update_cpu_full_pressure_chart(struct cgroup *cg) {
952 + if (is_cgroup_systemd_service(cg))
953 + return;
954 +
955 + struct pressure *res = &cg->cpu_pressure;
956 + struct pressure_charts *pcs = &res->full;
957 + RRDSET *chart = pcs->share_time.st;
958 +
959 + if (unlikely(!pcs->share_time.st)) {
960 + char *title = "CPU full pressure";
961 + char *context = k8s_is_kubepod(cg) ? "k8s.cgroup.cpu_full_pressure" : "cgroup.cpu_full_pressure";
962 + int prio = cgroup_containers_chart_priority + 2240;
963 +
964 + char buff[RRD_ID_LENGTH_MAX + 1];
965 + chart = pcs->share_time.st = rrdset_create_localhost(
966 + cgroup_chart_type(buff, cg),
967 + "cpu_full_pressure",
968 + NULL,
969 + "cpu",
970 + context,
971 + title,
972 + "percentage",
973 + PLUGIN_CGROUPS_NAME,
974 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
975 + prio,
976 + cgroup_update_every,
977 + RRDSET_TYPE_LINE);
978 +
979 + rrdset_update_rrdlabels(chart, cg->chart_labels);
980 + pcs->share_time.rd10 = rrddim_add(chart, "full 10", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
981 + pcs->share_time.rd60 = rrddim_add(chart, "full 60", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
982 + pcs->share_time.rd300 = rrddim_add(chart, "full 300", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
983 + }
984 +
985 + rrddim_set_by_pointer(chart, pcs->share_time.rd10, (collected_number)(pcs->share_time.value10 * 100));
986 + rrddim_set_by_pointer(chart, pcs->share_time.rd60, (collected_number)(pcs->share_time.value60 * 100));
987 + rrddim_set_by_pointer(chart, pcs->share_time.rd300, (collected_number)(pcs->share_time.value300 * 100));
988 + rrdset_done(chart);
989 +}
990 +
991 +void update_cpu_full_pressure_stall_time_chart(struct cgroup *cg) {
992 + if (is_cgroup_systemd_service(cg))
993 + return;
994 +
995 + struct pressure *res = &cg->cpu_pressure;
996 + struct pressure_charts *pcs = &res->full;
997 + RRDSET *chart = pcs->total_time.st;
998 +
999 + if (unlikely(!pcs->total_time.st)) {
1000 + char *title = "CPU full pressure stall time";
1001 + char *context =
1002 + k8s_is_kubepod(cg) ? "k8s.cgroup.cpu_full_pressure_stall_time" : "cgroup.cpu_full_pressure_stall_time";
1003 + int prio = cgroup_containers_chart_priority + 2260;
1004 +
1005 + char buff[RRD_ID_LENGTH_MAX + 1];
1006 + chart = pcs->total_time.st = rrdset_create_localhost(
1007 + cgroup_chart_type(buff, cg),
1008 + "cpu_full_pressure_stall_time",
1009 + NULL,
1010 + "cpu",
1011 + context,
1012 + title,
1013 + "ms",
1014 + PLUGIN_CGROUPS_NAME,
1015 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
1016 + prio,
1017 + cgroup_update_every,
1018 + RRDSET_TYPE_LINE);
1019 +
1020 + rrdset_update_rrdlabels(chart, cg->chart_labels);
1021 + pcs->total_time.rdtotal = rrddim_add(chart, "time", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1022 + }
1023 +
1024 + rrddim_set_by_pointer(chart, pcs->total_time.rdtotal, (collected_number)(pcs->total_time.value_total));
1025 + rrdset_done(chart);
1026 +}
1027 +
1028 +void update_mem_some_pressure_chart(struct cgroup *cg) {
1029 + if (is_cgroup_systemd_service(cg))
1030 + return;
1031 +
1032 + struct pressure *res = &cg->memory_pressure;
1033 + struct pressure_charts *pcs = &res->some;
1034 + RRDSET *chart = pcs->share_time.st;
1035 +
1036 + if (unlikely(!pcs->share_time.st)) {
1037 + char *title = "Memory some pressure";
1038 + char *context = k8s_is_kubepod(cg) ? "k8s.cgroup.memory_some_pressure" : "cgroup.memory_some_pressure";
1039 + int prio = cgroup_containers_chart_priority + 2300;
1040 +
1041 + char buff[RRD_ID_LENGTH_MAX + 1];
1042 + chart = pcs->share_time.st = rrdset_create_localhost(
1043 + cgroup_chart_type(buff, cg),
1044 + "mem_some_pressure",
1045 + NULL,
1046 + "mem",
1047 + context,
1048 + title,
1049 + "percentage",
1050 + PLUGIN_CGROUPS_NAME,
1051 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
1052 + prio,
1053 + cgroup_update_every,
1054 + RRDSET_TYPE_LINE);
1055 +
1056 + rrdset_update_rrdlabels(chart, cg->chart_labels);
1057 + pcs->share_time.rd10 = rrddim_add(chart, "some 10", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1058 + pcs->share_time.rd60 = rrddim_add(chart, "some 60", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1059 + pcs->share_time.rd300 = rrddim_add(chart, "some 300", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1060 + }
1061 +
1062 + rrddim_set_by_pointer(chart, pcs->share_time.rd10, (collected_number)(pcs->share_time.value10 * 100));
1063 + rrddim_set_by_pointer(chart, pcs->share_time.rd60, (collected_number)(pcs->share_time.value60 * 100));
1064 + rrddim_set_by_pointer(chart, pcs->share_time.rd300, (collected_number)(pcs->share_time.value300 * 100));
1065 + rrdset_done(chart);
1066 +}
1067 +
1068 +void update_mem_some_pressure_stall_time_chart(struct cgroup *cg) {
1069 + if (is_cgroup_systemd_service(cg))
1070 + return;
1071 +
1072 + struct pressure *res = &cg->memory_pressure;
1073 + struct pressure_charts *pcs = &res->some;
1074 + RRDSET *chart = pcs->total_time.st;
1075 +
1076 + if (unlikely(!pcs->total_time.st)) {
1077 + char *title = "Memory some pressure stall time";
1078 + char *context = k8s_is_kubepod(cg) ? "k8s.cgroup.memory_some_pressure_stall_time" :
1079 + "cgroup.memory_some_pressure_stall_time";
1080 + int prio = cgroup_containers_chart_priority + 2320;
1081 +
1082 + char buff[RRD_ID_LENGTH_MAX + 1];
1083 + chart = pcs->total_time.st = rrdset_create_localhost(
1084 + cgroup_chart_type(buff, cg),
1085 + "memory_some_pressure_stall_time",
1086 + NULL,
1087 + "mem",
1088 + context,
1089 + title,
1090 + "ms",
1091 + PLUGIN_CGROUPS_NAME,
1092 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
1093 + prio,
1094 + cgroup_update_every,
1095 + RRDSET_TYPE_LINE);
1096 +
1097 + rrdset_update_rrdlabels(chart, cg->chart_labels);
1098 + pcs->total_time.rdtotal = rrddim_add(chart, "time", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1099 + }
1100 +
1101 + rrddim_set_by_pointer(chart, pcs->total_time.rdtotal, (collected_number)(pcs->total_time.value_total));
1102 + rrdset_done(chart);
1103 +}
1104 +
1105 +void update_mem_full_pressure_chart(struct cgroup *cg) {
1106 + if (is_cgroup_systemd_service(cg))
1107 + return;
1108 +
1109 + struct pressure *res = &cg->memory_pressure;
1110 + struct pressure_charts *pcs = &res->full;
1111 + RRDSET *chart = pcs->share_time.st;
1112 +
1113 + if (unlikely(!pcs->share_time.st)) {
1114 + char *title = "Memory full pressure";
1115 + char *context = k8s_is_kubepod(cg) ? "k8s.cgroup.memory_full_pressure" : "cgroup.memory_full_pressure";
1116 + int prio = cgroup_containers_chart_priority + 2340;
1117 +
1118 + char buff[RRD_ID_LENGTH_MAX + 1];
1119 + chart = pcs->share_time.st = rrdset_create_localhost(
1120 + cgroup_chart_type(buff, cg),
1121 + "mem_full_pressure",
1122 + NULL,
1123 + "mem",
1124 + context,
1125 + title,
1126 + "percentage",
1127 + PLUGIN_CGROUPS_NAME,
1128 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
1129 + prio,
1130 + cgroup_update_every,
1131 + RRDSET_TYPE_LINE);
1132 +
1133 + rrdset_update_rrdlabels(chart, cg->chart_labels);
1134 + pcs->share_time.rd10 = rrddim_add(chart, "full 10", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1135 + pcs->share_time.rd60 = rrddim_add(chart, "full 60", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1136 + pcs->share_time.rd300 = rrddim_add(chart, "full 300", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1137 + }
1138 +
1139 + rrddim_set_by_pointer(chart, pcs->share_time.rd10, (collected_number)(pcs->share_time.value10 * 100));
1140 + rrddim_set_by_pointer(chart, pcs->share_time.rd60, (collected_number)(pcs->share_time.value60 * 100));
1141 + rrddim_set_by_pointer(chart, pcs->share_time.rd300, (collected_number)(pcs->share_time.value300 * 100));
1142 + rrdset_done(chart);
1143 +}
1144 +
1145 +void update_mem_full_pressure_stall_time_chart(struct cgroup *cg) {
1146 + if (is_cgroup_systemd_service(cg))
1147 + return;
1148 +
1149 + struct pressure *res = &cg->memory_pressure;
1150 + struct pressure_charts *pcs = &res->full;
1151 + RRDSET *chart = pcs->total_time.st;
1152 +
1153 + if (unlikely(!pcs->total_time.st)) {
1154 + char *title = "Memory full pressure stall time";
1155 + char *context = k8s_is_kubepod(cg) ? "k8s.cgroup.memory_full_pressure_stall_time" :
1156 + "cgroup.memory_full_pressure_stall_time";
1157 + int prio = cgroup_containers_chart_priority + 2360;
1158 +
1159 + char buff[RRD_ID_LENGTH_MAX + 1];
1160 + chart = pcs->total_time.st = rrdset_create_localhost(
1161 + cgroup_chart_type(buff, cg),
1162 + "memory_full_pressure_stall_time",
1163 + NULL,
1164 + "mem",
1165 + context,
1166 + title,
1167 + "ms",
1168 + PLUGIN_CGROUPS_NAME,
1169 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
1170 + prio,
1171 + cgroup_update_every,
1172 + RRDSET_TYPE_LINE);
1173 + rrdset_update_rrdlabels(chart, cg->chart_labels);
1174 + pcs->total_time.rdtotal = rrddim_add(chart, "time", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1175 + }
1176 +
1177 + rrddim_set_by_pointer(chart, pcs->total_time.rdtotal, (collected_number)(pcs->total_time.value_total));
1178 + rrdset_done(chart);
1179 +}
1180 +
1181 +void update_irq_some_pressure_chart(struct cgroup *cg) {
1182 + if (is_cgroup_systemd_service(cg))
1183 + return;
1184 +
1185 + struct pressure *res = &cg->irq_pressure;
1186 + struct pressure_charts *pcs = &res->some;
1187 + RRDSET *chart = pcs->share_time.st;
1188 +
1189 + if (unlikely(!pcs->share_time.st)) {
1190 + char *title = "IRQ some pressure";
1191 + char *context = k8s_is_kubepod(cg) ? "k8s.cgroup.irq_some_pressure" : "cgroup.irq_some_pressure";
1192 + int prio = cgroup_containers_chart_priority + 2310;
1193 +
1194 + char buff[RRD_ID_LENGTH_MAX + 1];
1195 + chart = pcs->share_time.st = rrdset_create_localhost(
1196 + cgroup_chart_type(buff, cg),
1197 + "irq_some_pressure",
1198 + NULL,
1199 + "interrupts",
1200 + context,
1201 + title,
1202 + "percentage",
1203 + PLUGIN_CGROUPS_NAME,
1204 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
1205 + prio,
1206 + cgroup_update_every,
1207 + RRDSET_TYPE_LINE);
1208 +
1209 + rrdset_update_rrdlabels(chart, cg->chart_labels);
1210 + pcs->share_time.rd10 = rrddim_add(chart, "some 10", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1211 + pcs->share_time.rd60 = rrddim_add(chart, "some 60", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1212 + pcs->share_time.rd300 = rrddim_add(chart, "some 300", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1213 + }
1214 +
1215 + rrddim_set_by_pointer(chart, pcs->share_time.rd10, (collected_number)(pcs->share_time.value10 * 100));
1216 + rrddim_set_by_pointer(chart, pcs->share_time.rd60, (collected_number)(pcs->share_time.value60 * 100));
1217 + rrddim_set_by_pointer(chart, pcs->share_time.rd300, (collected_number)(pcs->share_time.value300 * 100));
1218 + rrdset_done(chart);
1219 +}
1220 +
1221 +void update_irq_some_pressure_stall_time_chart(struct cgroup *cg) {
1222 + if (is_cgroup_systemd_service(cg))
1223 + return;
1224 +
1225 + struct pressure *res = &cg->irq_pressure;
1226 + struct pressure_charts *pcs = &res->some;
1227 + RRDSET *chart = pcs->total_time.st;
1228 +
1229 + if (unlikely(!pcs->total_time.st)) {
1230 + char *title = "IRQ some pressure stall time";
1231 + char *context =
1232 + k8s_is_kubepod(cg) ? "k8s.cgroup.irq_some_pressure_stall_time" : "cgroup.irq_some_pressure_stall_time";
1233 + int prio = cgroup_containers_chart_priority + 2330;
1234 +
1235 + char buff[RRD_ID_LENGTH_MAX + 1];
1236 + chart = pcs->total_time.st = rrdset_create_localhost(
1237 + cgroup_chart_type(buff, cg),
1238 + "irq_some_pressure_stall_time",
1239 + NULL,
1240 + "interrupts",
1241 + context,
1242 + title,
1243 + "ms",
1244 + PLUGIN_CGROUPS_NAME,
1245 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
1246 + prio,
1247 + cgroup_update_every,
1248 + RRDSET_TYPE_LINE);
1249 +
1250 + rrdset_update_rrdlabels(chart, cg->chart_labels);
1251 + pcs->total_time.rdtotal = rrddim_add(chart, "time", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1252 + }
1253 +
1254 + rrddim_set_by_pointer(chart, pcs->total_time.rdtotal, (collected_number)(pcs->total_time.value_total));
1255 + rrdset_done(chart);
1256 +}
1257 +
1258 +void update_irq_full_pressure_chart(struct cgroup *cg) {
1259 + if (is_cgroup_systemd_service(cg))
1260 + return;
1261 +
1262 + struct pressure *res = &cg->irq_pressure;
1263 + struct pressure_charts *pcs = &res->full;
1264 + RRDSET *chart = pcs->share_time.st;
1265 +
1266 + if (unlikely(!pcs->share_time.st)) {
1267 + char *title = "IRQ full pressure";
1268 + char *context = k8s_is_kubepod(cg) ? "k8s.cgroup.irq_full_pressure" : "cgroup.irq_full_pressure";
1269 + int prio = cgroup_containers_chart_priority + 2350;
1270 +
1271 + char buff[RRD_ID_LENGTH_MAX + 1];
1272 + chart = pcs->share_time.st = rrdset_create_localhost(
1273 + cgroup_chart_type(buff, cg),
1274 + "irq_full_pressure",
1275 + NULL,
1276 + "interrupts",
1277 + context,
1278 + title,
1279 + "percentage",
1280 + PLUGIN_CGROUPS_NAME,
1281 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
1282 + prio,
1283 + cgroup_update_every,
1284 + RRDSET_TYPE_LINE);
1285 +
1286 + rrdset_update_rrdlabels(chart, cg->chart_labels);
1287 + pcs->share_time.rd10 = rrddim_add(chart, "full 10", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1288 + pcs->share_time.rd60 = rrddim_add(chart, "full 60", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1289 + pcs->share_time.rd300 = rrddim_add(chart, "full 300", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1290 + }
1291 +
1292 + rrddim_set_by_pointer(chart, pcs->share_time.rd10, (collected_number)(pcs->share_time.value10 * 100));
1293 + rrddim_set_by_pointer(chart, pcs->share_time.rd60, (collected_number)(pcs->share_time.value60 * 100));
1294 + rrddim_set_by_pointer(chart, pcs->share_time.rd300, (collected_number)(pcs->share_time.value300 * 100));
1295 + rrdset_done(chart);
1296 +}
1297 +
1298 +void update_irq_full_pressure_stall_time_chart(struct cgroup *cg) {
1299 + if (is_cgroup_systemd_service(cg))
1300 + return;
1301 +
1302 + struct pressure *res = &cg->irq_pressure;
1303 + struct pressure_charts *pcs = &res->full;
1304 + RRDSET *chart = pcs->total_time.st;
1305 +
1306 + if (unlikely(!pcs->total_time.st)) {
1307 + char *title = "IRQ full pressure stall time";
1308 + char *context =
1309 + k8s_is_kubepod(cg) ? "k8s.cgroup.irq_full_pressure_stall_time" : "cgroup.irq_full_pressure_stall_time";
1310 + int prio = cgroup_containers_chart_priority + 2370;
1311 +
1312 + char buff[RRD_ID_LENGTH_MAX + 1];
1313 + chart = pcs->total_time.st = rrdset_create_localhost(
1314 + cgroup_chart_type(buff, cg),
1315 + "irq_full_pressure_stall_time",
1316 + NULL,
1317 + "interrupts",
1318 + context,
1319 + title,
1320 + "ms",
1321 + PLUGIN_CGROUPS_NAME,
1322 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
1323 + prio,
1324 + cgroup_update_every,
1325 + RRDSET_TYPE_LINE);
1326 +
1327 + rrdset_update_rrdlabels(chart, cg->chart_labels);
1328 + pcs->total_time.rdtotal = rrddim_add(chart, "time", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1329 + }
1330 +
1331 + rrddim_set_by_pointer(chart, pcs->total_time.rdtotal, (collected_number)(pcs->total_time.value_total));
1332 + rrdset_done(chart);
1333 +}
1334 +
1335 +void update_io_some_pressure_chart(struct cgroup *cg) {
1336 + if (is_cgroup_systemd_service(cg))
1337 + return;
1338 +
1339 + struct pressure *res = &cg->io_pressure;
1340 + struct pressure_charts *pcs = &res->some;
1341 + RRDSET *chart = pcs->share_time.st;
1342 +
1343 + if (unlikely(!pcs->share_time.st)) {
1344 + char *title = "I/O some pressure";
1345 + char *context = k8s_is_kubepod(cg) ? "k8s.cgroup.io_some_pressure" : "cgroup.io_some_pressure";
1346 + int prio = cgroup_containers_chart_priority + 2400;
1347 +
1348 + char buff[RRD_ID_LENGTH_MAX + 1];
1349 + chart = pcs->share_time.st = rrdset_create_localhost(
1350 + cgroup_chart_type(buff, cg),
1351 + "io_some_pressure",
1352 + NULL,
1353 + "disk",
1354 + context,
1355 + title,
1356 + "percentage",
1357 + PLUGIN_CGROUPS_NAME,
1358 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
1359 + prio,
1360 + cgroup_update_every,
1361 + RRDSET_TYPE_LINE);
1362 +
1363 + rrdset_update_rrdlabels(chart, cg->chart_labels);
1364 + pcs->share_time.rd10 = rrddim_add(chart, "some 10", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1365 + pcs->share_time.rd60 = rrddim_add(chart, "some 60", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1366 + pcs->share_time.rd300 = rrddim_add(chart, "some 300", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1367 + }
1368 +
1369 + rrddim_set_by_pointer(chart, pcs->share_time.rd10, (collected_number)(pcs->share_time.value10 * 100));
1370 + rrddim_set_by_pointer(chart, pcs->share_time.rd60, (collected_number)(pcs->share_time.value60 * 100));
1371 + rrddim_set_by_pointer(chart, pcs->share_time.rd300, (collected_number)(pcs->share_time.value300 * 100));
1372 + rrdset_done(chart);
1373 +}
1374 +
1375 +void update_io_some_pressure_stall_time_chart(struct cgroup *cg) {
1376 + if (is_cgroup_systemd_service(cg))
1377 + return;
1378 +
1379 + struct pressure *res = &cg->io_pressure;
1380 + struct pressure_charts *pcs = &res->some;
1381 + RRDSET *chart = pcs->total_time.st;
1382 +
1383 + if (unlikely(!pcs->total_time.st)) {
1384 + char *title = "I/O some pressure stall time";
1385 + char *context =
1386 + k8s_is_kubepod(cg) ? "k8s.cgroup.io_some_pressure_stall_time" : "cgroup.io_some_pressure_stall_time";
1387 + int prio = cgroup_containers_chart_priority + 2420;
1388 +
1389 + char buff[RRD_ID_LENGTH_MAX + 1];
1390 + chart = pcs->total_time.st = rrdset_create_localhost(
1391 + cgroup_chart_type(buff, cg),
1392 + "io_some_pressure_stall_time",
1393 + NULL,
1394 + "disk",
1395 + context,
1396 + title,
1397 + "ms",
1398 + PLUGIN_CGROUPS_NAME,
1399 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
1400 + prio,
1401 + cgroup_update_every,
1402 + RRDSET_TYPE_LINE);
1403 + rrdset_update_rrdlabels(chart, cg->chart_labels);
1404 + pcs->total_time.rdtotal = rrddim_add(chart, "time", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1405 + }
1406 +
1407 + rrddim_set_by_pointer(chart, pcs->total_time.rdtotal, (collected_number)(pcs->total_time.value_total));
1408 + rrdset_done(chart);
1409 +}
1410 +
1411 +void update_io_full_pressure_chart(struct cgroup *cg) {
1412 + if (is_cgroup_systemd_service(cg))
1413 + return;
1414 +
1415 + struct pressure *res = &cg->io_pressure;
1416 + struct pressure_charts *pcs = &res->full;
1417 + RRDSET *chart = pcs->share_time.st;
1418 +
1419 + if (unlikely(!pcs->share_time.st)) {
1420 + char *title = "I/O full pressure";
1421 + char *context = k8s_is_kubepod(cg) ? "k8s.cgroup.io_full_pressure" : "cgroup.io_full_pressure";
1422 + int prio = cgroup_containers_chart_priority + 2440;
1423 +
1424 + char buff[RRD_ID_LENGTH_MAX + 1];
1425 + chart = pcs->share_time.st = rrdset_create_localhost(
1426 + cgroup_chart_type(buff, cg),
1427 + "io_full_pressure",
1428 + NULL,
1429 + "disk",
1430 + context,
1431 + title,
1432 + "percentage",
1433 + PLUGIN_CGROUPS_NAME,
1434 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
1435 + prio,
1436 + cgroup_update_every,
1437 + RRDSET_TYPE_LINE);
1438 +
1439 + rrdset_update_rrdlabels(chart, cg->chart_labels);
1440 + pcs->share_time.rd10 = rrddim_add(chart, "full 10", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1441 + pcs->share_time.rd60 = rrddim_add(chart, "full 60", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1442 + pcs->share_time.rd300 = rrddim_add(chart, "full 300", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1443 + }
1444 +
1445 + rrddim_set_by_pointer(chart, pcs->share_time.rd10, (collected_number)(pcs->share_time.value10 * 100));
1446 + rrddim_set_by_pointer(chart, pcs->share_time.rd60, (collected_number)(pcs->share_time.value60 * 100));
1447 + rrddim_set_by_pointer(chart, pcs->share_time.rd300, (collected_number)(pcs->share_time.value300 * 100));
1448 + rrdset_done(chart);
1449 +}
1450 +
1451 +void update_io_full_pressure_stall_time_chart(struct cgroup *cg) {
1452 + if (is_cgroup_systemd_service(cg))
1453 + return;
1454 +
1455 + struct pressure *res = &cg->io_pressure;
1456 + struct pressure_charts *pcs = &res->full;
1457 + RRDSET *chart = pcs->total_time.st;
1458 +
1459 + if (unlikely(!pcs->total_time.st)) {
1460 + char *title = "I/O full pressure stall time";
1461 + char *context =
1462 + k8s_is_kubepod(cg) ? "k8s.cgroup.io_full_pressure_stall_time" : "cgroup.io_full_pressure_stall_time";
1463 + int prio = cgroup_containers_chart_priority + 2460;
1464 +
1465 + char buff[RRD_ID_LENGTH_MAX + 1];
1466 + chart = pcs->total_time.st = rrdset_create_localhost(
1467 + cgroup_chart_type(buff, cg),
1468 + "io_full_pressure_stall_time",
1469 + NULL,
1470 + "disk",
1471 + context,
1472 + title,
1473 + "ms",
1474 + PLUGIN_CGROUPS_NAME,
1475 + is_cgroup_systemd_service(cg) ? PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME : PLUGIN_CGROUPS_MODULE_CGROUPS_NAME,
1476 + prio,
1477 + cgroup_update_every,
1478 + RRDSET_TYPE_LINE);
1479 +
1480 + rrdset_update_rrdlabels(chart, cg->chart_labels);
1481 + pcs->total_time.rdtotal = rrddim_add(chart, "time", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1482 + }
1483 +
1484 + rrddim_set_by_pointer(chart, pcs->total_time.rdtotal, (collected_number)(pcs->total_time.value_total));
1485 + rrdset_done(chart);
1486 +}
collectors/cgroups.plugin/cgroup-discovery.c new
+1226
@@ -0,0 +1,1226 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "cgroup-internals.h"
4 +
5 +// discovery cgroup thread worker jobs
6 +#define WORKER_DISCOVERY_INIT 0
7 +#define WORKER_DISCOVERY_FIND 1
8 +#define WORKER_DISCOVERY_PROCESS 2
9 +#define WORKER_DISCOVERY_PROCESS_RENAME 3
10 +#define WORKER_DISCOVERY_PROCESS_NETWORK 4
11 +#define WORKER_DISCOVERY_PROCESS_FIRST_TIME 5
12 +#define WORKER_DISCOVERY_UPDATE 6
13 +#define WORKER_DISCOVERY_CLEANUP 7
14 +#define WORKER_DISCOVERY_COPY 8
15 +#define WORKER_DISCOVERY_SHARE 9
16 +#define WORKER_DISCOVERY_LOCK 10
17 +
18 +#if WORKER_UTILIZATION_MAX_JOB_TYPES < 11
19 +#error WORKER_UTILIZATION_MAX_JOB_TYPES has to be at least 11
20 +#endif
21 +
22 +struct cgroup *discovered_cgroup_root = NULL;
23 +
24 +char cgroup_chart_id_prefix[] = "cgroup_";
25 +char services_chart_id_prefix[] = "systemd_";
26 +char *cgroups_rename_script = NULL;
27 +
28 +
29 +// ----------------------------------------------------------------------------
30 +
31 +static inline void free_pressure(struct pressure *res) {
32 + if (res->some.share_time.st) rrdset_is_obsolete___safe_from_collector_thread(res->some.share_time.st);
33 + if (res->some.total_time.st) rrdset_is_obsolete___safe_from_collector_thread(res->some.total_time.st);
34 + if (res->full.share_time.st) rrdset_is_obsolete___safe_from_collector_thread(res->full.share_time.st);
35 + if (res->full.total_time.st) rrdset_is_obsolete___safe_from_collector_thread(res->full.total_time.st);
36 + freez(res->filename);
37 +}
38 +
39 +static inline void cgroup_free_network_interfaces(struct cgroup *cg) {
40 + while(cg->interfaces) {
41 + struct cgroup_network_interface *i = cg->interfaces;
42 + cg->interfaces = i->next;
43 +
44 + // delete the registration of proc_net_dev rename
45 + netdev_rename_device_del(i->host_device);
46 +
47 + freez((void *)i->host_device);
48 + freez((void *)i->container_device);
49 + freez((void *)i);
50 + }
51 +}
52 +
53 +static inline void cgroup_free(struct cgroup *cg) {
54 + netdata_log_debug(D_CGROUP, "Removing cgroup '%s' with chart id '%s' (was %s and %s)", cg->id, cg->chart_id, (cg->enabled)?"enabled":"disabled", (cg->available)?"available":"not available");
55 +
56 + cgroup_netdev_delete(cg);
57 +
58 + if(cg->st_cpu) rrdset_is_obsolete___safe_from_collector_thread(cg->st_cpu);
59 + if(cg->st_cpu_limit) rrdset_is_obsolete___safe_from_collector_thread(cg->st_cpu_limit);
60 + if(cg->st_cpu_per_core) rrdset_is_obsolete___safe_from_collector_thread(cg->st_cpu_per_core);
61 + if(cg->st_cpu_nr_throttled) rrdset_is_obsolete___safe_from_collector_thread(cg->st_cpu_nr_throttled);
62 + if(cg->st_cpu_throttled_time) rrdset_is_obsolete___safe_from_collector_thread(cg->st_cpu_throttled_time);
63 + if(cg->st_cpu_shares) rrdset_is_obsolete___safe_from_collector_thread(cg->st_cpu_shares);
64 + if(cg->st_mem) rrdset_is_obsolete___safe_from_collector_thread(cg->st_mem);
65 + if(cg->st_writeback) rrdset_is_obsolete___safe_from_collector_thread(cg->st_writeback);
66 + if(cg->st_mem_activity) rrdset_is_obsolete___safe_from_collector_thread(cg->st_mem_activity);
67 + if(cg->st_pgfaults) rrdset_is_obsolete___safe_from_collector_thread(cg->st_pgfaults);
68 + if(cg->st_mem_usage) rrdset_is_obsolete___safe_from_collector_thread(cg->st_mem_usage);
69 + if(cg->st_mem_usage_limit) rrdset_is_obsolete___safe_from_collector_thread(cg->st_mem_usage_limit);
70 + if(cg->st_mem_utilization) rrdset_is_obsolete___safe_from_collector_thread(cg->st_mem_utilization);
71 + if(cg->st_mem_failcnt) rrdset_is_obsolete___safe_from_collector_thread(cg->st_mem_failcnt);
72 + if(cg->st_io) rrdset_is_obsolete___safe_from_collector_thread(cg->st_io);
73 + if(cg->st_serviced_ops) rrdset_is_obsolete___safe_from_collector_thread(cg->st_serviced_ops);
74 + if(cg->st_throttle_io) rrdset_is_obsolete___safe_from_collector_thread(cg->st_throttle_io);
75 + if(cg->st_throttle_serviced_ops) rrdset_is_obsolete___safe_from_collector_thread(cg->st_throttle_serviced_ops);
76 + if(cg->st_queued_ops) rrdset_is_obsolete___safe_from_collector_thread(cg->st_queued_ops);
77 + if(cg->st_merged_ops) rrdset_is_obsolete___safe_from_collector_thread(cg->st_merged_ops);
78 +
79 + freez(cg->filename_cpuset_cpus);
80 + freez(cg->filename_cpu_cfs_period);
81 + freez(cg->filename_cpu_cfs_quota);
82 + freez(cg->filename_memory_limit);
83 + freez(cg->filename_memoryswap_limit);
84 +
85 + cgroup_free_network_interfaces(cg);
86 +
87 + freez(cg->cpuacct_usage.cpu_percpu);
88 +
89 + freez(cg->cpuacct_stat.filename);
90 + freez(cg->cpuacct_usage.filename);
91 + freez(cg->cpuacct_cpu_throttling.filename);
92 + freez(cg->cpuacct_cpu_shares.filename);
93 +
94 + arl_free(cg->memory.arl_base);
95 + freez(cg->memory.filename_detailed);
96 + freez(cg->memory.filename_failcnt);
97 + freez(cg->memory.filename_usage_in_bytes);
98 + freez(cg->memory.filename_msw_usage_in_bytes);
99 +
100 + freez(cg->io_service_bytes.filename);
101 + freez(cg->io_serviced.filename);
102 +
103 + freez(cg->throttle_io_service_bytes.filename);
104 + freez(cg->throttle_io_serviced.filename);
105 +
106 + freez(cg->io_merged.filename);
107 + freez(cg->io_queued.filename);
108 +
109 + free_pressure(&cg->cpu_pressure);
110 + free_pressure(&cg->io_pressure);
111 + free_pressure(&cg->memory_pressure);
112 + free_pressure(&cg->irq_pressure);
113 +
114 + freez(cg->id);
115 + freez(cg->intermediate_id);
116 + freez(cg->chart_id);
117 + freez(cg->name);
118 +
119 + rrdlabels_destroy(cg->chart_labels);
120 +
121 + freez(cg);
122 +
123 + cgroup_root_count--;
124 +}
125 +
126 +// ----------------------------------------------------------------------------
127 +// add/remove/find cgroup objects
128 +
129 +#define CGROUP_CHARTID_LINE_MAX 1024
130 +
131 +static inline char *cgroup_chart_id_strdupz(const char *s) {
132 + if(!s || !*s) s = "/";
133 +
134 + if(*s == '/' && s[1] != '\0') s++;
135 +
136 + char *r = strdupz(s);
137 + netdata_fix_chart_id(r);
138 +
139 + return r;
140 +}
141 +
142 +// TODO: move the code to cgroup_chart_id_strdupz() when the renaming script is fixed
143 +static inline void substitute_dots_in_id(char *s) {
144 + // dots are used to distinguish chart type and id in streaming, so we should replace them
145 + for (char *d = s; *d; d++) {
146 + if (*d == '.')
147 + *d = '-';
148 + }
149 +}
150 +
151 +// ----------------------------------------------------------------------------
152 +// parse k8s labels
153 +
154 +char *cgroup_parse_resolved_name_and_labels(RRDLABELS *labels, char *data) {
155 + // the first word, up to the first space is the name
156 + char *name = strsep_skip_consecutive_separators(&data, " ");
157 +
158 + // the rest are key=value pairs separated by comma
159 + while(data) {
160 + char *pair = strsep_skip_consecutive_separators(&data, ",");
161 + rrdlabels_add_pair(labels, pair, RRDLABEL_SRC_AUTO | RRDLABEL_SRC_K8S);
162 + }
163 +
164 + return name;
165 +}
166 +
167 +static inline void discovery_rename_cgroup(struct cgroup *cg) {
168 + if (!cg->pending_renames) {
169 + return;
170 + }
171 + cg->pending_renames--;
172 +
173 + netdata_log_debug(D_CGROUP, "looking for the name of cgroup '%s' with chart id '%s'", cg->id, cg->chart_id);
174 + netdata_log_debug(D_CGROUP, "executing command %s \"%s\" for cgroup '%s'", cgroups_rename_script, cg->intermediate_id, cg->chart_id);
175 + pid_t cgroup_pid;
176 +
177 + FILE *fp_child_input, *fp_child_output;
178 + (void)netdata_popen_raw_default_flags_and_environment(&cgroup_pid, &fp_child_input, &fp_child_output, cgroups_rename_script, cg->id, cg->intermediate_id);
179 + if (!fp_child_output) {
180 + collector_error("CGROUP: cannot popen(%s \"%s\", \"r\").", cgroups_rename_script, cg->intermediate_id);
181 + cg->pending_renames = 0;
182 + cg->processed = 1;
183 + return;
184 + }
185 +
186 + char buffer[CGROUP_CHARTID_LINE_MAX + 1];
187 + char *new_name = fgets(buffer, CGROUP_CHARTID_LINE_MAX, fp_child_output);
188 + int exit_code = netdata_pclose(fp_child_input, fp_child_output, cgroup_pid);
189 +
190 + switch (exit_code) {
191 + case 0:
192 + cg->pending_renames = 0;
193 + break;
194 +
195 + case 3:
196 + cg->pending_renames = 0;
197 + cg->processed = 1;
198 + break;
199 +
200 + default:
201 + break;
202 + }
203 +
204 + if (cg->pending_renames || cg->processed)
205 + return;
206 + if (!new_name || !*new_name || *new_name == '\n')
207 + return;
208 + if (!(new_name = trim(new_name)))
209 + return;
210 +
211 + if (!cg->chart_labels)
212 + cg->chart_labels = rrdlabels_create();
213 + // read the new labels and remove the obsolete ones
214 + rrdlabels_unmark_all(cg->chart_labels);
215 + char *name = cgroup_parse_resolved_name_and_labels(cg->chart_labels, new_name);
216 + rrdlabels_remove_all_unmarked(cg->chart_labels);
217 +
218 + freez(cg->name);
219 + cg->name = strdupz(name);
220 +
221 + freez(cg->chart_id);
222 + cg->chart_id = cgroup_chart_id_strdupz(name);
223 +
224 + substitute_dots_in_id(cg->chart_id);
225 + cg->hash_chart_id = simple_hash(cg->chart_id);
226 +}
227 +
228 +static void is_cgroup_procs_exist(netdata_ebpf_cgroup_shm_body_t *out, char *id) {
229 + struct stat buf;
230 +
231 + snprintfz(out->path, FILENAME_MAX, "%s%s/cgroup.procs", cgroup_cpuset_base, id);
232 + if (likely(stat(out->path, &buf) == 0)) {
233 + return;
234 + }
235 +
236 + snprintfz(out->path, FILENAME_MAX, "%s%s/cgroup.procs", cgroup_blkio_base, id);
237 + if (likely(stat(out->path, &buf) == 0)) {
238 + return;
239 + }
240 +
241 + snprintfz(out->path, FILENAME_MAX, "%s%s/cgroup.procs", cgroup_memory_base, id);
242 + if (likely(stat(out->path, &buf) == 0)) {
243 + return;
244 + }
245 +
246 + snprintfz(out->path, FILENAME_MAX, "%s%s/cgroup.procs", cgroup_devices_base, id);
247 + if (likely(stat(out->path, &buf) == 0)) {
248 + return;
249 + }
250 +
251 + out->path[0] = '\0';
252 + out->enabled = 0;
253 +}
254 +
255 +static inline void convert_cgroup_to_systemd_service(struct cgroup *cg) {
256 + char buffer[CGROUP_CHARTID_LINE_MAX + 1];
257 + cg->options |= CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE;
258 + strncpyz(buffer, cg->id, CGROUP_CHARTID_LINE_MAX);
259 + char *s = buffer;
260 +
261 + // skip to the last slash
262 + size_t len = strlen(s);
263 + while (len--) {
264 + if (unlikely(s[len] == '/')) {
265 + break;
266 + }
267 + }
268 + if (len) {
269 + s = &s[len + 1];
270 + }
271 +
272 + // remove extension
273 + len = strlen(s);
274 + while (len--) {
275 + if (unlikely(s[len] == '.')) {
276 + break;
277 + }
278 + }
279 + if (len) {
280 + s[len] = '\0';
281 + }
282 +
283 + freez(cg->name);
284 + cg->name = strdupz(s);
285 +
286 + freez(cg->chart_id);
287 + cg->chart_id = cgroup_chart_id_strdupz(s);
288 + substitute_dots_in_id(cg->chart_id);
289 + cg->hash_chart_id = simple_hash(cg->chart_id);
290 +}
291 +
292 +static inline struct cgroup *discovery_cgroup_add(const char *id) {
293 + netdata_log_debug(D_CGROUP, "adding to list, cgroup with id '%s'", id);
294 +
295 + struct cgroup *cg = callocz(1, sizeof(struct cgroup));
296 +
297 + cg->id = strdupz(id);
298 + cg->hash = simple_hash(cg->id);
299 +
300 + cg->name = strdupz(id);
301 +
302 + cg->intermediate_id = cgroup_chart_id_strdupz(id);
303 +
304 + cg->chart_id = cgroup_chart_id_strdupz(id);
305 + substitute_dots_in_id(cg->chart_id);
306 + cg->hash_chart_id = simple_hash(cg->chart_id);
307 +
308 + if (cgroup_use_unified_cgroups) {
309 + cg->options |= CGROUP_OPTIONS_IS_UNIFIED;
310 + }
311 +
312 + if (!discovered_cgroup_root)
313 + discovered_cgroup_root = cg;
314 + else {
315 + struct cgroup *t;
316 + for (t = discovered_cgroup_root; t->discovered_next; t = t->discovered_next) {
317 + }
318 + t->discovered_next = cg;
319 + }
320 +
321 + return cg;
322 +}
323 +
324 +static inline struct cgroup *discovery_cgroup_find(const char *id) {
325 + netdata_log_debug(D_CGROUP, "searching for cgroup '%s'", id);
326 +
327 + uint32_t hash = simple_hash(id);
328 +
329 + struct cgroup *cg;
330 + for(cg = discovered_cgroup_root; cg ; cg = cg->discovered_next) {
331 + if(hash == cg->hash && strcmp(id, cg->id) == 0)
332 + break;
333 + }
334 +
335 + netdata_log_debug(D_CGROUP, "cgroup '%s' %s in memory", id, (cg)?"found":"not found");
336 + return cg;
337 +}
338 +
339 +static int calc_cgroup_depth(const char *id) {
340 + int depth = 0;
341 + const char *s;
342 + for (s = id; *s; s++) {
343 + depth += unlikely(*s == '/');
344 + }
345 + return depth;
346 +}
347 +
348 +static inline void discovery_find_cgroup_in_dir_callback(const char *dir) {
349 + if (!dir || !*dir) {
350 + dir = "/";
351 + }
352 + netdata_log_debug(D_CGROUP, "examining cgroup dir '%s'", dir);
353 +
354 + struct cgroup *cg = discovery_cgroup_find(dir);
355 + if (cg) {
356 + cg->available = 1;
357 + return;
358 + }
359 +
360 + if (cgroup_root_count >= cgroup_root_max) {
361 + collector_info("CGROUP: maximum number of cgroups reached (%d). Not adding cgroup '%s'", cgroup_root_count, dir);
362 + return;
363 + }
364 +
365 + if (cgroup_max_depth > 0) {
366 + int depth = calc_cgroup_depth(dir);
367 + if (depth > cgroup_max_depth) {
368 + collector_info("CGROUP: '%s' is too deep (%d, while max is %d)", dir, depth, cgroup_max_depth);
369 + return;
370 + }
371 + }
372 +
373 + cg = discovery_cgroup_add(dir);
374 + cg->available = 1;
375 + cg->first_time_seen = 1;
376 + cg->function_ready = false;
377 + cgroup_root_count++;
378 +}
379 +
380 +static inline int discovery_find_dir_in_subdirs(const char *base, const char *this, void (*callback)(const char *)) {
381 + if(!this) this = base;
382 + netdata_log_debug(D_CGROUP, "searching for directories in '%s' (base '%s')", this?this:"", base);
383 +
384 + size_t dirlen = strlen(this), baselen = strlen(base);
385 +
386 + int ret = -1;
387 + int enabled = -1;
388 +
389 + const char *relative_path = &this[baselen];
390 + if(!*relative_path) relative_path = "/";
391 +
392 + DIR *dir = opendir(this);
393 + if(!dir) {
394 + collector_error("CGROUP: cannot read directory '%s'", base);
395 + return ret;
396 + }
397 + ret = 1;
398 +
399 + callback(relative_path);
400 +
401 + struct dirent *de = NULL;
402 + while((de = readdir(dir))) {
403 + if(de->d_type == DT_DIR
404 + && (
405 + (de->d_name[0] == '.' && de->d_name[1] == '\0')
406 + || (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
407 + ))
408 + continue;
409 +
410 + if(de->d_type == DT_DIR) {
411 + if(enabled == -1) {
412 + const char *r = relative_path;
413 + if(*r == '\0') r = "/";
414 +
415 + // do not decent in directories we are not interested
416 + enabled = matches_search_cgroup_paths(r);
417 + }
418 +
419 + if(enabled) {
420 + char *s = mallocz(dirlen + strlen(de->d_name) + 2);
421 + strcpy(s, this);
422 + strcat(s, "/");
423 + strcat(s, de->d_name);
424 + int ret2 = discovery_find_dir_in_subdirs(base, s, callback);
425 + if(ret2 > 0) ret += ret2;
426 + freez(s);
427 + }
428 + }
429 + }
430 +
431 + closedir(dir);
432 + return ret;
433 +}
434 +
435 +static inline void discovery_mark_as_unavailable_all_cgroups() {
436 + for (struct cgroup *cg = discovered_cgroup_root; cg; cg = cg->discovered_next) {
437 + cg->available = 0;
438 + }
439 +}
440 +
441 +static inline void discovery_update_filenames_cgroup_v1(struct cgroup *cg) {
442 + char filename[FILENAME_MAX + 1];
443 + struct stat buf;
444 +
445 + // CPU
446 + if (unlikely(cgroup_enable_cpuacct_stat && !cg->cpuacct_stat.filename)) {
447 + snprintfz(filename, FILENAME_MAX, "%s%s/cpuacct.stat", cgroup_cpuacct_base, cg->id);
448 + if (likely(stat(filename, &buf) != -1)) {
449 + cg->cpuacct_stat.filename = strdupz(filename);
450 + cg->cpuacct_stat.enabled = cgroup_enable_cpuacct_stat;
451 + snprintfz(filename, FILENAME_MAX, "%s%s/cpuset.cpus", cgroup_cpuset_base, cg->id);
452 + cg->filename_cpuset_cpus = strdupz(filename);
453 + snprintfz(filename, FILENAME_MAX, "%s%s/cpu.cfs_period_us", cgroup_cpuacct_base, cg->id);
454 + cg->filename_cpu_cfs_period = strdupz(filename);
455 + snprintfz(filename, FILENAME_MAX, "%s%s/cpu.cfs_quota_us", cgroup_cpuacct_base, cg->id);
456 + cg->filename_cpu_cfs_quota = strdupz(filename);
457 + }
458 + }
459 + // FIXME: remove usage_percpu
460 + if (unlikely(cgroup_enable_cpuacct_usage && !cg->cpuacct_usage.filename && !is_cgroup_systemd_service(cg))) {
461 + snprintfz(filename, FILENAME_MAX, "%s%s/cpuacct.usage_percpu", cgroup_cpuacct_base, cg->id);
462 + if (likely(stat(filename, &buf) != -1)) {
463 + cg->cpuacct_usage.filename = strdupz(filename);
464 + cg->cpuacct_usage.enabled = cgroup_enable_cpuacct_usage;
465 + }
466 + }
467 + if (unlikely(
468 + cgroup_enable_cpuacct_cpu_throttling && !cg->cpuacct_cpu_throttling.filename &&
469 + !is_cgroup_systemd_service(cg))) {
470 + snprintfz(filename, FILENAME_MAX, "%s%s/cpu.stat", cgroup_cpuacct_base, cg->id);
471 + if (likely(stat(filename, &buf) != -1)) {
472 + cg->cpuacct_cpu_throttling.filename = strdupz(filename);
473 + cg->cpuacct_cpu_throttling.enabled = cgroup_enable_cpuacct_cpu_throttling;
474 + }
475 + }
476 + if (unlikely(
477 + cgroup_enable_cpuacct_cpu_shares && !cg->cpuacct_cpu_shares.filename && !is_cgroup_systemd_service(cg))) {
478 + snprintfz(filename, FILENAME_MAX, "%s%s/cpu.shares", cgroup_cpuacct_base, cg->id);
479 + if (likely(stat(filename, &buf) != -1)) {
480 + cg->cpuacct_cpu_shares.filename = strdupz(filename);
481 + cg->cpuacct_cpu_shares.enabled = cgroup_enable_cpuacct_cpu_shares;
482 + }
483 + }
484 +
485 + // Memory
486 + if (unlikely(
487 + (cgroup_enable_detailed_memory || cgroup_used_memory) && !cg->memory.filename_detailed &&
488 + (cgroup_used_memory || cgroup_enable_systemd_services_detailed_memory || !is_cgroup_systemd_service(cg)))) {
489 + snprintfz(filename, FILENAME_MAX, "%s%s/memory.stat", cgroup_memory_base, cg->id);
490 + if (likely(stat(filename, &buf) != -1)) {
491 + cg->memory.filename_detailed = strdupz(filename);
492 + cg->memory.enabled_detailed =
493 + (cgroup_enable_detailed_memory == CONFIG_BOOLEAN_YES) ? CONFIG_BOOLEAN_YES : CONFIG_BOOLEAN_AUTO;
494 + }
495 + }
496 + if (unlikely(cgroup_enable_memory && !cg->memory.filename_usage_in_bytes)) {
497 + snprintfz(filename, FILENAME_MAX, "%s%s/memory.usage_in_bytes", cgroup_memory_base, cg->id);
498 + if (likely(stat(filename, &buf) != -1)) {
499 + cg->memory.filename_usage_in_bytes = strdupz(filename);
500 + cg->memory.enabled_usage_in_bytes = cgroup_enable_memory;
501 + snprintfz(filename, FILENAME_MAX, "%s%s/memory.limit_in_bytes", cgroup_memory_base, cg->id);
502 + cg->filename_memory_limit = strdupz(filename);
503 + }
504 + }
505 + if (unlikely(cgroup_enable_swap && !cg->memory.filename_msw_usage_in_bytes)) {
506 + snprintfz(filename, FILENAME_MAX, "%s%s/memory.memsw.usage_in_bytes", cgroup_memory_base, cg->id);
507 + if (likely(stat(filename, &buf) != -1)) {
508 + cg->memory.filename_msw_usage_in_bytes = strdupz(filename);
509 + cg->memory.enabled_msw_usage_in_bytes = cgroup_enable_swap;
510 + snprintfz(filename, FILENAME_MAX, "%s%s/memory.memsw.limit_in_bytes", cgroup_memory_base, cg->id);
511 + cg->filename_memoryswap_limit = strdupz(filename);
512 + }
513 + }
514 + if (unlikely(cgroup_enable_memory_failcnt && !cg->memory.filename_failcnt)) {
515 + snprintfz(filename, FILENAME_MAX, "%s%s/memory.failcnt", cgroup_memory_base, cg->id);
516 + if (likely(stat(filename, &buf) != -1)) {
517 + cg->memory.filename_failcnt = strdupz(filename);
518 + cg->memory.enabled_failcnt = cgroup_enable_memory_failcnt;
519 + }
520 + }
521 +
522 + // Blkio
523 + if (unlikely(cgroup_enable_blkio_io && !cg->io_service_bytes.filename)) {
524 + snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_service_bytes_recursive", cgroup_blkio_base, cg->id);
525 + if (unlikely(stat(filename, &buf) != -1)) {
526 + cg->io_service_bytes.filename = strdupz(filename);
527 + cg->io_service_bytes.enabled = cgroup_enable_blkio_io;
528 + } else {
529 + snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_service_bytes", cgroup_blkio_base, cg->id);
530 + if (likely(stat(filename, &buf) != -1)) {
531 + cg->io_service_bytes.filename = strdupz(filename);
532 + cg->io_service_bytes.enabled = cgroup_enable_blkio_io;
533 + }
534 + }
535 + }
536 + if (unlikely(cgroup_enable_blkio_ops && !cg->io_serviced.filename)) {
537 + snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_serviced_recursive", cgroup_blkio_base, cg->id);
538 + if (unlikely(stat(filename, &buf) != -1)) {
539 + cg->io_serviced.filename = strdupz(filename);
540 + cg->io_serviced.enabled = cgroup_enable_blkio_ops;
541 + } else {
542 + snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_serviced", cgroup_blkio_base, cg->id);
543 + if (likely(stat(filename, &buf) != -1)) {
544 + cg->io_serviced.filename = strdupz(filename);
545 + cg->io_serviced.enabled = cgroup_enable_blkio_ops;
546 + }
547 + }
548 + }
549 + if (unlikely(cgroup_enable_blkio_throttle_io && !cg->throttle_io_service_bytes.filename)) {
550 + snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_service_bytes_recursive", cgroup_blkio_base, cg->id);
551 + if (unlikely(stat(filename, &buf) != -1)) {
552 + cg->throttle_io_service_bytes.filename = strdupz(filename);
553 + cg->throttle_io_service_bytes.enabled = cgroup_enable_blkio_throttle_io;
554 + } else {
555 + snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_service_bytes", cgroup_blkio_base, cg->id);
556 + if (likely(stat(filename, &buf) != -1)) {
557 + cg->throttle_io_service_bytes.filename = strdupz(filename);
558 + cg->throttle_io_service_bytes.enabled = cgroup_enable_blkio_throttle_io;
559 + }
560 + }
561 + }
562 + if (unlikely(cgroup_enable_blkio_throttle_ops && !cg->throttle_io_serviced.filename)) {
563 + snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_serviced_recursive", cgroup_blkio_base, cg->id);
564 + if (unlikely(stat(filename, &buf) != -1)) {
565 + cg->throttle_io_serviced.filename = strdupz(filename);
566 + cg->throttle_io_serviced.enabled = cgroup_enable_blkio_throttle_ops;
567 + } else {
568 + snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_serviced", cgroup_blkio_base, cg->id);
569 + if (likely(stat(filename, &buf) != -1)) {
570 + cg->throttle_io_serviced.filename = strdupz(filename);
571 + cg->throttle_io_serviced.enabled = cgroup_enable_blkio_throttle_ops;
572 + }
573 + }
574 + }
575 + if (unlikely(cgroup_enable_blkio_merged_ops && !cg->io_merged.filename)) {
576 + snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_merged_recursive", cgroup_blkio_base, cg->id);
577 + if (unlikely(stat(filename, &buf) != -1)) {
578 + cg->io_merged.filename = strdupz(filename);
579 + cg->io_merged.enabled = cgroup_enable_blkio_merged_ops;
580 + } else {
581 + snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_merged", cgroup_blkio_base, cg->id);
582 + if (likely(stat(filename, &buf) != -1)) {
583 + cg->io_merged.filename = strdupz(filename);
584 + cg->io_merged.enabled = cgroup_enable_blkio_merged_ops;
585 + }
586 + }
587 + }
588 + if (unlikely(cgroup_enable_blkio_queued_ops && !cg->io_queued.filename)) {
589 + snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_queued_recursive", cgroup_blkio_base, cg->id);
590 + if (unlikely(stat(filename, &buf) != -1)) {
591 + cg->io_queued.filename = strdupz(filename);
592 + cg->io_queued.enabled = cgroup_enable_blkio_queued_ops;
593 + } else {
594 + snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_queued", cgroup_blkio_base, cg->id);
595 + if (likely(stat(filename, &buf) != -1)) {
596 + cg->io_queued.filename = strdupz(filename);
597 + cg->io_queued.enabled = cgroup_enable_blkio_queued_ops;
598 + }
599 + }
600 + }
601 +}
602 +
603 +static inline void discovery_update_filenames_cgroup_v2(struct cgroup *cg) {
604 + char filename[FILENAME_MAX + 1];
605 + struct stat buf;
606 +
607 + // CPU
608 + if (unlikely((cgroup_enable_cpuacct_stat || cgroup_enable_cpuacct_cpu_throttling) && !cg->cpuacct_stat.filename)) {
609 + snprintfz(filename, FILENAME_MAX, "%s%s/cpu.stat", cgroup_unified_base, cg->id);
610 + if (likely(stat(filename, &buf) != -1)) {
611 + cg->cpuacct_stat.filename = strdupz(filename);
612 + cg->cpuacct_stat.enabled = cgroup_enable_cpuacct_stat;
613 + cg->cpuacct_cpu_throttling.enabled = cgroup_enable_cpuacct_cpu_throttling;
614 + cg->filename_cpuset_cpus = NULL;
615 + cg->filename_cpu_cfs_period = NULL;
616 + snprintfz(filename, FILENAME_MAX, "%s%s/cpu.max", cgroup_unified_base, cg->id);
617 + cg->filename_cpu_cfs_quota = strdupz(filename);
618 + }
619 + }
620 + if (unlikely(cgroup_enable_cpuacct_cpu_shares && !cg->cpuacct_cpu_shares.filename)) {
621 + snprintfz(filename, FILENAME_MAX, "%s%s/cpu.weight", cgroup_unified_base, cg->id);
622 + if (likely(stat(filename, &buf) != -1)) {
623 + cg->cpuacct_cpu_shares.filename = strdupz(filename);
624 + cg->cpuacct_cpu_shares.enabled = cgroup_enable_cpuacct_cpu_shares;
625 + }
626 + }
627 +
628 + // Memory
629 + // FIXME: this if condition!
630 + if (unlikely(
631 + (cgroup_enable_detailed_memory || cgroup_used_memory) && !cg->memory.filename_detailed &&
632 + (cgroup_used_memory || cgroup_enable_systemd_services_detailed_memory || !is_cgroup_systemd_service(cg)))) {
633 + snprintfz(filename, FILENAME_MAX, "%s%s/memory.stat", cgroup_unified_base, cg->id);
634 + if (likely(stat(filename, &buf) != -1)) {
635 + cg->memory.filename_detailed = strdupz(filename);
636 + cg->memory.enabled_detailed =
637 + (cgroup_enable_detailed_memory == CONFIG_BOOLEAN_YES) ? CONFIG_BOOLEAN_YES : CONFIG_BOOLEAN_AUTO;
638 + }
639 + }
640 +
641 + if (unlikely(cgroup_enable_memory && !cg->memory.filename_usage_in_bytes)) {
642 + snprintfz(filename, FILENAME_MAX, "%s%s/memory.current", cgroup_unified_base, cg->id);
643 + if (likely(stat(filename, &buf) != -1)) {
644 + cg->memory.filename_usage_in_bytes = strdupz(filename);
645 + cg->memory.enabled_usage_in_bytes = cgroup_enable_memory;
646 + snprintfz(filename, FILENAME_MAX, "%s%s/memory.max", cgroup_unified_base, cg->id);
647 + cg->filename_memory_limit = strdupz(filename);
648 + }
649 + }
650 +
651 + if (unlikely(cgroup_enable_swap && !cg->memory.filename_msw_usage_in_bytes)) {
652 + snprintfz(filename, FILENAME_MAX, "%s%s/memory.swap.current", cgroup_unified_base, cg->id);
653 + if (likely(stat(filename, &buf) != -1)) {
654 + cg->memory.filename_msw_usage_in_bytes = strdupz(filename);
655 + cg->memory.enabled_msw_usage_in_bytes = cgroup_enable_swap;
656 + snprintfz(filename, FILENAME_MAX, "%s%s/memory.swap.max", cgroup_unified_base, cg->id);
657 + cg->filename_memoryswap_limit = strdupz(filename);
658 + }
659 + }
660 +
661 + // Blkio
662 + if (unlikely(cgroup_enable_blkio_io && !cg->io_service_bytes.filename)) {
663 + snprintfz(filename, FILENAME_MAX, "%s%s/io.stat", cgroup_unified_base, cg->id);
664 + if (likely(stat(filename, &buf) != -1)) {
665 + cg->io_service_bytes.filename = strdupz(filename);
666 + cg->io_service_bytes.enabled = cgroup_enable_blkio_io;
667 + }
668 + }
669 +
670 + if (unlikely(cgroup_enable_blkio_ops && !cg->io_serviced.filename)) {
671 + snprintfz(filename, FILENAME_MAX, "%s%s/io.stat", cgroup_unified_base, cg->id);
672 + if (likely(stat(filename, &buf) != -1)) {
673 + cg->io_serviced.filename = strdupz(filename);
674 + cg->io_serviced.enabled = cgroup_enable_blkio_ops;
675 + }
676 + }
677 +
678 + // PSI
679 + if (unlikely(cgroup_enable_pressure_cpu && !cg->cpu_pressure.filename)) {
680 + snprintfz(filename, FILENAME_MAX, "%s%s/cpu.pressure", cgroup_unified_base, cg->id);
681 + if (likely(stat(filename, &buf) != -1)) {
682 + cg->cpu_pressure.filename = strdupz(filename);
683 + cg->cpu_pressure.some.enabled = cgroup_enable_pressure_cpu;
684 + cg->cpu_pressure.full.enabled = CONFIG_BOOLEAN_NO;
685 + }
686 + }
687 +
688 + if (unlikely((cgroup_enable_pressure_io_some || cgroup_enable_pressure_io_full) && !cg->io_pressure.filename)) {
689 + snprintfz(filename, FILENAME_MAX, "%s%s/io.pressure", cgroup_unified_base, cg->id);
690 + if (likely(stat(filename, &buf) != -1)) {
691 + cg->io_pressure.filename = strdupz(filename);
692 + cg->io_pressure.some.enabled = cgroup_enable_pressure_io_some;
693 + cg->io_pressure.full.enabled = cgroup_enable_pressure_io_full;
694 + }
695 + }
696 +
697 + if (unlikely(
698 + (cgroup_enable_pressure_memory_some || cgroup_enable_pressure_memory_full) &&
699 + !cg->memory_pressure.filename)) {
700 + snprintfz(filename, FILENAME_MAX, "%s%s/memory.pressure", cgroup_unified_base, cg->id);
701 + if (likely(stat(filename, &buf) != -1)) {
702 + cg->memory_pressure.filename = strdupz(filename);
703 + cg->memory_pressure.some.enabled = cgroup_enable_pressure_memory_some;
704 + cg->memory_pressure.full.enabled = cgroup_enable_pressure_memory_full;
705 + }
706 + }
707 +
708 + if (unlikely((cgroup_enable_pressure_irq_some || cgroup_enable_pressure_irq_full) && !cg->irq_pressure.filename)) {
709 + snprintfz(filename, FILENAME_MAX, "%s%s/irq.pressure", cgroup_unified_base, cg->id);
710 + if (likely(stat(filename, &buf) != -1)) {
711 + cg->irq_pressure.filename = strdupz(filename);
712 + cg->irq_pressure.some.enabled = cgroup_enable_pressure_irq_some;
713 + cg->irq_pressure.full.enabled = cgroup_enable_pressure_irq_full;
714 + }
715 + }
716 +}
717 +
718 +static inline void discovery_update_filenames_all_cgroups() {
719 + struct stat buf;
720 + for (struct cgroup *cg = discovered_cgroup_root; cg; cg = cg->discovered_next) {
721 + if (unlikely(!cg->available || !cg->enabled || cg->pending_renames))
722 + continue;
723 +
724 + if (!cgroup_use_unified_cgroups)
725 + discovery_update_filenames_cgroup_v1(cg);
726 + else if (likely(cgroup_unified_exist))
727 + discovery_update_filenames_cgroup_v2(cg);
728 + }
729 +}
730 +
731 +static inline void discovery_cleanup_all_cgroups() {
732 + struct cgroup *cg = discovered_cgroup_root, *last = NULL;
733 +
734 + for(; cg ;) {
735 + if(!cg->available) {
736 + // enable the first duplicate cgroup
737 + {
738 + struct cgroup *t;
739 + for (t = discovered_cgroup_root; t; t = t->discovered_next) {
740 + if (t != cg && t->available && !t->enabled && t->options & CGROUP_OPTIONS_DISABLED_DUPLICATE &&
741 + (is_cgroup_systemd_service(t) == is_cgroup_systemd_service(cg)) &&
742 + t->hash_chart_id == cg->hash_chart_id && !strcmp(t->chart_id, cg->chart_id)) {
743 + netdata_log_debug(D_CGROUP, "Enabling duplicate of cgroup '%s' with id '%s', because the original with id '%s' stopped.", t->chart_id, t->id, cg->id);
744 + t->enabled = 1;
745 + t->options &= ~CGROUP_OPTIONS_DISABLED_DUPLICATE;
746 + break;
747 + }
748 + }
749 + }
750 +
751 + if(!last)
752 + discovered_cgroup_root = cg->discovered_next;
753 + else
754 + last->discovered_next = cg->discovered_next;
755 +
756 + cgroup_free(cg);
757 +
758 + if(!last)
759 + cg = discovered_cgroup_root;
760 + else
761 + cg = last->discovered_next;
762 + }
763 + else {
764 + last = cg;
765 + cg = cg->discovered_next;
766 + }
767 + }
768 +}
769 +
770 +static inline void discovery_copy_discovered_cgroups_to_reader() {
771 + netdata_log_debug(D_CGROUP, "copy discovered cgroups to the main group list");
772 +
773 + struct cgroup *cg;
774 +
775 + for (cg = discovered_cgroup_root; cg; cg = cg->discovered_next) {
776 + cg->next = cg->discovered_next;
777 + }
778 +
779 + cgroup_root = discovered_cgroup_root;
780 +}
781 +
782 +static inline void discovery_share_cgroups_with_ebpf() {
783 + struct cgroup *cg;
784 + int count;
785 + struct stat buf;
786 +
787 + if (shm_mutex_cgroup_ebpf == SEM_FAILED) {
788 + return;
789 + }
790 + sem_wait(shm_mutex_cgroup_ebpf);
791 +
792 + for (cg = cgroup_root, count = 0; cg; cg = cg->next, count++) {
793 + netdata_ebpf_cgroup_shm_body_t *ptr = &shm_cgroup_ebpf.body[count];
794 + char *prefix = (is_cgroup_systemd_service(cg)) ? services_chart_id_prefix : cgroup_chart_id_prefix;
795 + snprintfz(ptr->name, CGROUP_EBPF_NAME_SHARED_LENGTH - 1, "%s%s", prefix, cg->chart_id);
796 + ptr->hash = simple_hash(ptr->name);
797 + ptr->options = cg->options;
798 + ptr->enabled = cg->enabled;
799 + if (cgroup_use_unified_cgroups) {
800 + snprintfz(ptr->path, FILENAME_MAX, "%s%s/cgroup.procs", cgroup_unified_base, cg->id);
801 + if (likely(stat(ptr->path, &buf) == -1)) {
802 + ptr->path[0] = '\0';
803 + ptr->enabled = 0;
804 + }
805 + } else {
806 + is_cgroup_procs_exist(ptr, cg->id);
807 + }
808 +
809 + netdata_log_debug(D_CGROUP, "cgroup shared: NAME=%s, ENABLED=%d", ptr->name, ptr->enabled);
810 + }
811 +
812 + shm_cgroup_ebpf.header->cgroup_root_count = count;
813 + sem_post(shm_mutex_cgroup_ebpf);
814 +}
815 +
816 +static inline void discovery_find_all_cgroups_v1() {
817 + if (cgroup_enable_cpuacct_stat || cgroup_enable_cpuacct_usage) {
818 + if (discovery_find_dir_in_subdirs(cgroup_cpuacct_base, NULL, discovery_find_cgroup_in_dir_callback) == -1) {
819 + cgroup_enable_cpuacct_stat = cgroup_enable_cpuacct_usage = CONFIG_BOOLEAN_NO;
820 + collector_error("CGROUP: disabled cpu statistics.");
821 + }
822 + }
823 +
824 + if (cgroup_enable_blkio_io || cgroup_enable_blkio_ops || cgroup_enable_blkio_throttle_io ||
825 + cgroup_enable_blkio_throttle_ops || cgroup_enable_blkio_merged_ops || cgroup_enable_blkio_queued_ops) {
826 + if (discovery_find_dir_in_subdirs(cgroup_blkio_base, NULL, discovery_find_cgroup_in_dir_callback) == -1) {
827 + cgroup_enable_blkio_io = cgroup_enable_blkio_ops = cgroup_enable_blkio_throttle_io =
828 + cgroup_enable_blkio_throttle_ops = cgroup_enable_blkio_merged_ops = cgroup_enable_blkio_queued_ops =
829 + CONFIG_BOOLEAN_NO;
830 + collector_error("CGROUP: disabled blkio statistics.");
831 + }
832 + }
833 +
834 + if (cgroup_enable_memory || cgroup_enable_detailed_memory || cgroup_enable_swap || cgroup_enable_memory_failcnt) {
835 + if (discovery_find_dir_in_subdirs(cgroup_memory_base, NULL, discovery_find_cgroup_in_dir_callback) == -1) {
836 + cgroup_enable_memory = cgroup_enable_detailed_memory = cgroup_enable_swap = cgroup_enable_memory_failcnt =
837 + CONFIG_BOOLEAN_NO;
838 + collector_error("CGROUP: disabled memory statistics.");
839 + }
840 + }
841 +
842 + if (cgroup_search_in_devices) {
843 + if (discovery_find_dir_in_subdirs(cgroup_devices_base, NULL, discovery_find_cgroup_in_dir_callback) == -1) {
844 + cgroup_search_in_devices = 0;
845 + collector_error("CGROUP: disabled devices statistics.");
846 + }
847 + }
848 +}
849 +
850 +static inline void discovery_find_all_cgroups_v2() {
851 + if (discovery_find_dir_in_subdirs(cgroup_unified_base, NULL, discovery_find_cgroup_in_dir_callback) == -1) {
852 + cgroup_unified_exist = CONFIG_BOOLEAN_NO;
853 + collector_error("CGROUP: disabled unified cgroups statistics.");
854 + }
855 +}
856 +
857 +static int is_digits_only(const char *s) {
858 + do {
859 + if (!isdigit(*s++)) {
860 + return 0;
861 + }
862 + } while (*s);
863 +
864 + return 1;
865 +}
866 +
867 +static int is_cgroup_k8s_container(const char *id) {
868 + // examples:
869 + // https://github.com/netdata/netdata/blob/0fc101679dcd12f1cb8acdd07bb4c85d8e553e53/collectors/cgroups.plugin/cgroup-name.sh#L121-L147
870 + const char *p = id;
871 + const char *pp = NULL;
872 + int i = 0;
873 + size_t l = 3; // pod
874 + while ((p = strstr(p, "pod"))) {
875 + i++;
876 + p += l;
877 + pp = p;
878 + }
879 + return !(i < 2 || !pp || !(pp = strchr(pp, '/')) || !pp++ || !*pp);
880 +}
881 +
882 +#define TASK_COMM_LEN 16
883 +
884 +static int k8s_get_container_first_proc_comm(const char *id, char *comm) {
885 + if (!is_cgroup_k8s_container(id)) {
886 + return 1;
887 + }
888 +
889 + static procfile *ff = NULL;
890 +
891 + char filename[FILENAME_MAX + 1];
892 + snprintfz(filename, FILENAME_MAX, "%s/%s/cgroup.procs", cgroup_cpuacct_base, id);
893 +
894 + ff = procfile_reopen(ff, filename, NULL, CGROUP_PROCFILE_FLAG);
895 + if (unlikely(!ff)) {
896 + netdata_log_debug(D_CGROUP, "CGROUP: k8s_is_pause_container(): cannot open file '%s'.", filename);
897 + return 1;
898 + }
899 +
900 + ff = procfile_readall(ff);
901 + if (unlikely(!ff)) {
902 + netdata_log_debug(D_CGROUP, "CGROUP: k8s_is_pause_container(): cannot read file '%s'.", filename);
903 + return 1;
904 + }
905 +
906 + unsigned long lines = procfile_lines(ff);
907 + if (likely(lines < 2)) {
908 + return 1;
909 + }
910 +
911 + char *pid = procfile_lineword(ff, 0, 0);
912 + if (!pid || !*pid) {
913 + return 1;
914 + }
915 +
916 + snprintfz(filename, FILENAME_MAX, "%s/proc/%s/comm", netdata_configured_host_prefix, pid);
917 +
918 + ff = procfile_reopen(ff, filename, NULL, PROCFILE_FLAG_DEFAULT);
919 + if (unlikely(!ff)) {
920 + netdata_log_debug(D_CGROUP, "CGROUP: k8s_is_pause_container(): cannot open file '%s'.", filename);
921 + return 1;
922 + }
923 +
924 + ff = procfile_readall(ff);
925 + if (unlikely(!ff)) {
926 + netdata_log_debug(D_CGROUP, "CGROUP: k8s_is_pause_container(): cannot read file '%s'.", filename);
927 + return 1;
928 + }
929 +
930 + lines = procfile_lines(ff);
931 + if (unlikely(lines != 2)) {
932 + return 1;
933 + }
934 +
935 + char *proc_comm = procfile_lineword(ff, 0, 0);
936 + if (!proc_comm || !*proc_comm) {
937 + return 1;
938 + }
939 +
940 + strncpyz(comm, proc_comm, TASK_COMM_LEN);
941 + return 0;
942 +}
943 +
944 +static inline void discovery_process_first_time_seen_cgroup(struct cgroup *cg) {
945 + if (!cg->first_time_seen) {
946 + return;
947 + }
948 + cg->first_time_seen = 0;
949 +
950 + char comm[TASK_COMM_LEN + 1];
951 +
952 + if (cg->container_orchestrator == CGROUPS_ORCHESTRATOR_UNSET) {
953 + if (strstr(cg->id, "kubepods")) {
954 + cg->container_orchestrator = CGROUPS_ORCHESTRATOR_K8S;
955 + } else {
956 + cg->container_orchestrator = CGROUPS_ORCHESTRATOR_UNKNOWN;
957 + }
958 + }
959 +
960 + if (is_inside_k8s && !k8s_get_container_first_proc_comm(cg->id, comm)) {
961 + // container initialization may take some time when CPU % is high
962 + // seen on GKE: comm is '6' before 'runc:[2:INIT]' (dunno if it could be another number)
963 + if (is_digits_only(comm) || matches_entrypoint_parent_process_comm(comm)) {
964 + cg->first_time_seen = 1;
965 + return;
966 + }
967 + if (!strcmp(comm, "pause")) {
968 + // a container that holds the network namespace for the pod
969 + // we don't need to collect its metrics
970 + cg->processed = 1;
971 + return;
972 + }
973 + }
974 +
975 + if (cgroup_enable_systemd_services && matches_systemd_services_cgroups(cg->id)) {
976 + netdata_log_debug(D_CGROUP, "cgroup '%s' (name '%s') matches 'cgroups to match as systemd services'", cg->id, cg->chart_id);
977 + convert_cgroup_to_systemd_service(cg);
978 + return;
979 + }
980 +
981 + if (matches_enabled_cgroup_renames(cg->id)) {
982 + netdata_log_debug(D_CGROUP, "cgroup '%s' (name '%s') matches 'run script to rename cgroups matching', will try to rename it", cg->id, cg->chart_id);
983 + if (is_inside_k8s && is_cgroup_k8s_container(cg->id)) {
984 + // it may take up to a minute for the K8s API to return data for the container
985 + // tested on AWS K8s cluster with 100% CPU utilization
986 + cg->pending_renames = 9; // 1.5 minute
987 + } else {
988 + cg->pending_renames = 2;
989 + }
990 + }
991 +}
992 +
993 +static int discovery_is_cgroup_duplicate(struct cgroup *cg) {
994 + // https://github.com/netdata/netdata/issues/797#issuecomment-241248884
995 + struct cgroup *c;
996 + for (c = discovered_cgroup_root; c; c = c->discovered_next) {
997 + if (c != cg && c->enabled && (is_cgroup_systemd_service(c) == is_cgroup_systemd_service(cg)) &&
998 + c->hash_chart_id == cg->hash_chart_id && !strcmp(c->chart_id, cg->chart_id)) {
999 + collector_error(
1000 + "CGROUP: chart id '%s' already exists with id '%s' and is enabled and available. Disabling cgroup with id '%s'.",
1001 + cg->chart_id,
1002 + c->id,
1003 + cg->id);
1004 + return 1;
1005 + }
1006 + }
1007 + return 0;
1008 +}
1009 +
1010 +// ----------------------------------------------------------------------------
1011 +// cgroup network interfaces
1012 +
1013 +#define CGROUP_NETWORK_INTERFACE_MAX_LINE 2048
1014 +
1015 +static inline void read_cgroup_network_interfaces(struct cgroup *cg) {
1016 + netdata_log_debug(D_CGROUP, "looking for the network interfaces of cgroup '%s' with chart id '%s'", cg->id, cg->chart_id);
1017 +
1018 + pid_t cgroup_pid;
1019 + char cgroup_identifier[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1];
1020 +
1021 + if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
1022 + snprintfz(cgroup_identifier, CGROUP_NETWORK_INTERFACE_MAX_LINE, "%s%s", cgroup_cpuacct_base, cg->id);
1023 + }
1024 + else {
1025 + snprintfz(cgroup_identifier, CGROUP_NETWORK_INTERFACE_MAX_LINE, "%s%s", cgroup_unified_base, cg->id);
1026 + }
1027 +
1028 + netdata_log_debug(D_CGROUP, "executing cgroup_identifier %s --cgroup '%s' for cgroup '%s'", cgroups_network_interface_script, cgroup_identifier, cg->id);
1029 + FILE *fp_child_input, *fp_child_output;
1030 + (void)netdata_popen_raw_default_flags_and_environment(&cgroup_pid, &fp_child_input, &fp_child_output, cgroups_network_interface_script, "--cgroup", cgroup_identifier);
1031 + if(!fp_child_output) {
1032 + collector_error("CGROUP: cannot popen(%s --cgroup \"%s\", \"r\").", cgroups_network_interface_script, cgroup_identifier);
1033 + return;
1034 + }
1035 +
1036 + char *s;
1037 + char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1];
1038 + while((s = fgets(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, fp_child_output))) {
1039 + trim(s);
1040 +
1041 + if(*s && *s != '\n') {
1042 + char *t = s;
1043 + while(*t && *t != ' ') t++;
1044 + if(*t == ' ') {
1045 + *t = '\0';
1046 + t++;
1047 + }
1048 +
1049 + if(!*s) {
1050 + collector_error("CGROUP: empty host interface returned by script");
1051 + continue;
1052 + }
1053 +
1054 + if(!*t) {
1055 + collector_error("CGROUP: empty guest interface returned by script");
1056 + continue;
1057 + }
1058 +
1059 + struct cgroup_network_interface *i = callocz(1, sizeof(struct cgroup_network_interface));
1060 + i->host_device = strdupz(s);
1061 + i->container_device = strdupz(t);
1062 + i->next = cg->interfaces;
1063 + cg->interfaces = i;
1064 +
1065 + collector_info("CGROUP: cgroup '%s' has network interface '%s' as '%s'", cg->id, i->host_device, i->container_device);
1066 +
1067 + // register a device rename to proc_net_dev.c
1068 + netdev_rename_device_add(i->host_device, i->container_device, cg->chart_id, cg->chart_labels,
1069 + k8s_is_kubepod(cg) ? "k8s." : "", cgroup_netdev_get(cg));
1070 + }
1071 + }
1072 +
1073 + netdata_pclose(fp_child_input, fp_child_output, cgroup_pid);
1074 + // netdata_log_debug(D_CGROUP, "closed cgroup_identifier for cgroup '%s'", cg->id);
1075 +}
1076 +
1077 +static inline void discovery_process_cgroup(struct cgroup *cg) {
1078 + if (!cg->available || cg->processed) {
1079 + return;
1080 + }
1081 +
1082 + if (cg->first_time_seen) {
1083 + worker_is_busy(WORKER_DISCOVERY_PROCESS_FIRST_TIME);
1084 + discovery_process_first_time_seen_cgroup(cg);
1085 + if (unlikely(cg->first_time_seen || cg->processed)) {
1086 + return;
1087 + }
1088 + }
1089 +
1090 + if (cg->pending_renames) {
1091 + worker_is_busy(WORKER_DISCOVERY_PROCESS_RENAME);
1092 + discovery_rename_cgroup(cg);
1093 + if (unlikely(cg->pending_renames || cg->processed)) {
1094 + return;
1095 + }
1096 + }
1097 +
1098 + cg->processed = 1;
1099 +
1100 + if ((strlen(cg->chart_id) + strlen(cgroup_chart_id_prefix)) >= RRD_ID_LENGTH_MAX) {
1101 + collector_info("cgroup '%s' (chart id '%s') disabled because chart_id exceeds the limit (RRD_ID_LENGTH_MAX)", cg->id, cg->chart_id);
1102 + return;
1103 + }
1104 +
1105 + if (is_cgroup_systemd_service(cg)) {
1106 + if (discovery_is_cgroup_duplicate(cg)) {
1107 + cg->enabled = 0;
1108 + cg->options |= CGROUP_OPTIONS_DISABLED_DUPLICATE;
1109 + return;
1110 + }
1111 + if (!cg->chart_labels)
1112 + cg->chart_labels = rrdlabels_create();
1113 + rrdlabels_add(cg->chart_labels, "service_name", cg->name, RRDLABEL_SRC_AUTO);
1114 + cg->enabled = 1;
1115 + return;
1116 + }
1117 +
1118 + if (!(cg->enabled = matches_enabled_cgroup_names(cg->name))) {
1119 + netdata_log_debug(D_CGROUP, "cgroup '%s' (name '%s') disabled by 'enable by default cgroups names matching'", cg->id, cg->name);
1120 + return;
1121 + }
1122 +
1123 + if (!(cg->enabled = matches_enabled_cgroup_paths(cg->id))) {
1124 + netdata_log_debug(D_CGROUP, "cgroup '%s' (name '%s') disabled by 'enable by default cgroups matching'", cg->id, cg->name);
1125 + return;
1126 + }
1127 +
1128 + if (discovery_is_cgroup_duplicate(cg)) {
1129 + cg->enabled = 0;
1130 + cg->options |= CGROUP_OPTIONS_DISABLED_DUPLICATE;
1131 + return;
1132 + }
1133 +
1134 + if (!cg->chart_labels)
1135 + cg->chart_labels = rrdlabels_create();
1136 +
1137 + if (!k8s_is_kubepod(cg)) {
1138 + rrdlabels_add(cg->chart_labels, "cgroup_name", cg->name, RRDLABEL_SRC_AUTO);
1139 + if (!rrdlabels_exist(cg->chart_labels, "image"))
1140 + rrdlabels_add(cg->chart_labels, "image", "", RRDLABEL_SRC_AUTO);
1141 + }
1142 +
1143 + worker_is_busy(WORKER_DISCOVERY_PROCESS_NETWORK);
1144 + read_cgroup_network_interfaces(cg);
1145 +}
1146 +
1147 +static inline void discovery_find_all_cgroups() {
1148 + netdata_log_debug(D_CGROUP, "searching for cgroups");
1149 +
1150 + worker_is_busy(WORKER_DISCOVERY_INIT);
1151 + discovery_mark_as_unavailable_all_cgroups();
1152 +
1153 + worker_is_busy(WORKER_DISCOVERY_FIND);
1154 + if (!cgroup_use_unified_cgroups) {
1155 + discovery_find_all_cgroups_v1();
1156 + } else {
1157 + discovery_find_all_cgroups_v2();
1158 + }
1159 +
1160 + for (struct cgroup *cg = discovered_cgroup_root; cg; cg = cg->discovered_next) {
1161 + worker_is_busy(WORKER_DISCOVERY_PROCESS);
1162 + discovery_process_cgroup(cg);
1163 + }
1164 +
1165 + worker_is_busy(WORKER_DISCOVERY_UPDATE);
1166 + discovery_update_filenames_all_cgroups();
1167 +
1168 + worker_is_busy(WORKER_DISCOVERY_LOCK);
1169 + uv_mutex_lock(&cgroup_root_mutex);
1170 +
1171 + worker_is_busy(WORKER_DISCOVERY_CLEANUP);
1172 + discovery_cleanup_all_cgroups();
1173 +
1174 + worker_is_busy(WORKER_DISCOVERY_COPY);
1175 + discovery_copy_discovered_cgroups_to_reader();
1176 +
1177 + uv_mutex_unlock(&cgroup_root_mutex);
1178 +
1179 + worker_is_busy(WORKER_DISCOVERY_SHARE);
1180 + discovery_share_cgroups_with_ebpf();
1181 +
1182 + netdata_log_debug(D_CGROUP, "done searching for cgroups");
1183 +}
1184 +
1185 +void cgroup_discovery_worker(void *ptr)
1186 +{
1187 + UNUSED(ptr);
1188 +
1189 + worker_register("CGROUPSDISC");
1190 + worker_register_job_name(WORKER_DISCOVERY_INIT, "init");
1191 + worker_register_job_name(WORKER_DISCOVERY_FIND, "find");
1192 + worker_register_job_name(WORKER_DISCOVERY_PROCESS, "process");
1193 + worker_register_job_name(WORKER_DISCOVERY_PROCESS_RENAME, "rename");
1194 + worker_register_job_name(WORKER_DISCOVERY_PROCESS_NETWORK, "network");
1195 + worker_register_job_name(WORKER_DISCOVERY_PROCESS_FIRST_TIME, "new");
1196 + worker_register_job_name(WORKER_DISCOVERY_UPDATE, "update");
1197 + worker_register_job_name(WORKER_DISCOVERY_CLEANUP, "cleanup");
1198 + worker_register_job_name(WORKER_DISCOVERY_COPY, "copy");
1199 + worker_register_job_name(WORKER_DISCOVERY_SHARE, "share");
1200 + worker_register_job_name(WORKER_DISCOVERY_LOCK, "lock");
1201 +
1202 + entrypoint_parent_process_comm = simple_pattern_create(
1203 + " runc:[* " // http://terenceli.github.io/%E6%8A%80%E6%9C%AF/2021/12/28/runc-internals-3)
1204 + " exe ", // https://github.com/falcosecurity/falco/blob/9d41b0a151b83693929d3a9c84f7c5c85d070d3a/rules/falco_rules.yaml#L1961
1205 + NULL,
1206 + SIMPLE_PATTERN_EXACT, true);
1207 +
1208 + service_register(SERVICE_THREAD_TYPE_LIBUV, NULL, NULL, NULL, false);
1209 +
1210 + while (service_running(SERVICE_COLLECTORS)) {
1211 + worker_is_idle();
1212 +
1213 + uv_mutex_lock(&discovery_thread.mutex);
1214 + uv_cond_wait(&discovery_thread.cond_var, &discovery_thread.mutex);
1215 + uv_mutex_unlock(&discovery_thread.mutex);
1216 +
1217 + if (unlikely(!service_running(SERVICE_COLLECTORS)))
1218 + break;
1219 +
1220 + discovery_find_all_cgroups();
1221 + }
1222 + collector_info("discovery thread stopped");
1223 + worker_unregister();
1224 + service_exits();
1225 + __atomic_store_n(&discovery_thread.exited,1,__ATOMIC_RELAXED);
1226 +}
collectors/cgroups.plugin/cgroup-internals.h new
+498
@@ -0,0 +1,498 @@
1 +#include "sys_fs_cgroup.h"
2 +
3 +#ifndef NETDATA_CGROUP_INTERNALS_H
4 +#define NETDATA_CGROUP_INTERNALS_H 1
5 +
6 +#ifdef NETDATA_INTERNAL_CHECKS
7 +#define CGROUP_PROCFILE_FLAG PROCFILE_FLAG_DEFAULT
8 +#else
9 +#define CGROUP_PROCFILE_FLAG PROCFILE_FLAG_NO_ERROR_ON_FILE_IO
10 +#endif
11 +
12 +struct blkio {
13 + int updated;
14 + int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
15 + int delay_counter;
16 +
17 + char *filename;
18 +
19 + unsigned long long Read;
20 + unsigned long long Write;
21 +/*
22 + unsigned long long Sync;
23 + unsigned long long Async;
24 + unsigned long long Total;
25 +*/
26 +};
27 +
28 +// https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt
29 +struct memory {
30 + ARL_BASE *arl_base;
31 + ARL_ENTRY *arl_dirty;
32 + ARL_ENTRY *arl_swap;
33 +
34 + int updated_detailed;
35 + int updated_usage_in_bytes;
36 + int updated_msw_usage_in_bytes;
37 + int updated_failcnt;
38 +
39 + int enabled_detailed; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
40 + int enabled_usage_in_bytes; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
41 + int enabled_msw_usage_in_bytes; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
42 + int enabled_failcnt; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
43 +
44 + int delay_counter_detailed;
45 + int delay_counter_failcnt;
46 +
47 + char *filename_detailed;
48 + char *filename_usage_in_bytes;
49 + char *filename_msw_usage_in_bytes;
50 + char *filename_failcnt;
51 +
52 + int detailed_has_dirty;
53 + int detailed_has_swap;
54 +
55 + // detailed metrics
56 +/*
57 + unsigned long long cache;
58 + unsigned long long rss;
59 + unsigned long long rss_huge;
60 + unsigned long long mapped_file;
61 + unsigned long long writeback;
62 + unsigned long long dirty;
63 + unsigned long long swap;
64 + unsigned long long pgpgin;
65 + unsigned long long pgpgout;
66 + unsigned long long pgfault;
67 + unsigned long long pgmajfault;
68 + unsigned long long inactive_anon;
69 + unsigned long long active_anon;
70 + unsigned long long inactive_file;
71 + unsigned long long active_file;
72 + unsigned long long unevictable;
73 + unsigned long long hierarchical_memory_limit;
74 +*/
75 + //unified cgroups metrics
76 + unsigned long long anon;
77 + unsigned long long kernel_stack;
78 + unsigned long long slab;
79 + unsigned long long sock;
80 + // unsigned long long shmem;
81 + unsigned long long anon_thp;
82 + //unsigned long long file_writeback;
83 + //unsigned long long file_dirty;
84 + //unsigned long long file;
85 +
86 + unsigned long long total_cache;
87 + unsigned long long total_rss;
88 + unsigned long long total_rss_huge;
89 + unsigned long long total_mapped_file;
90 + unsigned long long total_writeback;
91 + unsigned long long total_dirty;
92 + unsigned long long total_swap;
93 + unsigned long long total_pgpgin;
94 + unsigned long long total_pgpgout;
95 + unsigned long long total_pgfault;
96 + unsigned long long total_pgmajfault;
97 +/*
98 + unsigned long long total_inactive_anon;
99 + unsigned long long total_active_anon;
100 +*/
101 +
102 + unsigned long long total_inactive_file;
103 +
104 +/*
105 + unsigned long long total_active_file;
106 + unsigned long long total_unevictable;
107 +*/
108 +
109 + // single file metrics
110 + unsigned long long usage_in_bytes;
111 + unsigned long long msw_usage_in_bytes;
112 + unsigned long long failcnt;
113 +};
114 +
115 +// https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt
116 +struct cpuacct_stat {
117 + int updated;
118 + int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
119 +
120 + char *filename;
121 +
122 + unsigned long long user; // v1, v2(user_usec)
123 + unsigned long long system; // v1, v2(system_usec)
124 +};
125 +
126 +// https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt
127 +struct cpuacct_usage {
128 + int updated;
129 + int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
130 +
131 + char *filename;
132 +
133 + unsigned int cpus;
134 + unsigned long long *cpu_percpu;
135 +};
136 +
137 +// represents cpuacct/cpu.stat, for v2 'cpuacct_stat' is used for 'user_usec', 'system_usec'
138 +struct cpuacct_cpu_throttling {
139 + int updated;
140 + int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
141 +
142 + char *filename;
143 +
144 + unsigned long long nr_periods;
145 + unsigned long long nr_throttled;
146 + unsigned long long throttled_time;
147 +
148 + unsigned long long nr_throttled_perc;
149 +};
150 +
151 +// https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/resource_management_guide/sec-cpu#sect-cfs
152 +// https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/managing_monitoring_and_updating_the_kernel/using-cgroups-v2-to-control-distribution-of-cpu-time-for-applications_managing-monitoring-and-updating-the-kernel#proc_controlling-distribution-of-cpu-time-for-applications-by-adjusting-cpu-weight_using-cgroups-v2-to-control-distribution-of-cpu-time-for-applications
153 +struct cpuacct_cpu_shares {
154 + int updated;
155 + int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
156 +
157 + char *filename;
158 +
159 + unsigned long long shares;
160 +};
161 +
162 +struct cgroup_network_interface {
163 + const char *host_device;
164 + const char *container_device;
165 + struct cgroup_network_interface *next;
166 +};
167 +
168 +enum cgroups_container_orchestrator {
169 + CGROUPS_ORCHESTRATOR_UNSET,
170 + CGROUPS_ORCHESTRATOR_UNKNOWN,
171 + CGROUPS_ORCHESTRATOR_K8S
172 +};
173 +
174 +
175 +// *** WARNING *** The fields are not thread safe. Take care of safe usage.
176 +struct cgroup {
177 + uint32_t options;
178 +
179 + int first_time_seen; // first time seen by the discoverer
180 + int processed; // the discoverer is done processing a cgroup (resolved name, set 'enabled' option)
181 +
182 + char available; // found in the filesystem
183 + char enabled; // enabled in the config
184 +
185 + bool function_ready; // true after the first iteration of chart creation/update
186 +
187 + char pending_renames;
188 +
189 + char *id;
190 + uint32_t hash;
191 +
192 + char *intermediate_id; // TODO: remove it when the renaming script is fixed
193 +
194 + char *chart_id;
195 + uint32_t hash_chart_id;
196 +
197 + // 'cgroup_name' label value.
198 + // by default this is the *id (path), later changed to the resolved name (cgroup-name.sh) or systemd service name.
199 + char *name;
200 +
201 + RRDLABELS *chart_labels;
202 +
203 + int container_orchestrator;
204 +
205 + struct cpuacct_stat cpuacct_stat;
206 + struct cpuacct_usage cpuacct_usage;
207 + struct cpuacct_cpu_throttling cpuacct_cpu_throttling;
208 + struct cpuacct_cpu_shares cpuacct_cpu_shares;
209 +
210 + struct memory memory;
211 +
212 + struct blkio io_service_bytes; // bytes
213 + struct blkio io_serviced; // operations
214 +
215 + struct blkio throttle_io_service_bytes; // bytes
216 + struct blkio throttle_io_serviced; // operations
217 +
218 + struct blkio io_merged; // operations
219 + struct blkio io_queued; // operations
220 +
221 + struct cgroup_network_interface *interfaces;
222 +
223 + struct pressure cpu_pressure;
224 + struct pressure io_pressure;
225 + struct pressure memory_pressure;
226 + struct pressure irq_pressure;
227 +
228 + // per cgroup charts
229 + RRDSET *st_cpu;
230 + RRDDIM *st_cpu_rd_user;
231 + RRDDIM *st_cpu_rd_system;
232 +
233 + RRDSET *st_cpu_limit;
234 + RRDSET *st_cpu_per_core;
235 + RRDSET *st_cpu_nr_throttled;
236 + RRDSET *st_cpu_throttled_time;
237 + RRDSET *st_cpu_shares;
238 +
239 + RRDSET *st_mem;
240 + RRDDIM *st_mem_rd_ram;
241 + RRDDIM *st_mem_rd_swap;
242 +
243 + RRDSET *st_mem_utilization;
244 + RRDSET *st_writeback;
245 + RRDSET *st_mem_activity;
246 + RRDSET *st_pgfaults;
247 + RRDSET *st_mem_usage;
248 + RRDSET *st_mem_usage_limit;
249 + RRDSET *st_mem_failcnt;
250 +
251 + RRDSET *st_io;
252 + RRDDIM *st_io_rd_read;
253 + RRDDIM *st_io_rd_written;
254 +
255 + RRDSET *st_serviced_ops;
256 +
257 + RRDSET *st_throttle_io;
258 + RRDDIM *st_throttle_io_rd_read;
259 + RRDDIM *st_throttle_io_rd_written;
260 +
261 + RRDSET *st_throttle_serviced_ops;
262 +
263 + RRDSET *st_queued_ops;
264 + RRDSET *st_merged_ops;
265 +
266 + // per cgroup chart variables
267 + char *filename_cpuset_cpus;
268 + unsigned long long cpuset_cpus;
269 +
270 + char *filename_cpu_cfs_period;
271 + unsigned long long cpu_cfs_period;
272 +
273 + char *filename_cpu_cfs_quota;
274 + unsigned long long cpu_cfs_quota;
275 +
276 + const RRDSETVAR_ACQUIRED *chart_var_cpu_limit;
277 + NETDATA_DOUBLE prev_cpu_usage;
278 +
279 + char *filename_memory_limit;
280 + unsigned long long memory_limit;
281 + const RRDSETVAR_ACQUIRED *chart_var_memory_limit;
282 +
283 + char *filename_memoryswap_limit;
284 + unsigned long long memoryswap_limit;
285 + const RRDSETVAR_ACQUIRED *chart_var_memoryswap_limit;
286 +
287 + const DICTIONARY_ITEM *cgroup_netdev_link;
288 +
289 + struct cgroup *next;
290 + struct cgroup *discovered_next;
291 +
292 +};
293 +
294 +struct discovery_thread {
295 + uv_thread_t thread;
296 + uv_mutex_t mutex;
297 + uv_cond_t cond_var;
298 + int exited;
299 +};
300 +
301 +extern struct discovery_thread discovery_thread;
302 +
303 +extern char *cgroups_rename_script;
304 +extern char cgroup_chart_id_prefix[];
305 +extern char services_chart_id_prefix[];
306 +extern uv_mutex_t cgroup_root_mutex;
307 +
308 +void cgroup_discovery_worker(void *ptr);
309 +
310 +
311 +
312 +
313 +
314 +extern int is_inside_k8s;
315 +extern long system_page_size;
316 +extern int cgroup_enable_cpuacct_stat;
317 +extern int cgroup_enable_cpuacct_usage;
318 +extern int cgroup_enable_cpuacct_cpu_throttling;
319 +extern int cgroup_enable_cpuacct_cpu_shares;
320 +extern int cgroup_enable_memory;
321 +extern int cgroup_enable_detailed_memory;
322 +extern int cgroup_enable_memory_failcnt;
323 +extern int cgroup_enable_swap;
324 +extern int cgroup_enable_blkio_io;
325 +extern int cgroup_enable_blkio_ops;
326 +extern int cgroup_enable_blkio_throttle_io;
327 +extern int cgroup_enable_blkio_throttle_ops;
328 +extern int cgroup_enable_blkio_merged_ops;
329 +extern int cgroup_enable_blkio_queued_ops;
330 +extern int cgroup_enable_pressure_cpu;
331 +extern int cgroup_enable_pressure_io_some;
332 +extern int cgroup_enable_pressure_io_full;
333 +extern int cgroup_enable_pressure_memory_some;
334 +extern int cgroup_enable_pressure_memory_full;
335 +extern int cgroup_enable_pressure_irq_some;
336 +extern int cgroup_enable_pressure_irq_full;
337 +extern int cgroup_enable_systemd_services;
338 +extern int cgroup_enable_systemd_services_detailed_memory;
339 +extern int cgroup_used_memory;
340 +extern int cgroup_use_unified_cgroups;
341 +extern int cgroup_unified_exist;
342 +extern int cgroup_search_in_devices;
343 +extern int cgroup_check_for_new_every;
344 +extern int cgroup_update_every;
345 +extern int cgroup_containers_chart_priority;
346 +extern int cgroup_recheck_zero_blkio_every_iterations;
347 +extern int cgroup_recheck_zero_mem_failcnt_every_iterations;
348 +extern int cgroup_recheck_zero_mem_detailed_every_iterations;
349 +extern char *cgroup_cpuacct_base;
350 +extern char *cgroup_cpuset_base;
351 +extern char *cgroup_blkio_base;
352 +extern char *cgroup_memory_base;
353 +extern char *cgroup_devices_base;
354 +extern char *cgroup_unified_base;
355 +extern int cgroup_root_count;
356 +extern int cgroup_root_max;
357 +extern int cgroup_max_depth;
358 +extern SIMPLE_PATTERN *enabled_cgroup_paths;
359 +extern SIMPLE_PATTERN *enabled_cgroup_names;
360 +extern SIMPLE_PATTERN *search_cgroup_paths;
361 +extern SIMPLE_PATTERN *enabled_cgroup_renames;
362 +extern SIMPLE_PATTERN *systemd_services_cgroups;
363 +extern SIMPLE_PATTERN *entrypoint_parent_process_comm;
364 +extern char *cgroups_network_interface_script;
365 +extern int cgroups_check;
366 +extern uint32_t Read_hash;
367 +extern uint32_t Write_hash;
368 +extern uint32_t user_hash;
369 +extern uint32_t system_hash;
370 +extern uint32_t user_usec_hash;
371 +extern uint32_t system_usec_hash;
372 +extern uint32_t nr_periods_hash;
373 +extern uint32_t nr_throttled_hash;
374 +extern uint32_t throttled_time_hash;
375 +extern uint32_t throttled_usec_hash;
376 +extern struct cgroup *cgroup_root;
377 +
378 +extern netdata_ebpf_cgroup_shm_t shm_cgroup_ebpf;
379 +extern int shm_fd_cgroup_ebpf;
380 +extern sem_t *shm_mutex_cgroup_ebpf;
381 +
382 +enum cgroups_type { CGROUPS_AUTODETECT_FAIL, CGROUPS_V1, CGROUPS_V2 };
383 +
384 +enum cgroups_systemd_setting {
385 + SYSTEMD_CGROUP_ERR,
386 + SYSTEMD_CGROUP_LEGACY,
387 + SYSTEMD_CGROUP_HYBRID,
388 + SYSTEMD_CGROUP_UNIFIED
389 +};
390 +
391 +struct cgroups_systemd_config_setting {
392 + char *name;
393 + enum cgroups_systemd_setting setting;
394 +};
395 +
396 +extern struct cgroups_systemd_config_setting cgroups_systemd_options[];
397 +
398 +static inline int matches_enabled_cgroup_paths(char *id) {
399 + return simple_pattern_matches(enabled_cgroup_paths, id);
400 +}
401 +
402 +static inline int matches_enabled_cgroup_names(char *name) {
403 + return simple_pattern_matches(enabled_cgroup_names, name);
404 +}
405 +
406 +static inline int matches_enabled_cgroup_renames(char *id) {
407 + return simple_pattern_matches(enabled_cgroup_renames, id);
408 +}
409 +
410 +static inline int matches_systemd_services_cgroups(char *id) {
411 + return simple_pattern_matches(systemd_services_cgroups, id);
412 +}
413 +
414 +static inline int matches_search_cgroup_paths(const char *dir) {
415 + return simple_pattern_matches(search_cgroup_paths, dir);
416 +}
417 +
418 +static inline int matches_entrypoint_parent_process_comm(const char *comm) {
419 + return simple_pattern_matches(entrypoint_parent_process_comm, comm);
420 +}
421 +
422 +static inline int is_cgroup_systemd_service(struct cgroup *cg) {
423 + return (int)(cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE);
424 +}
425 +
426 +static inline int k8s_is_kubepod(struct cgroup *cg) {
427 + return cg->container_orchestrator == CGROUPS_ORCHESTRATOR_K8S;
428 +}
429 +
430 +static inline char *cgroup_chart_type(char *buffer, struct cgroup *cg) {
431 + buffer[0] = '\0';
432 +
433 + if (cg->chart_id[0] == '\0' || (cg->chart_id[0] == '/' && cg->chart_id[1] == '\0'))
434 + strncpy(buffer, "cgroup_root", RRD_ID_LENGTH_MAX);
435 + else if (is_cgroup_systemd_service(cg))
436 + snprintfz(buffer, RRD_ID_LENGTH_MAX, "%s%s", services_chart_id_prefix, cg->chart_id);
437 + else
438 + snprintfz(buffer, RRD_ID_LENGTH_MAX, "%s%s", cgroup_chart_id_prefix, cg->chart_id);
439 +
440 + return buffer;
441 +}
442 +
443 +#define RRDFUNCTIONS_CGTOP_HELP "View running containers"
444 +
445 +int cgroup_function_cgroup_top(BUFFER *wb, int timeout, const char *function, void *collector_data,
446 + rrd_function_result_callback_t result_cb, void *result_cb_data,
447 + rrd_function_is_cancelled_cb_t is_cancelled_cb, void *is_cancelled_cb_data,
448 + rrd_function_register_canceller_cb_t register_canceller_cb, void *register_canceller_cb_data);
449 +int cgroup_function_systemd_top(BUFFER *wb, int timeout, const char *function, void *collector_data,
450 + rrd_function_result_callback_t result_cb, void *result_cb_data,
451 + rrd_function_is_cancelled_cb_t is_cancelled_cb, void *is_cancelled_cb_data,
452 + rrd_function_register_canceller_cb_t register_canceller_cb, void *register_canceller_cb_data);
453 +
454 +void cgroup_netdev_link_init(void);
455 +const DICTIONARY_ITEM *cgroup_netdev_get(struct cgroup *cg);
456 +void cgroup_netdev_delete(struct cgroup *cg);
457 +
458 +void update_cpu_utilization_chart(struct cgroup *cg);
459 +void update_cpu_utilization_limit_chart(struct cgroup *cg, NETDATA_DOUBLE cpu_limit);
460 +void update_cpu_throttled_chart(struct cgroup *cg);
461 +void update_cpu_throttled_duration_chart(struct cgroup *cg);
462 +void update_cpu_shares_chart(struct cgroup *cg);
463 +void update_cpu_per_core_usage_chart(struct cgroup *cg);
464 +
465 +void update_mem_usage_limit_chart(struct cgroup *cg, unsigned long long memory_limit);
466 +void update_mem_utilization_chart(struct cgroup *cg, unsigned long long memory_limit);
467 +void update_mem_usage_detailed_chart(struct cgroup *cg);
468 +void update_mem_writeback_chart(struct cgroup *cg);
469 +void update_mem_activity_chart(struct cgroup *cg);
470 +void update_mem_pgfaults_chart(struct cgroup *cg);
471 +void update_mem_failcnt_chart(struct cgroup *cg);
472 +void update_mem_usage_chart(struct cgroup *cg);
473 +
474 +void update_io_serviced_bytes_chart(struct cgroup *cg);
475 +void update_io_serviced_ops_chart(struct cgroup *cg);
476 +void update_throttle_io_serviced_bytes_chart(struct cgroup *cg);
477 +void update_throttle_io_serviced_ops_chart(struct cgroup *cg);
478 +void update_io_queued_ops_chart(struct cgroup *cg);
479 +void update_io_merged_ops_chart(struct cgroup *cg);
480 +
481 +void update_cpu_some_pressure_chart(struct cgroup *cg);
482 +void update_cpu_some_pressure_stall_time_chart(struct cgroup *cg);
483 +void update_cpu_full_pressure_chart(struct cgroup *cg);
484 +void update_cpu_full_pressure_stall_time_chart(struct cgroup *cg);
485 +void update_mem_some_pressure_chart(struct cgroup *cg);
486 +void update_mem_some_pressure_stall_time_chart(struct cgroup *cg);
487 +void update_mem_full_pressure_chart(struct cgroup *cg);
488 +void update_mem_full_pressure_stall_time_chart(struct cgroup *cg);
489 +void update_irq_some_pressure_chart(struct cgroup *cg);
490 +void update_irq_some_pressure_stall_time_chart(struct cgroup *cg);
491 +void update_irq_full_pressure_chart(struct cgroup *cg);
492 +void update_irq_full_pressure_stall_time_chart(struct cgroup *cg);
493 +void update_io_some_pressure_chart(struct cgroup *cg);
494 +void update_io_some_pressure_stall_time_chart(struct cgroup *cg);
495 +void update_io_full_pressure_chart(struct cgroup *cg);
496 +void update_io_full_pressure_stall_time_chart(struct cgroup *cg);
497 +
498 +#endif // NETDATA_CGROUP_INTERNALS_H
\ No newline at end of file
collectors/cgroups.plugin/cgroup-top.c new
+509
@@ -0,0 +1,509 @@
1 +// SPDX-License-Identifier: GPL-3.0-or-later
2 +
3 +#include "cgroup-internals.h"
4 +
5 +struct cgroup_netdev_link {
6 + size_t read_slot;
7 + NETDATA_DOUBLE received[2];
8 + NETDATA_DOUBLE sent[2];
9 +};
10 +
11 +static DICTIONARY *cgroup_netdev_link_dict = NULL;
12 +
13 +void cgroup_netdev_link_init(void) {
14 + cgroup_netdev_link_dict = dictionary_create_advanced(DICT_OPTION_FIXED_SIZE|DICT_OPTION_DONT_OVERWRITE_VALUE, NULL, sizeof(struct cgroup_netdev_link));
15 +}
16 +
17 +const DICTIONARY_ITEM *cgroup_netdev_get(struct cgroup *cg) {
18 + if(cg->cgroup_netdev_link)
19 + return cg->cgroup_netdev_link;
20 +
21 +
22 + struct cgroup_netdev_link t = {
23 + .read_slot = 0,
24 + .received = { NAN, NAN },
25 + .sent = { NAN, NAN },
26 + };
27 +
28 + cg->cgroup_netdev_link = dictionary_set_and_acquire_item(cgroup_netdev_link_dict, cg->id, &t, sizeof(struct cgroup_netdev_link));
29 + return dictionary_acquired_item_dup(cgroup_netdev_link_dict, cg->cgroup_netdev_link);
30 +}
31 +
32 +void cgroup_netdev_delete(struct cgroup *cg) {
33 + if(cg->cgroup_netdev_link) {
34 + dictionary_acquired_item_release(cgroup_netdev_link_dict, cg->cgroup_netdev_link);
35 + dictionary_del(cgroup_netdev_link_dict, cg->id);
36 + dictionary_garbage_collect(cgroup_netdev_link_dict);
37 + }
38 +}
39 +
40 +void cgroup_netdev_release(const DICTIONARY_ITEM *link) {
41 + if(link)
42 + dictionary_acquired_item_release(cgroup_netdev_link_dict, link);
43 +}
44 +
45 +const void *cgroup_netdev_dup(const DICTIONARY_ITEM *link) {
46 + return dictionary_acquired_item_dup(cgroup_netdev_link_dict, link);
47 +}
48 +
49 +void cgroup_netdev_reset_all(void) {
50 + struct cgroup_netdev_link *t;
51 + dfe_start_read(cgroup_netdev_link_dict, t) {
52 + if(t->read_slot >= 1) {
53 + t->read_slot = 0;
54 + t->received[1] = NAN;
55 + t->sent[1] = NAN;
56 + }
57 + else {
58 + t->read_slot = 1;
59 + t->received[0] = NAN;
60 + t->sent[0] = NAN;
61 + }
62 + }
63 + dfe_done(t);
64 +}
65 +
66 +void cgroup_netdev_add_bandwidth(const DICTIONARY_ITEM *link, NETDATA_DOUBLE received, NETDATA_DOUBLE sent) {
67 + if(!link)
68 + return;
69 +
70 + struct cgroup_netdev_link *t = dictionary_acquired_item_value(link);
71 +
72 + size_t slot = (t->read_slot) ? 0 : 1;
73 +
74 + if(isnan(t->received[slot]))
75 + t->received[slot] = received;
76 + else
77 + t->received[slot] += received;
78 +
79 + if(isnan(t->sent[slot]))
80 + t->sent[slot] = sent;
81 + else
82 + t->sent[slot] += sent;
83 +}
84 +
85 +void cgroup_netdev_get_bandwidth(struct cgroup *cg, NETDATA_DOUBLE *received, NETDATA_DOUBLE *sent) {
86 + if(!cg->cgroup_netdev_link) {
87 + *received = NAN;
88 + *sent = NAN;
89 + return;
90 + }
91 +
92 + struct cgroup_netdev_link *t = dictionary_acquired_item_value(cg->cgroup_netdev_link);
93 +
94 + size_t slot = (t->read_slot) ? 1 : 0;
95 +
96 + *received = t->received[slot];
97 + *sent = t->sent[slot];
98 +}
99 +
100 +int cgroup_function_cgroup_top(BUFFER *wb, int timeout __maybe_unused, const char *function __maybe_unused,
101 + void *collector_data __maybe_unused,
102 + rrd_function_result_callback_t result_cb, void *result_cb_data,
103 + rrd_function_is_cancelled_cb_t is_cancelled_cb, void *is_cancelled_cb_data,
104 + rrd_function_register_canceller_cb_t register_canceller_cb __maybe_unused,
105 + void *register_canceller_cb_data __maybe_unused) {
106 +
107 + buffer_flush(wb);
108 + wb->content_type = CT_APPLICATION_JSON;
109 + buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_DEFAULT);
110 +
111 + buffer_json_member_add_string(wb, "hostname", rrdhost_hostname(localhost));
112 + buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
113 + buffer_json_member_add_string(wb, "type", "table");
114 + buffer_json_member_add_time_t(wb, "update_every", 1);
115 + buffer_json_member_add_string(wb, "help", RRDFUNCTIONS_CGTOP_HELP);
116 + buffer_json_member_add_array(wb, "data");
117 +
118 + double max_cpu = 0.0;
119 + double max_ram = 0.0;
120 + double max_disk_io_read = 0.0;
121 + double max_disk_io_written = 0.0;
122 + double max_net_received = 0.0;
123 + double max_net_sent = 0.0;
124 +
125 + uv_mutex_lock(&cgroup_root_mutex);
126 +
127 + for(struct cgroup *cg = cgroup_root; cg ; cg = cg->next) {
128 + if(unlikely(!cg->enabled || cg->pending_renames || !cg->function_ready || is_cgroup_systemd_service(cg)))
129 + continue;
130 +
131 + buffer_json_add_array_item_array(wb);
132 +
133 + buffer_json_add_array_item_string(wb, cg->name); // Name
134 +
135 + if(k8s_is_kubepod(cg))
136 + buffer_json_add_array_item_string(wb, "k8s"); // Kind
137 + else
138 + buffer_json_add_array_item_string(wb, "cgroup"); // Kind
139 +
140 + double cpu = cg->st_cpu_rd_user->collector.last_stored_value + cg->st_cpu_rd_system->collector.last_stored_value;
141 + max_cpu = MAX(max_cpu, cpu);
142 + buffer_json_add_array_item_double(wb, cpu);
143 +
144 + double ram = cg->st_mem_rd_ram->collector.last_stored_value;
145 + max_ram = MAX(max_ram, ram);
146 + buffer_json_add_array_item_double(wb, ram);
147 +
148 + double disk_io_read = NAN;
149 + double disk_io_written = NAN;
150 + if (cg->st_throttle_io_rd_read) {
151 + disk_io_read = (cg->st_throttle_io_rd_read->collector.last_stored_value / 1024.0);
152 + disk_io_written = (ABS(cg->st_throttle_io_rd_written->collector.last_stored_value) / 1024.0);
153 + } else if (cg->st_io_rd_read) {
154 + disk_io_read = (cg->st_io_rd_read->collector.last_stored_value / 1024.0);
155 + disk_io_written = (ABS(cg->st_io_rd_written->collector.last_stored_value) / 1024.0);
156 + }
157 +
158 + if (!isnan(disk_io_read) && !isnan(disk_io_written)) {
159 + max_disk_io_read = MAX(max_disk_io_read, disk_io_read);
160 + max_disk_io_written = MAX(max_disk_io_written, disk_io_written);
161 + }
162 +
163 + buffer_json_add_array_item_double(wb, disk_io_read);
164 + buffer_json_add_array_item_double(wb, disk_io_written);
165 +
166 +
167 + NETDATA_DOUBLE received, sent;
168 + cgroup_netdev_get_bandwidth(cg, &received, &sent);
169 + if (!isnan(received) && !isnan(sent)) {
170 + received /= 1000.0;
171 + sent /= 1000.0;
172 + max_net_received = MAX(max_net_received, received);
173 + max_net_sent = MAX(max_net_sent, sent);
174 + }
175 +
176 + buffer_json_add_array_item_double(wb, received);
177 + buffer_json_add_array_item_double(wb, sent);
178 +
179 + buffer_json_array_close(wb);
180 + }
181 +
182 + uv_mutex_unlock(&cgroup_root_mutex);
183 +
184 + buffer_json_array_close(wb); // data
185 + buffer_json_member_add_object(wb, "columns");
186 + {
187 + size_t field_id = 0;
188 +
189 + // Node
190 + buffer_rrdf_table_add_field(wb, field_id++, "Name", "CGROUP Name",
191 + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
192 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
193 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
194 + RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY | RRDF_FIELD_OPTS_STICKY | RRDF_FIELD_OPTS_FULL_WIDTH,
195 + NULL);
196 +
197 + // Kind
198 + buffer_rrdf_table_add_field(wb, field_id++, "Kind", "CGROUP Kind",
199 + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
200 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
201 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
202 + RRDF_FIELD_OPTS_VISIBLE,
203 + NULL);
204 +
205 + // CPU
206 + buffer_rrdf_table_add_field(wb, field_id++, "CPU", "CPU Usage",
207 + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
208 + 2, "%", max_cpu, RRDF_FIELD_SORT_DESCENDING, NULL,
209 + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
210 + RRDF_FIELD_OPTS_VISIBLE,
211 + NULL);
212 +
213 + // RAM
214 + buffer_rrdf_table_add_field(wb, field_id++, "RAM", "RAM Usage",
215 + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
216 + 2, "MiB", max_ram, RRDF_FIELD_SORT_DESCENDING, NULL,
217 + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
218 + RRDF_FIELD_OPTS_VISIBLE,
219 + NULL);
220 +
221 + // Disk IO Reads
222 + buffer_rrdf_table_add_field(wb, field_id++, "Reads", "Disk Read Data",
223 + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
224 + 2, "MiB", max_disk_io_read, RRDF_FIELD_SORT_DESCENDING, NULL,
225 + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
226 + RRDF_FIELD_OPTS_VISIBLE,
227 + NULL);
228 +
229 + // Disk IO Writes
230 + buffer_rrdf_table_add_field(wb, field_id++, "Writes", "Disk Written Data",
231 + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
232 + 2, "MiB", max_disk_io_written, RRDF_FIELD_SORT_DESCENDING, NULL,
233 + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
234 + RRDF_FIELD_OPTS_VISIBLE,
235 + NULL);
236 +
237 + // Network Received
238 + buffer_rrdf_table_add_field(wb, field_id++, "Received", "Network Traffic Received",
239 + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
240 + 2, "Mbps", max_net_received, RRDF_FIELD_SORT_DESCENDING, NULL,
241 + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
242 + RRDF_FIELD_OPTS_VISIBLE,
243 + NULL);
244 +
245 + // Network Sent
246 + buffer_rrdf_table_add_field(wb, field_id++, "Sent", "Network Traffic Sent ",
247 + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
248 + 2, "Mbps", max_net_sent, RRDF_FIELD_SORT_DESCENDING, NULL,
249 + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
250 + RRDF_FIELD_OPTS_VISIBLE,
251 + NULL);
252 + }
253 + buffer_json_object_close(wb); // columns
254 + buffer_json_member_add_string(wb, "default_sort_column", "CPU");
255 +
256 + buffer_json_member_add_object(wb, "charts");
257 + {
258 + buffer_json_member_add_object(wb, "CPU");
259 + {
260 + buffer_json_member_add_string(wb, "name", "CPU");
261 + buffer_json_member_add_string(wb, "type", "stacked-bar");
262 + buffer_json_member_add_array(wb, "columns");
263 + {
264 + buffer_json_add_array_item_string(wb, "CPU");
265 + }
266 + buffer_json_array_close(wb);
267 + }
268 + buffer_json_object_close(wb);
269 +
270 + buffer_json_member_add_object(wb, "Memory");
271 + {
272 + buffer_json_member_add_string(wb, "name", "Memory");
273 + buffer_json_member_add_string(wb, "type", "stacked-bar");
274 + buffer_json_member_add_array(wb, "columns");
275 + {
276 + buffer_json_add_array_item_string(wb, "RAM");
277 + }
278 + buffer_json_array_close(wb);
279 + }
280 + buffer_json_object_close(wb);
281 +
282 + buffer_json_member_add_object(wb, "Traffic");
283 + {
284 + buffer_json_member_add_string(wb, "name", "Traffic");
285 + buffer_json_member_add_string(wb, "type", "stacked-bar");
286 + buffer_json_member_add_array(wb, "columns");
287 + {
288 + buffer_json_add_array_item_string(wb, "Received");
289 + buffer_json_add_array_item_string(wb, "Sent");
290 + }
291 + buffer_json_array_close(wb);
292 + }
293 + buffer_json_object_close(wb);
294 + }
295 + buffer_json_object_close(wb); // charts
296 +
297 + buffer_json_member_add_array(wb, "default_charts");
298 + {
299 + buffer_json_add_array_item_array(wb);
300 + buffer_json_add_array_item_string(wb, "CPU");
301 + buffer_json_add_array_item_string(wb, "Name");
302 + buffer_json_array_close(wb);
303 +
304 + buffer_json_add_array_item_array(wb);
305 + buffer_json_add_array_item_string(wb, "Memory");
306 + buffer_json_add_array_item_string(wb, "Name");
307 + buffer_json_array_close(wb);
308 + }
309 + buffer_json_array_close(wb);
310 +
311 + buffer_json_member_add_object(wb, "group_by");
312 + {
313 + buffer_json_member_add_object(wb, "Kind");
314 + {
315 + buffer_json_member_add_string(wb, "name", "Kind");
316 + buffer_json_member_add_array(wb, "columns");
317 + {
318 + buffer_json_add_array_item_string(wb, "Kind");
319 + }
320 + buffer_json_array_close(wb);
321 + }
322 + buffer_json_object_close(wb);
323 + }
324 + buffer_json_object_close(wb); // group_by
325 +
326 + buffer_json_member_add_time_t(wb, "expires", now_realtime_sec() + 1);
327 + buffer_json_finalize(wb);
328 +
329 + int response = HTTP_RESP_OK;
330 + if(is_cancelled_cb && is_cancelled_cb(is_cancelled_cb_data)) {
331 + buffer_flush(wb);
332 + response = HTTP_RESP_CLIENT_CLOSED_REQUEST;
333 + }
334 +
335 + if(result_cb)
336 + result_cb(wb, response, result_cb_data);
337 +
338 + return response;
339 +}
340 +
341 +int cgroup_function_systemd_top(BUFFER *wb, int timeout __maybe_unused, const char *function __maybe_unused,
342 + void *collector_data __maybe_unused,
343 + rrd_function_result_callback_t result_cb, void *result_cb_data,
344 + rrd_function_is_cancelled_cb_t is_cancelled_cb, void *is_cancelled_cb_data,
345 + rrd_function_register_canceller_cb_t register_canceller_cb __maybe_unused,
346 + void *register_canceller_cb_data __maybe_unused) {
347 +
348 + buffer_flush(wb);
349 + wb->content_type = CT_APPLICATION_JSON;
350 + buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_DEFAULT);
351 +
352 + buffer_json_member_add_string(wb, "hostname", rrdhost_hostname(localhost));
353 + buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
354 + buffer_json_member_add_string(wb, "type", "table");
355 + buffer_json_member_add_time_t(wb, "update_every", 1);
356 + buffer_json_member_add_string(wb, "help", RRDFUNCTIONS_CGTOP_HELP);
357 + buffer_json_member_add_array(wb, "data");
358 +
359 + double max_cpu = 0.0;
360 + double max_ram = 0.0;
361 + double max_disk_io_read = 0.0;
362 + double max_disk_io_written = 0.0;
363 +
364 + uv_mutex_lock(&cgroup_root_mutex);
365 +
366 + for(struct cgroup *cg = cgroup_root; cg ; cg = cg->next) {
367 + if(unlikely(!cg->enabled || cg->pending_renames || !cg->function_ready || !is_cgroup_systemd_service(cg)))
368 + continue;
369 +
370 + buffer_json_add_array_item_array(wb);
371 +
372 + buffer_json_add_array_item_string(wb, cg->name);
373 +
374 + double cpu = cg->st_cpu_rd_user->collector.last_stored_value + cg->st_cpu_rd_system->collector.last_stored_value;
375 + max_cpu = MAX(max_cpu, cpu);
376 + buffer_json_add_array_item_double(wb, cpu);
377 +
378 + double ram = cg->st_mem_rd_ram->collector.last_stored_value;
379 + max_ram = MAX(max_ram, ram);
380 + buffer_json_add_array_item_double(wb, ram);
381 +
382 + double disk_io_read = NAN;
383 + double disk_io_written = NAN;
384 + if (cg->st_throttle_io_rd_read) {
385 + disk_io_read = (cg->st_throttle_io_rd_read->collector.last_stored_value / 1024.0);
386 + disk_io_written = (ABS(cg->st_throttle_io_rd_written->collector.last_stored_value) / 1024.0);
387 + } else if (cg->st_io_rd_read) {
388 + disk_io_read = (cg->st_io_rd_read->collector.last_stored_value / 1024.0);
389 + disk_io_written = (ABS(cg->st_io_rd_written->collector.last_stored_value) / 1024.0);
390 + }
391 +
392 + if (!isnan(disk_io_read) && !isnan(disk_io_written)) {
393 + max_disk_io_read = MAX(max_disk_io_read, disk_io_read);
394 + max_disk_io_written = MAX(max_disk_io_written, disk_io_written);
395 + }
396 +
397 + buffer_json_add_array_item_double(wb, disk_io_read);
398 + buffer_json_add_array_item_double(wb, disk_io_written);
399 +
400 + buffer_json_array_close(wb);
401 + }
402 +
403 + uv_mutex_unlock(&cgroup_root_mutex);
404 +
405 + buffer_json_array_close(wb); // data
406 + buffer_json_member_add_object(wb, "columns");
407 + {
408 + size_t field_id = 0;
409 +
410 + // Node
411 + buffer_rrdf_table_add_field(wb, field_id++, "Name", "Systemd Service Name",
412 + RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
413 + 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
414 + RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
415 + RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY | RRDF_FIELD_OPTS_STICKY | RRDF_FIELD_OPTS_FULL_WIDTH,
416 + NULL);
417 +
418 + // CPU
419 + buffer_rrdf_table_add_field(wb, field_id++, "CPU", "CPU Usage",
420 + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
421 + 2, "%", max_cpu, RRDF_FIELD_SORT_DESCENDING, NULL,
422 + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
423 + RRDF_FIELD_OPTS_VISIBLE,
424 + NULL);
425 +
426 + // RAM
427 + buffer_rrdf_table_add_field(wb, field_id++, "RAM", "RAM Usage",
428 + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
429 + 2, "MiB", max_ram, RRDF_FIELD_SORT_DESCENDING, NULL,
430 + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
431 + RRDF_FIELD_OPTS_VISIBLE,
432 + NULL);
433 +
434 + // Disk IO Reads
435 + buffer_rrdf_table_add_field(wb, field_id++, "Reads", "Disk Read Data",
436 + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
437 + 2, "MiB", max_disk_io_read, RRDF_FIELD_SORT_DESCENDING, NULL,
438 + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
439 + RRDF_FIELD_OPTS_VISIBLE,
440 + NULL);
441 +
442 + // Disk IO Writes
443 + buffer_rrdf_table_add_field(wb, field_id++, "Writes", "Disk Written Data",
444 + RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
445 + 2, "MiB", max_disk_io_written, RRDF_FIELD_SORT_DESCENDING, NULL,
446 + RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
447 + RRDF_FIELD_OPTS_VISIBLE,
448 + NULL);
449 + }
450 +
451 + buffer_json_object_close(wb); // columns
452 + buffer_json_member_add_string(wb, "default_sort_column", "CPU");
453 +
454 + buffer_json_member_add_object(wb, "charts");
455 + {
456 + buffer_json_member_add_object(wb, "CPU");
457 + {
458 + buffer_json_member_add_string(wb, "name", "CPU");
459 + buffer_json_member_add_string(wb, "type", "stacked-bar");
460 + buffer_json_member_add_array(wb, "columns");
461 + {
462 + buffer_json_add_array_item_string(wb, "CPU");
463 + }
464 + buffer_json_array_close(wb);
465 + }
466 + buffer_json_object_close(wb);
467 +
468 + buffer_json_member_add_object(wb, "Memory");
469 + {
470 + buffer_json_member_add_string(wb, "name", "Memory");
471 + buffer_json_member_add_string(wb, "type", "stacked-bar");
472 + buffer_json_member_add_array(wb, "columns");
473 + {
474 + buffer_json_add_array_item_string(wb, "RAM");
475 + }
476 + buffer_json_array_close(wb);
477 + }
478 + buffer_json_object_close(wb);
479 + }
480 + buffer_json_object_close(wb); // charts
481 +
482 + buffer_json_member_add_array(wb, "default_charts");
483 + {
484 + buffer_json_add_array_item_array(wb);
485 + buffer_json_add_array_item_string(wb, "CPU");
486 + buffer_json_add_array_item_string(wb, "Name");
487 + buffer_json_array_close(wb);
488 +
489 + buffer_json_add_array_item_array(wb);
490 + buffer_json_add_array_item_string(wb, "Memory");
491 + buffer_json_add_array_item_string(wb, "Name");
492 + buffer_json_array_close(wb);
493 + }
494 + buffer_json_array_close(wb);
495 +
496 + buffer_json_member_add_time_t(wb, "expires", now_realtime_sec() + 1);
497 + buffer_json_finalize(wb);
498 +
499 + int response = HTTP_RESP_OK;
500 + if(is_cancelled_cb && is_cancelled_cb(is_cancelled_cb_data)) {
501 + buffer_flush(wb);
502 + response = HTTP_RESP_CLIENT_CLOSED_REQUEST;
503 + }
504 +
505 + if(result_cb)
506 + result_cb(wb, response, result_cb_data);
507 +
508 + return response;
509 +}
collectors/cgroups.plugin/sys_fs_cgroup.c
+319 -3296
@@ -1,149 +1,97 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 -#include "sys_fs_cgroup.h"
4 -
5 -#define PLUGIN_CGROUPS_NAME "cgroups.plugin"
6 -#define PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME "systemd"
7 -#define PLUGIN_CGROUPS_MODULE_CGROUPS_NAME "/sys/fs/cgroup"
8 -
9 -#ifdef NETDATA_INTERNAL_CHECKS
10 -#define CGROUP_PROCFILE_FLAG PROCFILE_FLAG_DEFAULT
11 -#else
12 -#define CGROUP_PROCFILE_FLAG PROCFILE_FLAG_NO_ERROR_ON_FILE_IO
13 -#endif
3 +#include "cgroup-internals.h"
4
5 // main cgroups thread worker jobs
6 #define WORKER_CGROUPS_LOCK 0
7 #define WORKER_CGROUPS_READ 1
8 #define WORKER_CGROUPS_CHART 2
9
20 -// discovery cgroup thread worker jobs
21 -#define WORKER_DISCOVERY_INIT 0
22 -#define WORKER_DISCOVERY_FIND 1
23 -#define WORKER_DISCOVERY_PROCESS 2
24 -#define WORKER_DISCOVERY_PROCESS_RENAME 3
25 -#define WORKER_DISCOVERY_PROCESS_NETWORK 4
26 -#define WORKER_DISCOVERY_PROCESS_FIRST_TIME 5
27 -#define WORKER_DISCOVERY_UPDATE 6
28 -#define WORKER_DISCOVERY_CLEANUP 7
29 -#define WORKER_DISCOVERY_COPY 8
30 -#define WORKER_DISCOVERY_SHARE 9
31 -#define WORKER_DISCOVERY_LOCK 10
32 -
33 -#if WORKER_UTILIZATION_MAX_JOB_TYPES < 11
34 -#error WORKER_UTILIZATION_MAX_JOB_TYPES has to be at least 11
35 -#endif
36 -
10 // ----------------------------------------------------------------------------
11 // cgroup globals
12 +unsigned long long host_ram_total = 0;
13 +int is_inside_k8s = 0;
14 +long system_page_size = 4096; // system will be queried via sysconf() in configuration()
15 +int cgroup_enable_cpuacct_stat = CONFIG_BOOLEAN_AUTO;
16 +int cgroup_enable_cpuacct_usage = CONFIG_BOOLEAN_NO;
17 +int cgroup_enable_cpuacct_cpu_throttling = CONFIG_BOOLEAN_YES;
18 +int cgroup_enable_cpuacct_cpu_shares = CONFIG_BOOLEAN_NO;
19 +int cgroup_enable_memory = CONFIG_BOOLEAN_AUTO;
20 +int cgroup_enable_detailed_memory = CONFIG_BOOLEAN_AUTO;
21 +int cgroup_enable_memory_failcnt = CONFIG_BOOLEAN_AUTO;
22 +int cgroup_enable_swap = CONFIG_BOOLEAN_AUTO;
23 +int cgroup_enable_blkio_io = CONFIG_BOOLEAN_AUTO;
24 +int cgroup_enable_blkio_ops = CONFIG_BOOLEAN_AUTO;
25 +int cgroup_enable_blkio_throttle_io = CONFIG_BOOLEAN_AUTO;
26 +int cgroup_enable_blkio_throttle_ops = CONFIG_BOOLEAN_AUTO;
27 +int cgroup_enable_blkio_merged_ops = CONFIG_BOOLEAN_AUTO;
28 +int cgroup_enable_blkio_queued_ops = CONFIG_BOOLEAN_AUTO;
29 +int cgroup_enable_pressure_cpu = CONFIG_BOOLEAN_AUTO;
30 +int cgroup_enable_pressure_io_some = CONFIG_BOOLEAN_AUTO;
31 +int cgroup_enable_pressure_io_full = CONFIG_BOOLEAN_AUTO;
32 +int cgroup_enable_pressure_memory_some = CONFIG_BOOLEAN_AUTO;
33 +int cgroup_enable_pressure_memory_full = CONFIG_BOOLEAN_AUTO;
34 +int cgroup_enable_pressure_irq_some = CONFIG_BOOLEAN_NO;
35 +int cgroup_enable_pressure_irq_full = CONFIG_BOOLEAN_AUTO;
36 +int cgroup_enable_systemd_services = CONFIG_BOOLEAN_YES;
37 +int cgroup_enable_systemd_services_detailed_memory = CONFIG_BOOLEAN_NO;
38 +int cgroup_used_memory = CONFIG_BOOLEAN_YES;
39 +int cgroup_use_unified_cgroups = CONFIG_BOOLEAN_NO;
40 +int cgroup_unified_exist = CONFIG_BOOLEAN_AUTO;
41 +int cgroup_search_in_devices = 1;
42 +int cgroup_check_for_new_every = 10;
43 +int cgroup_update_every = 1;
44 +int cgroup_containers_chart_priority = NETDATA_CHART_PRIO_CGROUPS_CONTAINERS;
45 +int cgroup_recheck_zero_blkio_every_iterations = 10;
46 +int cgroup_recheck_zero_mem_failcnt_every_iterations = 10;
47 +int cgroup_recheck_zero_mem_detailed_every_iterations = 10;
48 +char *cgroup_cpuacct_base = NULL;
49 +char *cgroup_cpuset_base = NULL;
50 +char *cgroup_blkio_base = NULL;
51 +char *cgroup_memory_base = NULL;
52 +char *cgroup_devices_base = NULL;
53 +char *cgroup_unified_base = NULL;
54 +int cgroup_root_count = 0;
55 +int cgroup_root_max = 1000;
56 +int cgroup_max_depth = 0;
57 +SIMPLE_PATTERN *enabled_cgroup_paths = NULL;
58 +SIMPLE_PATTERN *enabled_cgroup_names = NULL;
59 +SIMPLE_PATTERN *search_cgroup_paths = NULL;
60 +SIMPLE_PATTERN *enabled_cgroup_renames = NULL;
61 +SIMPLE_PATTERN *systemd_services_cgroups = NULL;
62 +SIMPLE_PATTERN *entrypoint_parent_process_comm = NULL;
63 +char *cgroups_network_interface_script = NULL;
64 +int cgroups_check = 0;
65 +uint32_t Read_hash = 0;
66 +uint32_t Write_hash = 0;
67 +uint32_t user_hash = 0;
68 +uint32_t system_hash = 0;
69 +uint32_t user_usec_hash = 0;
70 +uint32_t system_usec_hash = 0;
71 +uint32_t nr_periods_hash = 0;
72 +uint32_t nr_throttled_hash = 0;
73 +uint32_t throttled_time_hash = 0;
74 +uint32_t throttled_usec_hash = 0;
75
40 -static char cgroup_chart_id_prefix[] = "cgroup_";
41 -static char services_chart_id_prefix[] = "systemd_";
42 -
43 -static int is_inside_k8s = 0;
44 -
45 -static long system_page_size = 4096; // system will be queried via sysconf() in configuration()
46 -
47 -static int cgroup_enable_cpuacct_stat = CONFIG_BOOLEAN_AUTO;
48 -static int cgroup_enable_cpuacct_usage = CONFIG_BOOLEAN_AUTO;
49 -static int cgroup_enable_cpuacct_cpu_throttling = CONFIG_BOOLEAN_YES;
50 -static int cgroup_enable_cpuacct_cpu_shares = CONFIG_BOOLEAN_NO;
51 -static int cgroup_enable_memory = CONFIG_BOOLEAN_AUTO;
52 -static int cgroup_enable_detailed_memory = CONFIG_BOOLEAN_AUTO;
53 -static int cgroup_enable_memory_failcnt = CONFIG_BOOLEAN_AUTO;
54 -static int cgroup_enable_swap = CONFIG_BOOLEAN_AUTO;
55 -static int cgroup_enable_blkio_io = CONFIG_BOOLEAN_AUTO;
56 -static int cgroup_enable_blkio_ops = CONFIG_BOOLEAN_AUTO;
57 -static int cgroup_enable_blkio_throttle_io = CONFIG_BOOLEAN_AUTO;
58 -static int cgroup_enable_blkio_throttle_ops = CONFIG_BOOLEAN_AUTO;
59 -static int cgroup_enable_blkio_merged_ops = CONFIG_BOOLEAN_AUTO;
60 -static int cgroup_enable_blkio_queued_ops = CONFIG_BOOLEAN_AUTO;
61 -static int cgroup_enable_pressure_cpu = CONFIG_BOOLEAN_AUTO;
62 -static int cgroup_enable_pressure_io_some = CONFIG_BOOLEAN_AUTO;
63 -static int cgroup_enable_pressure_io_full = CONFIG_BOOLEAN_AUTO;
64 -static int cgroup_enable_pressure_memory_some = CONFIG_BOOLEAN_AUTO;
65 -static int cgroup_enable_pressure_memory_full = CONFIG_BOOLEAN_AUTO;
66 -static int cgroup_enable_pressure_irq_some = CONFIG_BOOLEAN_NO;
67 -static int cgroup_enable_pressure_irq_full = CONFIG_BOOLEAN_AUTO;
68 -
69 -static int cgroup_enable_systemd_services = CONFIG_BOOLEAN_YES;
70 -static int cgroup_enable_systemd_services_detailed_memory = CONFIG_BOOLEAN_NO;
71 -static int cgroup_used_memory = CONFIG_BOOLEAN_YES;
72 -
73 -static int cgroup_use_unified_cgroups = CONFIG_BOOLEAN_NO;
74 -static int cgroup_unified_exist = CONFIG_BOOLEAN_AUTO;
75 -
76 -static int cgroup_search_in_devices = 1;
77 -
78 -static int cgroup_check_for_new_every = 10;
79 -static int cgroup_update_every = 1;
80 -static int cgroup_containers_chart_priority = NETDATA_CHART_PRIO_CGROUPS_CONTAINERS;
81 -
82 -static int cgroup_recheck_zero_blkio_every_iterations = 10;
83 -static int cgroup_recheck_zero_mem_failcnt_every_iterations = 10;
84 -static int cgroup_recheck_zero_mem_detailed_every_iterations = 10;
85 -
86 -static char *cgroup_cpuacct_base = NULL;
87 -static char *cgroup_cpuset_base = NULL;
88 -static char *cgroup_blkio_base = NULL;
89 -static char *cgroup_memory_base = NULL;
90 -static char *cgroup_devices_base = NULL;
91 -static char *cgroup_unified_base = NULL;
92 -
93 -static int cgroup_root_count = 0;
94 -static int cgroup_root_max = 1000;
95 -static int cgroup_max_depth = 0;
96 -
97 -static SIMPLE_PATTERN *enabled_cgroup_paths = NULL;
98 -static SIMPLE_PATTERN *enabled_cgroup_names = NULL;
99 -static SIMPLE_PATTERN *search_cgroup_paths = NULL;
100 -static SIMPLE_PATTERN *enabled_cgroup_renames = NULL;
101 -static SIMPLE_PATTERN *systemd_services_cgroups = NULL;
102 -
103 -static SIMPLE_PATTERN *entrypoint_parent_process_comm = NULL;
104 -
105 -static char *cgroups_rename_script = NULL;
106 -static char *cgroups_network_interface_script = NULL;
107 -
108 -static int cgroups_check = 0;
109 -
110 -static uint32_t Read_hash = 0;
111 -static uint32_t Write_hash = 0;
112 -static uint32_t user_hash = 0;
113 -static uint32_t system_hash = 0;
114 -static uint32_t user_usec_hash = 0;
115 -static uint32_t system_usec_hash = 0;
116 -static uint32_t nr_periods_hash = 0;
117 -static uint32_t nr_throttled_hash = 0;
118 -static uint32_t throttled_time_hash = 0;
119 -static uint32_t throttled_usec_hash = 0;
120 -
121 -enum cgroups_type { CGROUPS_AUTODETECT_FAIL, CGROUPS_V1, CGROUPS_V2 };
122 -
123 -enum cgroups_systemd_setting {
124 - SYSTEMD_CGROUP_ERR,
125 - SYSTEMD_CGROUP_LEGACY,
126 - SYSTEMD_CGROUP_HYBRID,
127 - SYSTEMD_CGROUP_UNIFIED
128 -};
129 -
130 -struct cgroups_systemd_config_setting {
131 - char *name;
132 - enum cgroups_systemd_setting setting;
133 -};
76 +// *** WARNING *** The fields are not thread safe. Take care of safe usage.
77 +struct cgroup *cgroup_root = NULL;
78 +uv_mutex_t cgroup_root_mutex;
79
135 -static struct cgroups_systemd_config_setting cgroups_systemd_options[] = {
136 - { .name = "legacy", .setting = SYSTEMD_CGROUP_LEGACY },
137 - { .name = "hybrid", .setting = SYSTEMD_CGROUP_HYBRID },
138 - { .name = "unified", .setting = SYSTEMD_CGROUP_UNIFIED },
139 - { .name = NULL, .setting = SYSTEMD_CGROUP_ERR },
80 +struct cgroups_systemd_config_setting cgroups_systemd_options[] = {
81 + { .name = "legacy", .setting = SYSTEMD_CGROUP_LEGACY },
82 + { .name = "hybrid", .setting = SYSTEMD_CGROUP_HYBRID },
83 + { .name = "unified", .setting = SYSTEMD_CGROUP_UNIFIED },
84 + { .name = NULL, .setting = SYSTEMD_CGROUP_ERR },
85 };
86
87 // Shared memory with information from detected cgroups
88 netdata_ebpf_cgroup_shm_t shm_cgroup_ebpf = {NULL, NULL};
144 -static int shm_fd_cgroup_ebpf = -1;
89 +int shm_fd_cgroup_ebpf = -1;
90 sem_t *shm_mutex_cgroup_ebpf = SEM_FAILED;
91
92 +struct discovery_thread discovery_thread;
93 +
94 +
95 /* on Fed systemd is not in PATH for some reason */
96 #define SYSTEMD_CMD_RHEL "/usr/lib/systemd/systemd --version"
97 #define SYSTEMD_HIERARCHY_STRING "default-hierarchy="
@@ -621,395 +569,6 @@ end_init_shm:
569 shm_unlink(NETDATA_SHARED_MEMORY_EBPF_CGROUP_NAME);
570 }
571
624 -// ----------------------------------------------------------------------------
625 -// cgroup objects
626 -
627 -struct blkio {
628 - int updated;
629 - int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
630 - int delay_counter;
631 -
632 - char *filename;
633 -
634 - unsigned long long Read;
635 - unsigned long long Write;
636 -/*
637 - unsigned long long Sync;
638 - unsigned long long Async;
639 - unsigned long long Total;
640 -*/
641 -};
642 -
643 -// https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt
644 -struct memory {
645 - ARL_BASE *arl_base;
646 - ARL_ENTRY *arl_dirty;
647 - ARL_ENTRY *arl_swap;
648 -
649 - int updated_detailed;
650 - int updated_usage_in_bytes;
651 - int updated_msw_usage_in_bytes;
652 - int updated_failcnt;
653 -
654 - int enabled_detailed; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
655 - int enabled_usage_in_bytes; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
656 - int enabled_msw_usage_in_bytes; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
657 - int enabled_failcnt; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
658 -
659 - int delay_counter_detailed;
660 - int delay_counter_failcnt;
661 -
662 - char *filename_detailed;
663 - char *filename_usage_in_bytes;
664 - char *filename_msw_usage_in_bytes;
665 - char *filename_failcnt;
666 -
667 - int detailed_has_dirty;
668 - int detailed_has_swap;
669 -
670 - // detailed metrics
671 -/*
672 - unsigned long long cache;
673 - unsigned long long rss;
674 - unsigned long long rss_huge;
675 - unsigned long long mapped_file;
676 - unsigned long long writeback;
677 - unsigned long long dirty;
678 - unsigned long long swap;
679 - unsigned long long pgpgin;
680 - unsigned long long pgpgout;
681 - unsigned long long pgfault;
682 - unsigned long long pgmajfault;
683 - unsigned long long inactive_anon;
684 - unsigned long long active_anon;
685 - unsigned long long inactive_file;
686 - unsigned long long active_file;
687 - unsigned long long unevictable;
688 - unsigned long long hierarchical_memory_limit;
689 -*/
690 - //unified cgroups metrics
691 - unsigned long long anon;
692 - unsigned long long kernel_stack;
693 - unsigned long long slab;
694 - unsigned long long sock;
695 - unsigned long long shmem;
696 - unsigned long long anon_thp;
697 - //unsigned long long file_writeback;
698 - //unsigned long long file_dirty;
699 - //unsigned long long file;
700 -
701 - unsigned long long total_cache;
702 - unsigned long long total_rss;
703 - unsigned long long total_rss_huge;
704 - unsigned long long total_mapped_file;
705 - unsigned long long total_writeback;
706 - unsigned long long total_dirty;
707 - unsigned long long total_swap;
708 - unsigned long long total_pgpgin;
709 - unsigned long long total_pgpgout;
710 - unsigned long long total_pgfault;
711 - unsigned long long total_pgmajfault;
712 -/*
713 - unsigned long long total_inactive_anon;
714 - unsigned long long total_active_anon;
715 -*/
716 -
717 - unsigned long long total_inactive_file;
718 -
719 -/*
720 - unsigned long long total_active_file;
721 - unsigned long long total_unevictable;
722 -*/
723 -
724 - // single file metrics
725 - unsigned long long usage_in_bytes;
726 - unsigned long long msw_usage_in_bytes;
727 - unsigned long long failcnt;
728 -};
729 -
730 -// https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt
731 -struct cpuacct_stat {
732 - int updated;
733 - int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
734 -
735 - char *filename;
736 -
737 - unsigned long long user; // v1, v2(user_usec)
738 - unsigned long long system; // v1, v2(system_usec)
739 -};
740 -
741 -// https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt
742 -struct cpuacct_usage {
743 - int updated;
744 - int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
745 -
746 - char *filename;
747 -
748 - unsigned int cpus;
749 - unsigned long long *cpu_percpu;
750 -};
751 -
752 -// represents cpuacct/cpu.stat, for v2 'cpuacct_stat' is used for 'user_usec', 'system_usec'
753 -struct cpuacct_cpu_throttling {
754 - int updated;
755 - int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
756 -
757 - char *filename;
758 -
759 - unsigned long long nr_periods;
760 - unsigned long long nr_throttled;
761 - unsigned long long throttled_time;
762 -
763 - unsigned long long nr_throttled_perc;
764 -};
765 -
766 -// https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/resource_management_guide/sec-cpu#sect-cfs
767 -// https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/managing_monitoring_and_updating_the_kernel/using-cgroups-v2-to-control-distribution-of-cpu-time-for-applications_managing-monitoring-and-updating-the-kernel#proc_controlling-distribution-of-cpu-time-for-applications-by-adjusting-cpu-weight_using-cgroups-v2-to-control-distribution-of-cpu-time-for-applications
768 -struct cpuacct_cpu_shares {
769 - int updated;
770 - int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
771 -
772 - char *filename;
773 -
774 - unsigned long long shares;
775 -};
776 -
777 -struct cgroup_network_interface {
778 - const char *host_device;
779 - const char *container_device;
780 - struct cgroup_network_interface *next;
781 -};
782 -
783 -enum cgroups_container_orchestrator {
784 - CGROUPS_ORCHESTRATOR_UNSET,
785 - CGROUPS_ORCHESTRATOR_UNKNOWN,
786 - CGROUPS_ORCHESTRATOR_K8S
787 -};
788 -
789 -// *** WARNING *** The fields are not thread safe. Take care of safe usage.
790 -struct cgroup {
791 - uint32_t options;
792 -
793 - int first_time_seen; // first time seen by the discoverer
794 - int processed; // the discoverer is done processing a cgroup (resolved name, set 'enabled' option)
795 -
796 - char available; // found in the filesystem
797 - char enabled; // enabled in the config
798 -
799 - char pending_renames;
800 -
801 - char *id;
802 - uint32_t hash;
803 -
804 - char *intermediate_id; // TODO: remove it when the renaming script is fixed
805 -
806 - char *chart_id;
807 - uint32_t hash_chart_id;
808 -
809 - // 'cgroup_name' label value.
810 - // By default this is the *id (path), later changed to the resolved name (cgroup-name.sh) or systemd service name.
811 - char *name;
812 -
813 - RRDLABELS *chart_labels;
814 -
815 - int container_orchestrator;
816 -
817 - struct cpuacct_stat cpuacct_stat;
818 - struct cpuacct_usage cpuacct_usage;
819 - struct cpuacct_cpu_throttling cpuacct_cpu_throttling;
820 - struct cpuacct_cpu_shares cpuacct_cpu_shares;
821 -
822 - struct memory memory;
823 -
824 - struct blkio io_service_bytes; // bytes
825 - struct blkio io_serviced; // operations
826 -
827 - struct blkio throttle_io_service_bytes; // bytes
828 - struct blkio throttle_io_serviced; // operations
829 -
830 - struct blkio io_merged; // operations
831 - struct blkio io_queued; // operations
832 -
833 - struct cgroup_network_interface *interfaces;
834 -
835 - struct pressure cpu_pressure;
836 - struct pressure io_pressure;
837 - struct pressure memory_pressure;
838 - struct pressure irq_pressure;
839 -
840 - // per cgroup charts
841 - RRDSET *st_cpu;
842 - RRDSET *st_cpu_limit;
843 - RRDSET *st_cpu_per_core;
844 - RRDSET *st_cpu_nr_throttled;
845 - RRDSET *st_cpu_throttled_time;
846 - RRDSET *st_cpu_shares;
847 -
848 - RRDSET *st_mem;
849 - RRDSET *st_mem_utilization;
850 - RRDSET *st_writeback;
851 - RRDSET *st_mem_activity;
852 - RRDSET *st_pgfaults;
853 - RRDSET *st_mem_usage;
854 - RRDSET *st_mem_usage_limit;
855 - RRDSET *st_mem_failcnt;
856 -
857 - RRDSET *st_io;
858 - RRDSET *st_serviced_ops;
859 - RRDSET *st_throttle_io;
860 - RRDSET *st_throttle_serviced_ops;
861 - RRDSET *st_queued_ops;
862 - RRDSET *st_merged_ops;
863 -
864 - // per cgroup chart variables
865 - char *filename_cpuset_cpus;
866 - unsigned long long cpuset_cpus;
867 -
868 - char *filename_cpu_cfs_period;
869 - unsigned long long cpu_cfs_period;
870 -
871 - char *filename_cpu_cfs_quota;
872 - unsigned long long cpu_cfs_quota;
873 -
874 - const RRDSETVAR_ACQUIRED *chart_var_cpu_limit;
875 - NETDATA_DOUBLE prev_cpu_usage;
876 -
877 - char *filename_memory_limit;
878 - unsigned long long memory_limit;
879 - const RRDSETVAR_ACQUIRED *chart_var_memory_limit;
880 -
881 - char *filename_memoryswap_limit;
882 - unsigned long long memoryswap_limit;
883 - const RRDSETVAR_ACQUIRED *chart_var_memoryswap_limit;
884 -
885 - struct cgroup *next;
886 - struct cgroup *discovered_next;
887 -
888 -} *cgroup_root = NULL;
889 -
890 -uv_mutex_t cgroup_root_mutex;
891 -
892 -struct cgroup *discovered_cgroup_root = NULL;
893 -
894 -struct discovery_thread {
895 - uv_thread_t thread;
896 - uv_mutex_t mutex;
897 - uv_cond_t cond_var;
898 - int exited;
899 -} discovery_thread;
900 -
901 -// ---------------------------------------------------------------------------------------------
902 -
903 -static inline int matches_enabled_cgroup_paths(char *id) {
904 - return simple_pattern_matches(enabled_cgroup_paths, id);
905 -}
906 -
907 -static inline int matches_enabled_cgroup_names(char *name) {
908 - return simple_pattern_matches(enabled_cgroup_names, name);
909 -}
910 -
911 -static inline int matches_enabled_cgroup_renames(char *id) {
912 - return simple_pattern_matches(enabled_cgroup_renames, id);
913 -}
914 -
915 -static inline int matches_systemd_services_cgroups(char *id) {
916 - return simple_pattern_matches(systemd_services_cgroups, id);
917 -}
918 -
919 -static inline int matches_search_cgroup_paths(const char *dir) {
920 - return simple_pattern_matches(search_cgroup_paths, dir);
921 -}
922 -
923 -static inline int matches_entrypoint_parent_process_comm(const char *comm) {
924 - return simple_pattern_matches(entrypoint_parent_process_comm, comm);
925 -}
926 -
927 -static inline int is_cgroup_systemd_service(struct cgroup *cg) {
928 - return (cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE);
929 -}
930 -
931 -// ---------------------------------------------------------------------------------------------
932 -static int k8s_is_kubepod(struct cgroup *cg) {
933 - return cg->container_orchestrator == CGROUPS_ORCHESTRATOR_K8S;
934 -}
935 -
936 -static int k8s_is_container(const char *id) {
937 - // examples:
938 - // https://github.com/netdata/netdata/blob/0fc101679dcd12f1cb8acdd07bb4c85d8e553e53/collectors/cgroups.plugin/cgroup-name.sh#L121-L147
939 - const char *p = id;
940 - const char *pp = NULL;
941 - int i = 0;
942 - size_t l = 3; // pod
943 - while ((p = strstr(p, "pod"))) {
944 - i++;
945 - p += l;
946 - pp = p;
947 - }
948 - return !(i < 2 || !pp || !(pp = strchr(pp, '/')) || !pp++ || !*pp);
949 -}
950 -
951 -#define TASK_COMM_LEN 16
952 -
953 -static int k8s_get_container_first_proc_comm(const char *id, char *comm) {
954 - if (!k8s_is_container(id)) {
955 - return 1;
956 - }
957 -
958 - static procfile *ff = NULL;
959 -
960 - char filename[FILENAME_MAX + 1];
961 - snprintfz(filename, FILENAME_MAX, "%s/%s/cgroup.procs", cgroup_cpuacct_base, id);
962 -
963 - ff = procfile_reopen(ff, filename, NULL, CGROUP_PROCFILE_FLAG);
964 - if (unlikely(!ff)) {
965 - netdata_log_debug(D_CGROUP, "CGROUP: k8s_is_pause_container(): cannot open file '%s'.", filename);
966 - return 1;
967 - }
968 -
969 - ff = procfile_readall(ff);
970 - if (unlikely(!ff)) {
971 - netdata_log_debug(D_CGROUP, "CGROUP: k8s_is_pause_container(): cannot read file '%s'.", filename);
972 - return 1;
973 - }
974 -
975 - unsigned long lines = procfile_lines(ff);
976 - if (likely(lines < 2)) {
977 - return 1;
978 - }
979 -
980 - char *pid = procfile_lineword(ff, 0, 0);
981 - if (!pid || !*pid) {
982 - return 1;
983 - }
984 -
985 - snprintfz(filename, FILENAME_MAX, "%s/proc/%s/comm", netdata_configured_host_prefix, pid);
986 -
987 - ff = procfile_reopen(ff, filename, NULL, PROCFILE_FLAG_DEFAULT);
988 - if (unlikely(!ff)) {
989 - netdata_log_debug(D_CGROUP, "CGROUP: k8s_is_pause_container(): cannot open file '%s'.", filename);
990 - return 1;
991 - }
992 -
993 - ff = procfile_readall(ff);
994 - if (unlikely(!ff)) {
995 - netdata_log_debug(D_CGROUP, "CGROUP: k8s_is_pause_container(): cannot read file '%s'.", filename);
996 - return 1;
997 - }
998 -
999 - lines = procfile_lines(ff);
1000 - if (unlikely(lines != 2)) {
1001 - return 1;
1002 - }
1003 -
1004 - char *proc_comm = procfile_lineword(ff, 0, 0);
1005 - if (!proc_comm || !*proc_comm) {
1006 - return 1;
1007 - }
1008 -
1009 - strncpyz(comm, proc_comm, TASK_COMM_LEN);
1010 - return 0;
1011 -}
1012 -
572 // ---------------------------------------------------------------------------------------------
573
574 static unsigned long long calc_delta(unsigned long long curr, unsigned long long prev) {
@@ -1023,16 +582,7 @@ static unsigned long long calc_percentage(unsigned long long value, unsigned lon
582 if (total == 0) {
583 return 0;
584 }
1026 - return (NETDATA_DOUBLE)value / (NETDATA_DOUBLE)total * 100;
1027 -}
1028 -
1029 -static int calc_cgroup_depth(const char *id) {
1030 - int depth = 0;
1031 - const char *s;
1032 - for (s = id; *s; s++) {
1033 - depth += unlikely(*s == '/');
1034 - }
1035 - return depth;
585 + return (unsigned long long)((NETDATA_DOUBLE)value / (NETDATA_DOUBLE)total * 100);
586 }
587
588 // ----------------------------------------------------------------------------
@@ -1636,1777 +1186,178 @@ static inline void read_all_discovered_cgroups(struct cgroup *root) {
1186 }
1187 }
1188
1639 -// ----------------------------------------------------------------------------
1640 -// cgroup network interfaces
1641 -
1642 -#define CGROUP_NETWORK_INTERFACE_MAX_LINE 2048
1643 -static inline void read_cgroup_network_interfaces(struct cgroup *cg) {
1644 - netdata_log_debug(D_CGROUP, "looking for the network interfaces of cgroup '%s' with chart id '%s'", cg->id, cg->chart_id);
1645 -
1646 - pid_t cgroup_pid;
1647 - char cgroup_identifier[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1];
1648 -
1649 - if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
1650 - snprintfz(cgroup_identifier, CGROUP_NETWORK_INTERFACE_MAX_LINE, "%s%s", cgroup_cpuacct_base, cg->id);
1651 - }
1652 - else {
1653 - snprintfz(cgroup_identifier, CGROUP_NETWORK_INTERFACE_MAX_LINE, "%s%s", cgroup_unified_base, cg->id);
1654 - }
1655 -
1656 - netdata_log_debug(D_CGROUP, "executing cgroup_identifier %s --cgroup '%s' for cgroup '%s'", cgroups_network_interface_script, cgroup_identifier, cg->id);
1657 - FILE *fp_child_input, *fp_child_output;
1658 - (void)netdata_popen_raw_default_flags_and_environment(&cgroup_pid, &fp_child_input, &fp_child_output, cgroups_network_interface_script, "--cgroup", cgroup_identifier);
1659 - if(!fp_child_output) {
1660 - collector_error("CGROUP: cannot popen(%s --cgroup \"%s\", \"r\").", cgroups_network_interface_script, cgroup_identifier);
1661 - return;
1662 - }
1663 -
1664 - char *s;
1665 - char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1];
1666 - while((s = fgets(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, fp_child_output))) {
1667 - trim(s);
1668 -
1669 - if(*s && *s != '\n') {
1670 - char *t = s;
1671 - while(*t && *t != ' ') t++;
1672 - if(*t == ' ') {
1673 - *t = '\0';
1674 - t++;
1675 - }
1189 +// update CPU and memory limits
1190
1677 - if(!*s) {
1678 - collector_error("CGROUP: empty host interface returned by script");
1679 - continue;
1680 - }
1191 +static inline void update_cpu_limits(char **filename, unsigned long long *value, struct cgroup *cg) {
1192 + if(*filename) {
1193 + int ret = -1;
1194
1682 - if(!*t) {
1683 - collector_error("CGROUP: empty guest interface returned by script");
1684 - continue;
1195 + if(value == &cg->cpuset_cpus) {
1196 + unsigned long ncpus = read_cpuset_cpus(*filename, get_system_cpus());
1197 + if(ncpus) {
1198 + *value = ncpus;
1199 + ret = 0;
1200 }
1201 + }
1202 + else if(value == &cg->cpu_cfs_period || value == &cg->cpu_cfs_quota) {
1203 + ret = read_single_number_file(*filename, value);
1204 + }
1205 + else ret = -1;
1206
1687 - struct cgroup_network_interface *i = callocz(1, sizeof(struct cgroup_network_interface));
1688 - i->host_device = strdupz(s);
1689 - i->container_device = strdupz(t);
1690 - i->next = cg->interfaces;
1691 - cg->interfaces = i;
1692 -
1693 - collector_info("CGROUP: cgroup '%s' has network interface '%s' as '%s'", cg->id, i->host_device, i->container_device);
1694 -
1695 - // register a device rename to proc_net_dev.c
1696 - netdev_rename_device_add(
1697 - i->host_device, i->container_device, cg->chart_id, cg->chart_labels, k8s_is_kubepod(cg) ? "k8s." : "");
1207 + if(ret) {
1208 + collector_error("Cannot refresh cgroup %s cpu limit by reading '%s'. Will not update its limit anymore.", cg->id, *filename);
1209 + freez(*filename);
1210 + *filename = NULL;
1211 }
1212 }
1700 -
1701 - netdata_pclose(fp_child_input, fp_child_output, cgroup_pid);
1702 - // netdata_log_debug(D_CGROUP, "closed cgroup_identifier for cgroup '%s'", cg->id);
1213 }
1214
1705 -static inline void free_cgroup_network_interfaces(struct cgroup *cg) {
1706 - while(cg->interfaces) {
1707 - struct cgroup_network_interface *i = cg->interfaces;
1708 - cg->interfaces = i->next;
1709 -
1710 - // delete the registration of proc_net_dev rename
1711 - netdev_rename_device_del(i->host_device);
1215 +static inline void update_cpu_limits2(struct cgroup *cg) {
1216 + if(cg->filename_cpu_cfs_quota){
1217 + static procfile *ff = NULL;
1218
1713 - freez((void *)i->host_device);
1714 - freez((void *)i->container_device);
1715 - freez((void *)i);
1716 - }
1717 -}
1219 + ff = procfile_reopen(ff, cg->filename_cpu_cfs_quota, NULL, CGROUP_PROCFILE_FLAG);
1220 + if(unlikely(!ff)) {
1221 + goto cpu_limits2_err;
1222 + }
1223
1719 -// ----------------------------------------------------------------------------
1720 -// add/remove/find cgroup objects
1224 + ff = procfile_readall(ff);
1225 + if(unlikely(!ff)) {
1226 + goto cpu_limits2_err;
1227 + }
1228
1722 -#define CGROUP_CHARTID_LINE_MAX 1024
1229 + unsigned long lines = procfile_lines(ff);
1230
1724 -static inline char *cgroup_chart_id_strdupz(const char *s) {
1725 - if(!s || !*s) s = "/";
1231 + if (unlikely(lines < 1)) {
1232 + collector_error("CGROUP: file '%s' should have 1 lines.", cg->filename_cpu_cfs_quota);
1233 + return;
1234 + }
1235
1727 - if(*s == '/' && s[1] != '\0') s++;
1236 + cg->cpu_cfs_period = str2ull(procfile_lineword(ff, 0, 1), NULL);
1237 + cg->cpuset_cpus = get_system_cpus();
1238
1729 - char *r = strdupz(s);
1730 - netdata_fix_chart_id(r);
1239 + char *s = "max\n\0";
1240 + if(strcmp(s, procfile_lineword(ff, 0, 0)) == 0){
1241 + cg->cpu_cfs_quota = cg->cpu_cfs_period * cg->cpuset_cpus;
1242 + } else {
1243 + cg->cpu_cfs_quota = str2ull(procfile_lineword(ff, 0, 0), NULL);
1244 + }
1245 + netdata_log_debug(D_CGROUP, "CPU limits values: %llu %llu %llu", cg->cpu_cfs_period, cg->cpuset_cpus, cg->cpu_cfs_quota);
1246 + return;
1247
1732 - return r;
1733 -}
1248 +cpu_limits2_err:
1249 + collector_error("Cannot refresh cgroup %s cpu limit by reading '%s'. Will not update its limit anymore.", cg->id, cg->filename_cpu_cfs_quota);
1250 + freez(cg->filename_cpu_cfs_quota);
1251 + cg->filename_cpu_cfs_quota = NULL;
1252
1735 -// TODO: move the code to cgroup_chart_id_strdupz() when the renaming script is fixed
1736 -static inline void substitute_dots_in_id(char *s) {
1737 - // dots are used to distinguish chart type and id in streaming, so we should replace them
1738 - for (char *d = s; *d; d++) {
1739 - if (*d == '.')
1740 - *d = '-';
1253 }
1254 }
1255
1744 -// ----------------------------------------------------------------------------
1745 -// parse k8s labels
1256 +static inline int update_memory_limits(struct cgroup *cg) {
1257 + char **filename = &cg->filename_memory_limit;
1258 + const RRDSETVAR_ACQUIRED **chart_var = &cg->chart_var_memory_limit;
1259 + unsigned long long *value = &cg->memory_limit;
1260
1747 -char *cgroup_parse_resolved_name_and_labels(RRDLABELS *labels, char *data) {
1748 - // the first word, up to the first space is the name
1749 - char *name = strsep_skip_consecutive_separators(&data, " ");
1261 + if(*filename) {
1262 + if(unlikely(!*chart_var)) {
1263 + *chart_var = rrdsetvar_custom_chart_variable_add_and_acquire(cg->st_mem_usage, "memory_limit");
1264 + if(!*chart_var) {
1265 + collector_error("Cannot create cgroup %s chart variable '%s'. Will not update its limit anymore.", cg->id, "memory_limit");
1266 + freez(*filename);
1267 + *filename = NULL;
1268 + }
1269 + }
1270
1751 - // the rest are key=value pairs separated by comma
1752 - while(data) {
1753 - char *pair = strsep_skip_consecutive_separators(&data, ",");
1754 - rrdlabels_add_pair(labels, pair, RRDLABEL_SRC_AUTO | RRDLABEL_SRC_K8S);
1271 + if(*filename && *chart_var) {
1272 + if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
1273 + if(read_single_number_file(*filename, value)) {
1274 + collector_error("Cannot refresh cgroup %s memory limit by reading '%s'. Will not update its limit anymore.", cg->id, *filename);
1275 + freez(*filename);
1276 + *filename = NULL;
1277 + }
1278 + else {
1279 + rrdsetvar_custom_chart_variable_set(cg->st_mem_usage, *chart_var, (NETDATA_DOUBLE)(*value) / (1024.0 * 1024.0));
1280 + return 1;
1281 + }
1282 + } else {
1283 + char buffer[30 + 1];
1284 + int ret = read_file(*filename, buffer, 30);
1285 + if(ret) {
1286 + collector_error("Cannot refresh cgroup %s memory limit by reading '%s'. Will not update its limit anymore.", cg->id, *filename);
1287 + freez(*filename);
1288 + *filename = NULL;
1289 + return 0;
1290 + }
1291 + char *s = "max\n\0";
1292 + if(strcmp(s, buffer) == 0){
1293 + *value = UINT64_MAX;
1294 + rrdsetvar_custom_chart_variable_set(cg->st_mem_usage, *chart_var, (NETDATA_DOUBLE)(*value) / (1024.0 * 1024.0));
1295 + return 1;
1296 + }
1297 + *value = str2ull(buffer, NULL);
1298 + rrdsetvar_custom_chart_variable_set(cg->st_mem_usage, *chart_var, (NETDATA_DOUBLE)(*value) / (1024.0 * 1024.0));
1299 + return 1;
1300 + }
1301 + }
1302 }
1756 -
1757 - return name;
1303 + return 0;
1304 }
1305
1306 // ----------------------------------------------------------------------------
1307 +// generate charts
1308
1762 -static inline void free_pressure(struct pressure *res) {
1763 - if (res->some.share_time.st) rrdset_is_obsolete___safe_from_collector_thread(res->some.share_time.st);
1764 - if (res->some.total_time.st) rrdset_is_obsolete___safe_from_collector_thread(res->some.total_time.st);
1765 - if (res->full.share_time.st) rrdset_is_obsolete___safe_from_collector_thread(res->full.share_time.st);
1766 - if (res->full.total_time.st) rrdset_is_obsolete___safe_from_collector_thread(res->full.total_time.st);
1767 - freez(res->filename);
1768 -}
1769 -
1770 -static inline void cgroup_free(struct cgroup *cg) {
1771 - netdata_log_debug(D_CGROUP, "Removing cgroup '%s' with chart id '%s' (was %s and %s)", cg->id, cg->chart_id, (cg->enabled)?"enabled":"disabled", (cg->available)?"available":"not available");
1772 -
1773 - if(cg->st_cpu) rrdset_is_obsolete___safe_from_collector_thread(cg->st_cpu);
1774 - if(cg->st_cpu_limit) rrdset_is_obsolete___safe_from_collector_thread(cg->st_cpu_limit);
1775 - if(cg->st_cpu_per_core) rrdset_is_obsolete___safe_from_collector_thread(cg->st_cpu_per_core);
1776 - if(cg->st_cpu_nr_throttled) rrdset_is_obsolete___safe_from_collector_thread(cg->st_cpu_nr_throttled);
1777 - if(cg->st_cpu_throttled_time) rrdset_is_obsolete___safe_from_collector_thread(cg->st_cpu_throttled_time);
1778 - if(cg->st_cpu_shares) rrdset_is_obsolete___safe_from_collector_thread(cg->st_cpu_shares);
1779 - if(cg->st_mem) rrdset_is_obsolete___safe_from_collector_thread(cg->st_mem);
1780 - if(cg->st_writeback) rrdset_is_obsolete___safe_from_collector_thread(cg->st_writeback);
1781 - if(cg->st_mem_activity) rrdset_is_obsolete___safe_from_collector_thread(cg->st_mem_activity);
1782 - if(cg->st_pgfaults) rrdset_is_obsolete___safe_from_collector_thread(cg->st_pgfaults);
1783 - if(cg->st_mem_usage) rrdset_is_obsolete___safe_from_collector_thread(cg->st_mem_usage);
1784 - if(cg->st_mem_usage_limit) rrdset_is_obsolete___safe_from_collector_thread(cg->st_mem_usage_limit);
1785 - if(cg->st_mem_utilization) rrdset_is_obsolete___safe_from_collector_thread(cg->st_mem_utilization);
1786 - if(cg->st_mem_failcnt) rrdset_is_obsolete___safe_from_collector_thread(cg->st_mem_failcnt);
1787 - if(cg->st_io) rrdset_is_obsolete___safe_from_collector_thread(cg->st_io);
1788 - if(cg->st_serviced_ops) rrdset_is_obsolete___safe_from_collector_thread(cg->st_serviced_ops);
1789 - if(cg->st_throttle_io) rrdset_is_obsolete___safe_from_collector_thread(cg->st_throttle_io);
1790 - if(cg->st_throttle_serviced_ops) rrdset_is_obsolete___safe_from_collector_thread(cg->st_throttle_serviced_ops);
1791 - if(cg->st_queued_ops) rrdset_is_obsolete___safe_from_collector_thread(cg->st_queued_ops);
1792 - if(cg->st_merged_ops) rrdset_is_obsolete___safe_from_collector_thread(cg->st_merged_ops);
1793 -
1794 - freez(cg->filename_cpuset_cpus);
1795 - freez(cg->filename_cpu_cfs_period);
1796 - freez(cg->filename_cpu_cfs_quota);
1797 - freez(cg->filename_memory_limit);
1798 - freez(cg->filename_memoryswap_limit);
1799 -
1800 - free_cgroup_network_interfaces(cg);
1801 -
1802 - freez(cg->cpuacct_usage.cpu_percpu);
1803 -
1804 - freez(cg->cpuacct_stat.filename);
1805 - freez(cg->cpuacct_usage.filename);
1806 - freez(cg->cpuacct_cpu_throttling.filename);
1807 - freez(cg->cpuacct_cpu_shares.filename);
1808 -
1809 - arl_free(cg->memory.arl_base);
1810 - freez(cg->memory.filename_detailed);
1811 - freez(cg->memory.filename_failcnt);
1812 - freez(cg->memory.filename_usage_in_bytes);
1813 - freez(cg->memory.filename_msw_usage_in_bytes);
1814 -
1815 - freez(cg->io_service_bytes.filename);
1816 - freez(cg->io_serviced.filename);
1817 -
1818 - freez(cg->throttle_io_service_bytes.filename);
1819 - freez(cg->throttle_io_serviced.filename);
1820 -
1821 - freez(cg->io_merged.filename);
1822 - freez(cg->io_queued.filename);
1823 -
1824 - free_pressure(&cg->cpu_pressure);
1825 - free_pressure(&cg->io_pressure);
1826 - free_pressure(&cg->memory_pressure);
1827 - free_pressure(&cg->irq_pressure);
1828 -
1829 - freez(cg->id);
1830 - freez(cg->intermediate_id);
1831 - freez(cg->chart_id);
1832 - freez(cg->name);
1833 -
1834 - rrdlabels_destroy(cg->chart_labels);
1835 -
1836 - freez(cg);
1837 -
1838 - cgroup_root_count--;
1839 -}
1840 -
1841 -// ----------------------------------------------------------------------------
1842 -
1843 -static inline void discovery_rename_cgroup(struct cgroup *cg) {
1844 - if (!cg->pending_renames) {
1845 - return;
1846 - }
1847 - cg->pending_renames--;
1848 -
1849 - netdata_log_debug(D_CGROUP, "looking for the name of cgroup '%s' with chart id '%s'", cg->id, cg->chart_id);
1850 - netdata_log_debug(D_CGROUP, "executing command %s \"%s\" for cgroup '%s'", cgroups_rename_script, cg->intermediate_id, cg->chart_id);
1851 - pid_t cgroup_pid;
1852 -
1853 - FILE *fp_child_input, *fp_child_output;
1854 - (void)netdata_popen_raw_default_flags_and_environment(&cgroup_pid, &fp_child_input, &fp_child_output, cgroups_rename_script, cg->id, cg->intermediate_id);
1855 - if (!fp_child_output) {
1856 - collector_error("CGROUP: cannot popen(%s \"%s\", \"r\").", cgroups_rename_script, cg->intermediate_id);
1857 - cg->pending_renames = 0;
1858 - cg->processed = 1;
1859 - return;
1860 - }
1861 -
1862 - char buffer[CGROUP_CHARTID_LINE_MAX + 1];
1863 - char *new_name = fgets(buffer, CGROUP_CHARTID_LINE_MAX, fp_child_output);
1864 - int exit_code = netdata_pclose(fp_child_input, fp_child_output, cgroup_pid);
1865 -
1866 - switch (exit_code) {
1867 - case 0:
1868 - cg->pending_renames = 0;
1869 - break;
1870 -
1871 - case 3:
1872 - cg->pending_renames = 0;
1873 - cg->processed = 1;
1874 - break;
1875 - }
1876 -
1877 - if (cg->pending_renames || cg->processed)
1878 - return;
1879 - if (!new_name || !*new_name || *new_name == '\n')
1880 - return;
1881 - if (!(new_name = trim(new_name)))
1882 - return;
1883 -
1884 - char *name = new_name;
1885 -
1886 - if (!cg->chart_labels)
1887 - cg->chart_labels = rrdlabels_create();
1888 - // read the new labels and remove the obsolete ones
1889 - rrdlabels_unmark_all(cg->chart_labels);
1890 - name = cgroup_parse_resolved_name_and_labels(cg->chart_labels, new_name);
1891 - rrdlabels_remove_all_unmarked(cg->chart_labels);
1892 -
1893 - freez(cg->name);
1894 - cg->name = strdupz(name);
1895 -
1896 - freez(cg->chart_id);
1897 - cg->chart_id = cgroup_chart_id_strdupz(name);
1898 -
1899 - substitute_dots_in_id(cg->chart_id);
1900 - cg->hash_chart_id = simple_hash(cg->chart_id);
1901 -}
1902 -
1903 -static void is_cgroup_procs_exist(netdata_ebpf_cgroup_shm_body_t *out, char *id) {
1904 - struct stat buf;
1905 -
1906 - snprintfz(out->path, FILENAME_MAX, "%s%s/cgroup.procs", cgroup_cpuset_base, id);
1907 - if (likely(stat(out->path, &buf) == 0)) {
1908 - return;
1909 - }
1910 -
1911 - snprintfz(out->path, FILENAME_MAX, "%s%s/cgroup.procs", cgroup_blkio_base, id);
1912 - if (likely(stat(out->path, &buf) == 0)) {
1913 - return;
1914 - }
1915 -
1916 - snprintfz(out->path, FILENAME_MAX, "%s%s/cgroup.procs", cgroup_memory_base, id);
1917 - if (likely(stat(out->path, &buf) == 0)) {
1918 - return;
1919 - }
1920 -
1921 - snprintfz(out->path, FILENAME_MAX, "%s%s/cgroup.procs", cgroup_devices_base, id);
1922 - if (likely(stat(out->path, &buf) == 0)) {
1923 - return;
1924 - }
1925 -
1926 - out->path[0] = '\0';
1927 - out->enabled = 0;
1928 -}
1929 -
1930 -static inline void convert_cgroup_to_systemd_service(struct cgroup *cg) {
1931 - char buffer[CGROUP_CHARTID_LINE_MAX + 1];
1932 - cg->options |= CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE;
1933 - strncpyz(buffer, cg->id, CGROUP_CHARTID_LINE_MAX);
1934 - char *s = buffer;
1935 -
1936 - // skip to the last slash
1937 - size_t len = strlen(s);
1938 - while (len--) {
1939 - if (unlikely(s[len] == '/')) {
1940 - break;
1941 - }
1942 - }
1943 - if (len) {
1944 - s = &s[len + 1];
1945 - }
1946 -
1947 - // remove extension
1948 - len = strlen(s);
1949 - while (len--) {
1950 - if (unlikely(s[len] == '.')) {
1951 - break;
1952 - }
1953 - }
1954 - if (len) {
1955 - s[len] = '\0';
1956 - }
1957 -
1958 - freez(cg->name);
1959 - cg->name = strdupz(s);
1960 -
1961 - freez(cg->chart_id);
1962 - cg->chart_id = cgroup_chart_id_strdupz(s);
1963 - substitute_dots_in_id(cg->chart_id);
1964 - cg->hash_chart_id = simple_hash(cg->chart_id);
1965 -}
1966 -
1967 -static inline struct cgroup *discovery_cgroup_add(const char *id) {
1968 - netdata_log_debug(D_CGROUP, "adding to list, cgroup with id '%s'", id);
1969 -
1970 - struct cgroup *cg = callocz(1, sizeof(struct cgroup));
1971 -
1972 - cg->id = strdupz(id);
1973 - cg->hash = simple_hash(cg->id);
1974 -
1975 - cg->name = strdupz(id);
1976 -
1977 - cg->intermediate_id = cgroup_chart_id_strdupz(id);
1978 -
1979 - cg->chart_id = cgroup_chart_id_strdupz(id);
1980 - substitute_dots_in_id(cg->chart_id);
1981 - cg->hash_chart_id = simple_hash(cg->chart_id);
1982 -
1983 - if (cgroup_use_unified_cgroups) {
1984 - cg->options |= CGROUP_OPTIONS_IS_UNIFIED;
1985 - }
1986 -
1987 - if (!discovered_cgroup_root)
1988 - discovered_cgroup_root = cg;
1989 - else {
1990 - struct cgroup *t;
1991 - for (t = discovered_cgroup_root; t->discovered_next; t = t->discovered_next) {
1992 - }
1993 - t->discovered_next = cg;
1994 - }
1995 -
1996 - return cg;
1997 -}
1998 -
1999 -static inline struct cgroup *discovery_cgroup_find(const char *id) {
2000 - netdata_log_debug(D_CGROUP, "searching for cgroup '%s'", id);
2001 -
2002 - uint32_t hash = simple_hash(id);
2003 -
2004 - struct cgroup *cg;
2005 - for(cg = discovered_cgroup_root; cg ; cg = cg->discovered_next) {
2006 - if(hash == cg->hash && strcmp(id, cg->id) == 0)
2007 - break;
2008 - }
2009 -
2010 - netdata_log_debug(D_CGROUP, "cgroup '%s' %s in memory", id, (cg)?"found":"not found");
2011 - return cg;
2012 -}
2013 -
2014 -static inline void discovery_find_cgroup_in_dir_callback(const char *dir) {
2015 - if (!dir || !*dir) {
2016 - dir = "/";
2017 - }
2018 - netdata_log_debug(D_CGROUP, "examining cgroup dir '%s'", dir);
2019 -
2020 - struct cgroup *cg = discovery_cgroup_find(dir);
2021 - if (cg) {
2022 - cg->available = 1;
2023 - return;
2024 - }
2025 -
2026 - if (cgroup_root_count >= cgroup_root_max) {
2027 - collector_info("CGROUP: maximum number of cgroups reached (%d). Not adding cgroup '%s'", cgroup_root_count, dir);
2028 - return;
2029 - }
2030 -
2031 - if (cgroup_max_depth > 0) {
2032 - int depth = calc_cgroup_depth(dir);
2033 - if (depth > cgroup_max_depth) {
2034 - collector_info("CGROUP: '%s' is too deep (%d, while max is %d)", dir, depth, cgroup_max_depth);
2035 - return;
2036 - }
2037 - }
2038 -
2039 - cg = discovery_cgroup_add(dir);
2040 - cg->available = 1;
2041 - cg->first_time_seen = 1;
2042 - cgroup_root_count++;
2043 -}
2044 -
2045 -static inline int discovery_find_dir_in_subdirs(const char *base, const char *this, void (*callback)(const char *)) {
2046 - if(!this) this = base;
2047 - netdata_log_debug(D_CGROUP, "searching for directories in '%s' (base '%s')", this?this:"", base);
2048 -
2049 - size_t dirlen = strlen(this), baselen = strlen(base);
2050 -
2051 - int ret = -1;
2052 - int enabled = -1;
2053 -
2054 - const char *relative_path = &this[baselen];
2055 - if(!*relative_path) relative_path = "/";
2056 -
2057 - DIR *dir = opendir(this);
2058 - if(!dir) {
2059 - collector_error("CGROUP: cannot read directory '%s'", base);
2060 - return ret;
2061 - }
2062 - ret = 1;
2063 -
2064 - callback(relative_path);
2065 -
2066 - struct dirent *de = NULL;
2067 - while((de = readdir(dir))) {
2068 - if(de->d_type == DT_DIR
2069 - && (
2070 - (de->d_name[0] == '.' && de->d_name[1] == '\0')
2071 - || (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
2072 - ))
2073 - continue;
2074 -
2075 - if(de->d_type == DT_DIR) {
2076 - if(enabled == -1) {
2077 - const char *r = relative_path;
2078 - if(*r == '\0') r = "/";
2079 -
2080 - // do not decent in directories we are not interested
2081 - enabled = matches_search_cgroup_paths(r);
2082 - }
2083 -
2084 - if(enabled) {
2085 - char *s = mallocz(dirlen + strlen(de->d_name) + 2);
2086 - strcpy(s, this);
2087 - strcat(s, "/");
2088 - strcat(s, de->d_name);
2089 - int ret2 = discovery_find_dir_in_subdirs(base, s, callback);
2090 - if(ret2 > 0) ret += ret2;
2091 - freez(s);
2092 - }
2093 - }
2094 - }
2095 -
2096 - closedir(dir);
2097 - return ret;
2098 -}
2099 -
2100 -static inline void discovery_mark_all_cgroups_as_unavailable() {
2101 - netdata_log_debug(D_CGROUP, "marking all cgroups as not available");
2102 - struct cgroup *cg;
2103 - for (cg = discovered_cgroup_root; cg; cg = cg->discovered_next) {
2104 - cg->available = 0;
2105 - }
2106 -}
2107 -
2108 -static inline void discovery_update_filenames() {
2109 - struct cgroup *cg;
2110 - struct stat buf;
2111 - for(cg = discovered_cgroup_root; cg ; cg = cg->discovered_next) {
2112 - if(unlikely(!cg->available || !cg->enabled || cg->pending_renames))
2113 - continue;
2114 -
2115 - netdata_log_debug(D_CGROUP, "checking paths for cgroup '%s'", cg->id);
2116 -
2117 - // check for newly added cgroups
2118 - // and update the filenames they read
2119 - char filename[FILENAME_MAX + 1];
2120 - if(!cgroup_use_unified_cgroups) {
2121 - if(unlikely(cgroup_enable_cpuacct_stat && !cg->cpuacct_stat.filename)) {
2122 - snprintfz(filename, FILENAME_MAX, "%s%s/cpuacct.stat", cgroup_cpuacct_base, cg->id);
2123 - if(likely(stat(filename, &buf) != -1)) {
2124 - cg->cpuacct_stat.filename = strdupz(filename);
2125 - cg->cpuacct_stat.enabled = cgroup_enable_cpuacct_stat;
2126 - snprintfz(filename, FILENAME_MAX, "%s%s/cpuset.cpus", cgroup_cpuset_base, cg->id);
2127 - cg->filename_cpuset_cpus = strdupz(filename);
2128 - snprintfz(filename, FILENAME_MAX, "%s%s/cpu.cfs_period_us", cgroup_cpuacct_base, cg->id);
2129 - cg->filename_cpu_cfs_period = strdupz(filename);
2130 - snprintfz(filename, FILENAME_MAX, "%s%s/cpu.cfs_quota_us", cgroup_cpuacct_base, cg->id);
2131 - cg->filename_cpu_cfs_quota = strdupz(filename);
2132 - netdata_log_debug(D_CGROUP, "cpuacct.stat filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_stat.filename);
2133 - }
2134 - else
2135 - netdata_log_debug(D_CGROUP, "cpuacct.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2136 - }
2137 -
2138 - if(unlikely(cgroup_enable_cpuacct_usage && !cg->cpuacct_usage.filename && !is_cgroup_systemd_service(cg))) {
2139 - snprintfz(filename, FILENAME_MAX, "%s%s/cpuacct.usage_percpu", cgroup_cpuacct_base, cg->id);
2140 - if(likely(stat(filename, &buf) != -1)) {
2141 - cg->cpuacct_usage.filename = strdupz(filename);
2142 - cg->cpuacct_usage.enabled = cgroup_enable_cpuacct_usage;
2143 - netdata_log_debug(D_CGROUP, "cpuacct.usage_percpu filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_usage.filename);
2144 - }
2145 - else
2146 - netdata_log_debug(D_CGROUP, "cpuacct.usage_percpu file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2147 - }
2148 - if(unlikely(cgroup_enable_cpuacct_cpu_throttling && !cg->cpuacct_cpu_throttling.filename && !is_cgroup_systemd_service(cg))) {
2149 - snprintfz(filename, FILENAME_MAX, "%s%s/cpu.stat", cgroup_cpuacct_base, cg->id);
2150 - if(likely(stat(filename, &buf) != -1)) {
2151 - cg->cpuacct_cpu_throttling.filename = strdupz(filename);
2152 - cg->cpuacct_cpu_throttling.enabled = cgroup_enable_cpuacct_cpu_throttling;
2153 - netdata_log_debug(D_CGROUP, "cpu.stat filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_cpu_throttling.filename);
2154 - }
2155 - else
2156 - netdata_log_debug(D_CGROUP, "cpu.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2157 - }
2158 - if (unlikely(
2159 - cgroup_enable_cpuacct_cpu_shares && !cg->cpuacct_cpu_shares.filename &&
2160 - !is_cgroup_systemd_service(cg))) {
2161 - snprintfz(filename, FILENAME_MAX, "%s%s/cpu.shares", cgroup_cpuacct_base, cg->id);
2162 - if (likely(stat(filename, &buf) != -1)) {
2163 - cg->cpuacct_cpu_shares.filename = strdupz(filename);
2164 - cg->cpuacct_cpu_shares.enabled = cgroup_enable_cpuacct_cpu_shares;
2165 - netdata_log_debug(
2166 - D_CGROUP, "cpu.shares filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_cpu_shares.filename);
2167 - } else
2168 - netdata_log_debug(D_CGROUP, "cpu.shares file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2169 - }
2170 -
2171 - if(unlikely((cgroup_enable_detailed_memory || cgroup_used_memory) && !cg->memory.filename_detailed && (cgroup_used_memory || cgroup_enable_systemd_services_detailed_memory || !is_cgroup_systemd_service(cg)))) {
2172 - snprintfz(filename, FILENAME_MAX, "%s%s/memory.stat", cgroup_memory_base, cg->id);
2173 - if(likely(stat(filename, &buf) != -1)) {
2174 - cg->memory.filename_detailed = strdupz(filename);
2175 - cg->memory.enabled_detailed = (cgroup_enable_detailed_memory == CONFIG_BOOLEAN_YES)?CONFIG_BOOLEAN_YES:CONFIG_BOOLEAN_AUTO;
2176 - netdata_log_debug(D_CGROUP, "memory.stat filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_detailed);
2177 - }
2178 - else
2179 - netdata_log_debug(D_CGROUP, "memory.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2180 - }
2181 -
2182 - if(unlikely(cgroup_enable_memory && !cg->memory.filename_usage_in_bytes)) {
2183 - snprintfz(filename, FILENAME_MAX, "%s%s/memory.usage_in_bytes", cgroup_memory_base, cg->id);
2184 - if(likely(stat(filename, &buf) != -1)) {
2185 - cg->memory.filename_usage_in_bytes = strdupz(filename);
2186 - cg->memory.enabled_usage_in_bytes = cgroup_enable_memory;
2187 - netdata_log_debug(D_CGROUP, "memory.usage_in_bytes filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_usage_in_bytes);
2188 - snprintfz(filename, FILENAME_MAX, "%s%s/memory.limit_in_bytes", cgroup_memory_base, cg->id);
2189 - cg->filename_memory_limit = strdupz(filename);
2190 - }
2191 - else
2192 - netdata_log_debug(D_CGROUP, "memory.usage_in_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2193 - }
2194 -
2195 - if(unlikely(cgroup_enable_swap && !cg->memory.filename_msw_usage_in_bytes)) {
2196 - snprintfz(filename, FILENAME_MAX, "%s%s/memory.memsw.usage_in_bytes", cgroup_memory_base, cg->id);
2197 - if(likely(stat(filename, &buf) != -1)) {
2198 - cg->memory.filename_msw_usage_in_bytes = strdupz(filename);
2199 - cg->memory.enabled_msw_usage_in_bytes = cgroup_enable_swap;
2200 - snprintfz(filename, FILENAME_MAX, "%s%s/memory.memsw.limit_in_bytes", cgroup_memory_base, cg->id);
2201 - cg->filename_memoryswap_limit = strdupz(filename);
2202 - netdata_log_debug(D_CGROUP, "memory.msw_usage_in_bytes filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_msw_usage_in_bytes);
2203 - }
2204 - else
2205 - netdata_log_debug(D_CGROUP, "memory.msw_usage_in_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2206 - }
2207 -
2208 - if(unlikely(cgroup_enable_memory_failcnt && !cg->memory.filename_failcnt)) {
2209 - snprintfz(filename, FILENAME_MAX, "%s%s/memory.failcnt", cgroup_memory_base, cg->id);
2210 - if(likely(stat(filename, &buf) != -1)) {
2211 - cg->memory.filename_failcnt = strdupz(filename);
2212 - cg->memory.enabled_failcnt = cgroup_enable_memory_failcnt;
2213 - netdata_log_debug(D_CGROUP, "memory.failcnt filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_failcnt);
2214 - }
2215 - else
2216 - netdata_log_debug(D_CGROUP, "memory.failcnt file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2217 - }
2218 -
2219 - if(unlikely(cgroup_enable_blkio_io && !cg->io_service_bytes.filename)) {
2220 - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_service_bytes_recursive", cgroup_blkio_base, cg->id);
2221 - if (unlikely(stat(filename, &buf) != -1)) {
2222 - cg->io_service_bytes.filename = strdupz(filename);
2223 - cg->io_service_bytes.enabled = cgroup_enable_blkio_io;
2224 - netdata_log_debug(D_CGROUP, "blkio.io_service_bytes_recursive filename for cgroup '%s': '%s'", cg->id, cg->io_service_bytes.filename);
2225 - } else {
2226 - netdata_log_debug(D_CGROUP, "blkio.io_service_bytes_recursive file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2227 - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_service_bytes", cgroup_blkio_base, cg->id);
2228 - if (likely(stat(filename, &buf) != -1)) {
2229 - cg->io_service_bytes.filename = strdupz(filename);
2230 - cg->io_service_bytes.enabled = cgroup_enable_blkio_io;
2231 - netdata_log_debug(D_CGROUP, "blkio.io_service_bytes filename for cgroup '%s': '%s'", cg->id, cg->io_service_bytes.filename);
2232 - } else {
2233 - netdata_log_debug(D_CGROUP, "blkio.io_service_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2234 - }
2235 - }
2236 - }
2237 -
2238 - if (unlikely(cgroup_enable_blkio_ops && !cg->io_serviced.filename)) {
2239 - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_serviced_recursive", cgroup_blkio_base, cg->id);
2240 - if (unlikely(stat(filename, &buf) != -1)) {
2241 - cg->io_serviced.filename = strdupz(filename);
2242 - cg->io_serviced.enabled = cgroup_enable_blkio_ops;
2243 - netdata_log_debug(D_CGROUP, "blkio.io_serviced_recursive filename for cgroup '%s': '%s'", cg->id, cg->io_serviced.filename);
2244 - } else {
2245 - netdata_log_debug(D_CGROUP, "blkio.io_serviced_recursive file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2246 - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_serviced", cgroup_blkio_base, cg->id);
2247 - if (likely(stat(filename, &buf) != -1)) {
2248 - cg->io_serviced.filename = strdupz(filename);
2249 - cg->io_serviced.enabled = cgroup_enable_blkio_ops;
2250 - netdata_log_debug(D_CGROUP, "blkio.io_serviced filename for cgroup '%s': '%s'", cg->id, cg->io_serviced.filename);
2251 - } else {
2252 - netdata_log_debug(D_CGROUP, "blkio.io_serviced file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2253 - }
2254 - }
2255 - }
2256 -
2257 - if (unlikely(cgroup_enable_blkio_throttle_io && !cg->throttle_io_service_bytes.filename)) {
2258 - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_service_bytes_recursive", cgroup_blkio_base, cg->id);
2259 - if (unlikely(stat(filename, &buf) != -1)) {
2260 - cg->throttle_io_service_bytes.filename = strdupz(filename);
2261 - cg->throttle_io_service_bytes.enabled = cgroup_enable_blkio_throttle_io;
2262 - netdata_log_debug(D_CGROUP,"blkio.throttle.io_service_bytes_recursive filename for cgroup '%s': '%s'", cg->id, cg->throttle_io_service_bytes.filename);
2263 - } else {
2264 - netdata_log_debug(D_CGROUP, "blkio.throttle.io_service_bytes_recursive file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2265 - snprintfz(
2266 - filename, FILENAME_MAX, "%s%s/blkio.throttle.io_service_bytes", cgroup_blkio_base, cg->id);
2267 - if (likely(stat(filename, &buf) != -1)) {
2268 - cg->throttle_io_service_bytes.filename = strdupz(filename);
2269 - cg->throttle_io_service_bytes.enabled = cgroup_enable_blkio_throttle_io;
2270 - netdata_log_debug(D_CGROUP, "blkio.throttle.io_service_bytes filename for cgroup '%s': '%s'", cg->id, cg->throttle_io_service_bytes.filename);
2271 - } else {
2272 - netdata_log_debug(D_CGROUP, "blkio.throttle.io_service_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2273 - }
2274 - }
2275 - }
2276 -
2277 - if (unlikely(cgroup_enable_blkio_throttle_ops && !cg->throttle_io_serviced.filename)) {
2278 - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_serviced_recursive", cgroup_blkio_base, cg->id);
2279 - if (unlikely(stat(filename, &buf) != -1)) {
2280 - cg->throttle_io_serviced.filename = strdupz(filename);
2281 - cg->throttle_io_serviced.enabled = cgroup_enable_blkio_throttle_ops;
2282 - netdata_log_debug(D_CGROUP, "blkio.throttle.io_serviced_recursive filename for cgroup '%s': '%s'", cg->id, cg->throttle_io_serviced.filename);
2283 - } else {
2284 - netdata_log_debug(D_CGROUP, "blkio.throttle.io_serviced_recursive file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2285 - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_serviced", cgroup_blkio_base, cg->id);
2286 - if (likely(stat(filename, &buf) != -1)) {
2287 - cg->throttle_io_serviced.filename = strdupz(filename);
2288 - cg->throttle_io_serviced.enabled = cgroup_enable_blkio_throttle_ops;
2289 - netdata_log_debug(D_CGROUP, "blkio.throttle.io_serviced filename for cgroup '%s': '%s'", cg->id, cg->throttle_io_serviced.filename);
2290 - } else {
2291 - netdata_log_debug(D_CGROUP, "blkio.throttle.io_serviced file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2292 - }
2293 - }
2294 - }
2295 -
2296 - if (unlikely(cgroup_enable_blkio_merged_ops && !cg->io_merged.filename)) {
2297 - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_merged_recursive", cgroup_blkio_base, cg->id);
2298 - if (unlikely(stat(filename, &buf) != -1)) {
2299 - cg->io_merged.filename = strdupz(filename);
2300 - cg->io_merged.enabled = cgroup_enable_blkio_merged_ops;
2301 - netdata_log_debug(D_CGROUP, "blkio.io_merged_recursive filename for cgroup '%s': '%s'", cg->id, cg->io_merged.filename);
2302 - } else {
2303 - netdata_log_debug(D_CGROUP, "blkio.io_merged_recursive file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2304 - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_merged", cgroup_blkio_base, cg->id);
2305 - if (likely(stat(filename, &buf) != -1)) {
2306 - cg->io_merged.filename = strdupz(filename);
2307 - cg->io_merged.enabled = cgroup_enable_blkio_merged_ops;
2308 - netdata_log_debug(D_CGROUP, "blkio.io_merged filename for cgroup '%s': '%s'", cg->id, cg->io_merged.filename);
2309 - } else {
2310 - netdata_log_debug(D_CGROUP, "blkio.io_merged file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2311 - }
2312 - }
2313 - }
2314 -
2315 - if (unlikely(cgroup_enable_blkio_queued_ops && !cg->io_queued.filename)) {
2316 - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_queued_recursive", cgroup_blkio_base, cg->id);
2317 - if (unlikely(stat(filename, &buf) != -1)) {
2318 - cg->io_queued.filename = strdupz(filename);
2319 - cg->io_queued.enabled = cgroup_enable_blkio_queued_ops;
2320 - netdata_log_debug(D_CGROUP, "blkio.io_queued_recursive filename for cgroup '%s': '%s'", cg->id, cg->io_queued.filename);
2321 - } else {
2322 - netdata_log_debug(D_CGROUP, "blkio.io_queued_recursive file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2323 - snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_queued", cgroup_blkio_base, cg->id);
2324 - if (likely(stat(filename, &buf) != -1)) {
2325 - cg->io_queued.filename = strdupz(filename);
2326 - cg->io_queued.enabled = cgroup_enable_blkio_queued_ops;
2327 - netdata_log_debug(D_CGROUP, "blkio.io_queued filename for cgroup '%s': '%s'", cg->id, cg->io_queued.filename);
2328 - } else {
2329 - netdata_log_debug(D_CGROUP, "blkio.io_queued file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2330 - }
2331 - }
2332 - }
2333 - }
2334 - else if(likely(cgroup_unified_exist)) {
2335 - if(unlikely(cgroup_enable_blkio_io && !cg->io_service_bytes.filename)) {
2336 - snprintfz(filename, FILENAME_MAX, "%s%s/io.stat", cgroup_unified_base, cg->id);
2337 - if(likely(stat(filename, &buf) != -1)) {
2338 - cg->io_service_bytes.filename = strdupz(filename);
2339 - cg->io_service_bytes.enabled = cgroup_enable_blkio_io;
2340 - netdata_log_debug(D_CGROUP, "io.stat filename for unified cgroup '%s': '%s'", cg->id, cg->io_service_bytes.filename);
2341 - } else
2342 - netdata_log_debug(D_CGROUP, "io.stat file for unified cgroup '%s': '%s' does not exist.", cg->id, filename);
2343 - }
2344 - if (unlikely(cgroup_enable_blkio_ops && !cg->io_serviced.filename)) {
2345 - snprintfz(filename, FILENAME_MAX, "%s%s/io.stat", cgroup_unified_base, cg->id);
2346 - if (likely(stat(filename, &buf) != -1)) {
2347 - cg->io_serviced.filename = strdupz(filename);
2348 - cg->io_serviced.enabled = cgroup_enable_blkio_ops;
2349 - netdata_log_debug(D_CGROUP, "io.stat filename for unified cgroup '%s': '%s'", cg->id, cg->io_service_bytes.filename);
2350 - } else
2351 - netdata_log_debug(D_CGROUP, "io.stat file for unified cgroup '%s': '%s' does not exist.", cg->id, filename);
2352 - }
2353 - if (unlikely(
2354 - (cgroup_enable_cpuacct_stat || cgroup_enable_cpuacct_cpu_throttling) &&
2355 - !cg->cpuacct_stat.filename)) {
2356 - snprintfz(filename, FILENAME_MAX, "%s%s/cpu.stat", cgroup_unified_base, cg->id);
2357 - if(likely(stat(filename, &buf) != -1)) {
2358 - cg->cpuacct_stat.filename = strdupz(filename);
2359 - cg->cpuacct_stat.enabled = cgroup_enable_cpuacct_stat;
2360 - cg->cpuacct_cpu_throttling.enabled = cgroup_enable_cpuacct_cpu_throttling;
2361 - cg->filename_cpuset_cpus = NULL;
2362 - cg->filename_cpu_cfs_period = NULL;
2363 - snprintfz(filename, FILENAME_MAX, "%s%s/cpu.max", cgroup_unified_base, cg->id);
2364 - cg->filename_cpu_cfs_quota = strdupz(filename);
2365 - netdata_log_debug(D_CGROUP, "cpu.stat filename for unified cgroup '%s': '%s'", cg->id, cg->cpuacct_stat.filename);
2366 - }
2367 - else
2368 - netdata_log_debug(D_CGROUP, "cpu.stat file for unified cgroup '%s': '%s' does not exist.", cg->id, filename);
2369 - }
2370 - if (unlikely(cgroup_enable_cpuacct_cpu_shares && !cg->cpuacct_cpu_shares.filename)) {
2371 - snprintfz(filename, FILENAME_MAX, "%s%s/cpu.weight", cgroup_unified_base, cg->id);
2372 - if (likely(stat(filename, &buf) != -1)) {
2373 - cg->cpuacct_cpu_shares.filename = strdupz(filename);
2374 - cg->cpuacct_cpu_shares.enabled = cgroup_enable_cpuacct_cpu_shares;
2375 - netdata_log_debug(D_CGROUP, "cpu.weight filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_cpu_shares.filename);
2376 - } else
2377 - netdata_log_debug(D_CGROUP, "cpu.weight file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2378 - }
2379 -
2380 - if(unlikely((cgroup_enable_detailed_memory || cgroup_used_memory) && !cg->memory.filename_detailed && (cgroup_used_memory || cgroup_enable_systemd_services_detailed_memory || !is_cgroup_systemd_service(cg)))) {
2381 - snprintfz(filename, FILENAME_MAX, "%s%s/memory.stat", cgroup_unified_base, cg->id);
2382 - if(likely(stat(filename, &buf) != -1)) {
2383 - cg->memory.filename_detailed = strdupz(filename);
2384 - cg->memory.enabled_detailed = (cgroup_enable_detailed_memory == CONFIG_BOOLEAN_YES)?CONFIG_BOOLEAN_YES:CONFIG_BOOLEAN_AUTO;
2385 - netdata_log_debug(D_CGROUP, "memory.stat filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_detailed);
2386 - }
2387 - else
2388 - netdata_log_debug(D_CGROUP, "memory.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2389 - }
2390 -
2391 - if(unlikely(cgroup_enable_memory && !cg->memory.filename_usage_in_bytes)) {
2392 - snprintfz(filename, FILENAME_MAX, "%s%s/memory.current", cgroup_unified_base, cg->id);
2393 - if(likely(stat(filename, &buf) != -1)) {
2394 - cg->memory.filename_usage_in_bytes = strdupz(filename);
2395 - cg->memory.enabled_usage_in_bytes = cgroup_enable_memory;
2396 - netdata_log_debug(D_CGROUP, "memory.current filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_usage_in_bytes);
2397 - snprintfz(filename, FILENAME_MAX, "%s%s/memory.max", cgroup_unified_base, cg->id);
2398 - cg->filename_memory_limit = strdupz(filename);
2399 - }
2400 - else
2401 - netdata_log_debug(D_CGROUP, "memory.current file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2402 - }
2403 -
2404 - if(unlikely(cgroup_enable_swap && !cg->memory.filename_msw_usage_in_bytes)) {
2405 - snprintfz(filename, FILENAME_MAX, "%s%s/memory.swap.current", cgroup_unified_base, cg->id);
2406 - if(likely(stat(filename, &buf) != -1)) {
2407 - cg->memory.filename_msw_usage_in_bytes = strdupz(filename);
2408 - cg->memory.enabled_msw_usage_in_bytes = cgroup_enable_swap;
2409 - snprintfz(filename, FILENAME_MAX, "%s%s/memory.swap.max", cgroup_unified_base, cg->id);
2410 - cg->filename_memoryswap_limit = strdupz(filename);
2411 - netdata_log_debug(D_CGROUP, "memory.swap.current filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_msw_usage_in_bytes);
2412 - }
2413 - else
2414 - netdata_log_debug(D_CGROUP, "memory.swap file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2415 - }
2416 -
2417 - if (unlikely(cgroup_enable_pressure_cpu && !cg->cpu_pressure.filename)) {
2418 - snprintfz(filename, FILENAME_MAX, "%s%s/cpu.pressure", cgroup_unified_base, cg->id);
2419 - if (likely(stat(filename, &buf) != -1)) {
2420 - cg->cpu_pressure.filename = strdupz(filename);
2421 - cg->cpu_pressure.some.enabled = cgroup_enable_pressure_cpu;
2422 - cg->cpu_pressure.full.enabled = CONFIG_BOOLEAN_NO;
2423 - netdata_log_debug(D_CGROUP, "cpu.pressure filename for cgroup '%s': '%s'", cg->id, cg->cpu_pressure.filename);
2424 - } else {
2425 - netdata_log_debug(D_CGROUP, "cpu.pressure file for cgroup '%s': '%s' does not exist", cg->id, filename);
2426 - }
2427 - }
2428 -
2429 - if (unlikely((cgroup_enable_pressure_io_some || cgroup_enable_pressure_io_full) && !cg->io_pressure.filename)) {
2430 - snprintfz(filename, FILENAME_MAX, "%s%s/io.pressure", cgroup_unified_base, cg->id);
2431 - if (likely(stat(filename, &buf) != -1)) {
2432 - cg->io_pressure.filename = strdupz(filename);
2433 - cg->io_pressure.some.enabled = cgroup_enable_pressure_io_some;
2434 - cg->io_pressure.full.enabled = cgroup_enable_pressure_io_full;
2435 - netdata_log_debug(D_CGROUP, "io.pressure filename for cgroup '%s': '%s'", cg->id, cg->io_pressure.filename);
2436 - } else {
2437 - netdata_log_debug(D_CGROUP, "io.pressure file for cgroup '%s': '%s' does not exist", cg->id, filename);
2438 - }
2439 - }
2440 -
2441 - if (unlikely((cgroup_enable_pressure_memory_some || cgroup_enable_pressure_memory_full) && !cg->memory_pressure.filename)) {
2442 - snprintfz(filename, FILENAME_MAX, "%s%s/memory.pressure", cgroup_unified_base, cg->id);
2443 - if (likely(stat(filename, &buf) != -1)) {
2444 - cg->memory_pressure.filename = strdupz(filename);
2445 - cg->memory_pressure.some.enabled = cgroup_enable_pressure_memory_some;
2446 - cg->memory_pressure.full.enabled = cgroup_enable_pressure_memory_full;
2447 - netdata_log_debug(D_CGROUP, "memory.pressure filename for cgroup '%s': '%s'", cg->id, cg->memory_pressure.filename);
2448 - } else {
2449 - netdata_log_debug(D_CGROUP, "memory.pressure file for cgroup '%s': '%s' does not exist", cg->id, filename);
2450 - }
2451 - }
2452 -
2453 - if (unlikely((cgroup_enable_pressure_irq_some || cgroup_enable_pressure_irq_full) && !cg->irq_pressure.filename)) {
2454 - snprintfz(filename, FILENAME_MAX, "%s%s/irq.pressure", cgroup_unified_base, cg->id);
2455 - if (likely(stat(filename, &buf) != -1)) {
2456 - cg->irq_pressure.filename = strdupz(filename);
2457 - cg->irq_pressure.some.enabled = cgroup_enable_pressure_irq_some;
2458 - cg->irq_pressure.full.enabled = cgroup_enable_pressure_irq_full;
2459 - netdata_log_debug(D_CGROUP, "irq.pressure filename for cgroup '%s': '%s'", cg->id, cg->irq_pressure.filename);
2460 - } else {
2461 - netdata_log_debug(D_CGROUP, "irq.pressure file for cgroup '%s': '%s' does not exist", cg->id, filename);
2462 - }
2463 - }
2464 - }
2465 - }
2466 -}
2467 -
2468 -static inline void discovery_cleanup_all_cgroups() {
2469 - struct cgroup *cg = discovered_cgroup_root, *last = NULL;
2470 -
2471 - for(; cg ;) {
2472 - if(!cg->available) {
2473 - // enable the first duplicate cgroup
2474 - {
2475 - struct cgroup *t;
2476 - for (t = discovered_cgroup_root; t; t = t->discovered_next) {
2477 - if (t != cg && t->available && !t->enabled && t->options & CGROUP_OPTIONS_DISABLED_DUPLICATE &&
2478 - (is_cgroup_systemd_service(t) == is_cgroup_systemd_service(cg)) &&
2479 - t->hash_chart_id == cg->hash_chart_id && !strcmp(t->chart_id, cg->chart_id)) {
2480 - netdata_log_debug(D_CGROUP, "Enabling duplicate of cgroup '%s' with id '%s', because the original with id '%s' stopped.", t->chart_id, t->id, cg->id);
2481 - t->enabled = 1;
2482 - t->options &= ~CGROUP_OPTIONS_DISABLED_DUPLICATE;
2483 - break;
2484 - }
2485 - }
2486 - }
2487 -
2488 - if(!last)
2489 - discovered_cgroup_root = cg->discovered_next;
2490 - else
2491 - last->discovered_next = cg->discovered_next;
2492 -
2493 - cgroup_free(cg);
2494 -
2495 - if(!last)
2496 - cg = discovered_cgroup_root;
2497 - else
2498 - cg = last->discovered_next;
2499 - }
2500 - else {
2501 - last = cg;
2502 - cg = cg->discovered_next;
2503 - }
2504 - }
2505 -}
2506 -
2507 -static inline void discovery_copy_discovered_cgroups_to_reader() {
2508 - netdata_log_debug(D_CGROUP, "copy discovered cgroups to the main group list");
2509 -
2510 - struct cgroup *cg;
2511 -
2512 - for (cg = discovered_cgroup_root; cg; cg = cg->discovered_next) {
2513 - cg->next = cg->discovered_next;
2514 - }
2515 -
2516 - cgroup_root = discovered_cgroup_root;
2517 -}
2518 -
2519 -static inline void discovery_share_cgroups_with_ebpf() {
2520 - struct cgroup *cg;
2521 - int count;
2522 - struct stat buf;
2523 -
2524 - if (shm_mutex_cgroup_ebpf == SEM_FAILED) {
2525 - return;
2526 - }
2527 - sem_wait(shm_mutex_cgroup_ebpf);
2528 -
2529 - for (cg = cgroup_root, count = 0; cg; cg = cg->next, count++) {
2530 - netdata_ebpf_cgroup_shm_body_t *ptr = &shm_cgroup_ebpf.body[count];
2531 - char *prefix = (is_cgroup_systemd_service(cg)) ? services_chart_id_prefix : cgroup_chart_id_prefix;
2532 - snprintfz(ptr->name, CGROUP_EBPF_NAME_SHARED_LENGTH - 1, "%s%s", prefix, cg->chart_id);
2533 - ptr->hash = simple_hash(ptr->name);
2534 - ptr->options = cg->options;
2535 - ptr->enabled = cg->enabled;
2536 - if (cgroup_use_unified_cgroups) {
2537 - snprintfz(ptr->path, FILENAME_MAX, "%s%s/cgroup.procs", cgroup_unified_base, cg->id);
2538 - if (likely(stat(ptr->path, &buf) == -1)) {
2539 - ptr->path[0] = '\0';
2540 - ptr->enabled = 0;
2541 - }
2542 - } else {
2543 - is_cgroup_procs_exist(ptr, cg->id);
2544 - }
2545 -
2546 - netdata_log_debug(D_CGROUP, "cgroup shared: NAME=%s, ENABLED=%d", ptr->name, ptr->enabled);
2547 - }
2548 -
2549 - shm_cgroup_ebpf.header->cgroup_root_count = count;
2550 - sem_post(shm_mutex_cgroup_ebpf);
2551 -}
2552 -
2553 -static inline void discovery_find_all_cgroups_v1() {
2554 - if (cgroup_enable_cpuacct_stat || cgroup_enable_cpuacct_usage) {
2555 - if (discovery_find_dir_in_subdirs(cgroup_cpuacct_base, NULL, discovery_find_cgroup_in_dir_callback) == -1) {
2556 - cgroup_enable_cpuacct_stat = cgroup_enable_cpuacct_usage = CONFIG_BOOLEAN_NO;
2557 - collector_error("CGROUP: disabled cpu statistics.");
2558 - }
2559 - }
2560 -
2561 - if (cgroup_enable_blkio_io || cgroup_enable_blkio_ops || cgroup_enable_blkio_throttle_io ||
2562 - cgroup_enable_blkio_throttle_ops || cgroup_enable_blkio_merged_ops || cgroup_enable_blkio_queued_ops) {
2563 - if (discovery_find_dir_in_subdirs(cgroup_blkio_base, NULL, discovery_find_cgroup_in_dir_callback) == -1) {
2564 - cgroup_enable_blkio_io = cgroup_enable_blkio_ops = cgroup_enable_blkio_throttle_io =
2565 - cgroup_enable_blkio_throttle_ops = cgroup_enable_blkio_merged_ops = cgroup_enable_blkio_queued_ops =
2566 - CONFIG_BOOLEAN_NO;
2567 - collector_error("CGROUP: disabled blkio statistics.");
2568 - }
2569 - }
2570 -
2571 - if (cgroup_enable_memory || cgroup_enable_detailed_memory || cgroup_enable_swap || cgroup_enable_memory_failcnt) {
2572 - if (discovery_find_dir_in_subdirs(cgroup_memory_base, NULL, discovery_find_cgroup_in_dir_callback) == -1) {
2573 - cgroup_enable_memory = cgroup_enable_detailed_memory = cgroup_enable_swap = cgroup_enable_memory_failcnt =
2574 - CONFIG_BOOLEAN_NO;
2575 - collector_error("CGROUP: disabled memory statistics.");
2576 - }
2577 - }
2578 -
2579 - if (cgroup_search_in_devices) {
2580 - if (discovery_find_dir_in_subdirs(cgroup_devices_base, NULL, discovery_find_cgroup_in_dir_callback) == -1) {
2581 - cgroup_search_in_devices = 0;
2582 - collector_error("CGROUP: disabled devices statistics.");
2583 - }
2584 - }
2585 -}
2586 -
2587 -static inline void discovery_find_all_cgroups_v2() {
2588 - if (discovery_find_dir_in_subdirs(cgroup_unified_base, NULL, discovery_find_cgroup_in_dir_callback) == -1) {
2589 - cgroup_unified_exist = CONFIG_BOOLEAN_NO;
2590 - collector_error("CGROUP: disabled unified cgroups statistics.");
2591 - }
2592 -}
2593 -
2594 -static int is_digits_only(const char *s) {
2595 - do {
2596 - if (!isdigit(*s++)) {
2597 - return 0;
2598 - }
2599 - } while (*s);
2600 -
2601 - return 1;
2602 -}
2603 -
2604 -static inline void discovery_process_first_time_seen_cgroup(struct cgroup *cg) {
2605 - if (!cg->first_time_seen) {
2606 - return;
2607 - }
2608 - cg->first_time_seen = 0;
2609 -
2610 - char comm[TASK_COMM_LEN + 1];
2611 -
2612 - if (cg->container_orchestrator == CGROUPS_ORCHESTRATOR_UNSET) {
2613 - if (strstr(cg->id, "kubepods")) {
2614 - cg->container_orchestrator = CGROUPS_ORCHESTRATOR_K8S;
2615 - } else {
2616 - cg->container_orchestrator = CGROUPS_ORCHESTRATOR_UNKNOWN;
2617 - }
2618 - }
2619 -
2620 - if (is_inside_k8s && !k8s_get_container_first_proc_comm(cg->id, comm)) {
2621 - // container initialization may take some time when CPU % is high
2622 - // seen on GKE: comm is '6' before 'runc:[2:INIT]' (dunno if it could be another number)
2623 - if (is_digits_only(comm) || matches_entrypoint_parent_process_comm(comm)) {
2624 - cg->first_time_seen = 1;
2625 - return;
2626 - }
2627 - if (!strcmp(comm, "pause")) {
2628 - // a container that holds the network namespace for the pod
2629 - // we don't need to collect its metrics
2630 - cg->processed = 1;
2631 - return;
2632 - }
2633 - }
2634 -
2635 - if (cgroup_enable_systemd_services && matches_systemd_services_cgroups(cg->id)) {
2636 - netdata_log_debug(D_CGROUP, "cgroup '%s' (name '%s') matches 'cgroups to match as systemd services'", cg->id, cg->chart_id);
2637 - convert_cgroup_to_systemd_service(cg);
2638 - return;
2639 - }
2640 -
2641 - if (matches_enabled_cgroup_renames(cg->id)) {
2642 - netdata_log_debug(D_CGROUP, "cgroup '%s' (name '%s') matches 'run script to rename cgroups matching', will try to rename it", cg->id, cg->chart_id);
2643 - if (is_inside_k8s && k8s_is_container(cg->id)) {
2644 - // it may take up to a minute for the K8s API to return data for the container
2645 - // tested on AWS K8s cluster with 100% CPU utilization
2646 - cg->pending_renames = 9; // 1.5 minute
2647 - } else {
2648 - cg->pending_renames = 2;
2649 - }
2650 - }
2651 -}
2652 -
2653 -static int discovery_is_cgroup_duplicate(struct cgroup *cg) {
2654 - // https://github.com/netdata/netdata/issues/797#issuecomment-241248884
2655 - struct cgroup *c;
2656 - for (c = discovered_cgroup_root; c; c = c->discovered_next) {
2657 - if (c != cg && c->enabled && (is_cgroup_systemd_service(c) == is_cgroup_systemd_service(cg)) &&
2658 - c->hash_chart_id == cg->hash_chart_id && !strcmp(c->chart_id, cg->chart_id)) {
2659 - collector_error(
2660 - "CGROUP: chart id '%s' already exists with id '%s' and is enabled and available. Disabling cgroup with id '%s'.",
2661 - cg->chart_id,
2662 - c->id,
2663 - cg->id);
2664 - return 1;
2665 - }
2666 - }
2667 - return 0;
2668 -}
2669 -
2670 -static inline void discovery_process_cgroup(struct cgroup *cg) {
2671 - if (!cg) {
2672 - netdata_log_debug(D_CGROUP, "discovery_process_cgroup() received NULL");
2673 - return;
2674 - }
2675 - if (!cg->available || cg->processed) {
2676 - return;
2677 - }
2678 -
2679 - if (cg->first_time_seen) {
2680 - worker_is_busy(WORKER_DISCOVERY_PROCESS_FIRST_TIME);
2681 - discovery_process_first_time_seen_cgroup(cg);
2682 - if (unlikely(cg->first_time_seen || cg->processed)) {
2683 - return;
2684 - }
2685 - }
2686 -
2687 - if (cg->pending_renames) {
2688 - worker_is_busy(WORKER_DISCOVERY_PROCESS_RENAME);
2689 - discovery_rename_cgroup(cg);
2690 - if (unlikely(cg->pending_renames || cg->processed)) {
2691 - return;
2692 - }
2693 - }
2694 -
2695 - cg->processed = 1;
2696 -
2697 - if ((strlen(cg->chart_id) + strlen(cgroup_chart_id_prefix)) >= RRD_ID_LENGTH_MAX) {
2698 - collector_info("cgroup '%s' (chart id '%s') disabled because chart_id exceeds the limit (RRD_ID_LENGTH_MAX)", cg->id, cg->chart_id);
2699 - return;
2700 - }
2701 -
2702 - if (is_cgroup_systemd_service(cg)) {
2703 - if (discovery_is_cgroup_duplicate(cg)) {
2704 - cg->enabled = 0;
2705 - cg->options |= CGROUP_OPTIONS_DISABLED_DUPLICATE;
2706 - return;
2707 - }
2708 - if (!cg->chart_labels)
2709 - cg->chart_labels = rrdlabels_create();
2710 - rrdlabels_add(cg->chart_labels, "service_name", cg->name, RRDLABEL_SRC_AUTO);
2711 - cg->enabled = 1;
2712 - return;
2713 - }
2714 -
2715 - if (!(cg->enabled = matches_enabled_cgroup_names(cg->name))) {
2716 - netdata_log_debug(D_CGROUP, "cgroup '%s' (name '%s') disabled by 'enable by default cgroups names matching'", cg->id, cg->name);
2717 - return;
2718 - }
2719 -
2720 - if (!(cg->enabled = matches_enabled_cgroup_paths(cg->id))) {
2721 - netdata_log_debug(D_CGROUP, "cgroup '%s' (name '%s') disabled by 'enable by default cgroups matching'", cg->id, cg->name);
2722 - return;
2723 - }
2724 -
2725 - if (discovery_is_cgroup_duplicate(cg)) {
2726 - cg->enabled = 0;
2727 - cg->options |= CGROUP_OPTIONS_DISABLED_DUPLICATE;
2728 - return;
2729 - }
2730 -
2731 - if (!cg->chart_labels)
2732 - cg->chart_labels = rrdlabels_create();
2733 -
2734 - if (!k8s_is_kubepod(cg)) {
2735 - rrdlabels_add(cg->chart_labels, "cgroup_name", cg->name, RRDLABEL_SRC_AUTO);
2736 - if (!rrdlabels_exist(cg->chart_labels, "image"))
2737 - rrdlabels_add(cg->chart_labels, "image", "", RRDLABEL_SRC_AUTO);
2738 - }
2739 -
2740 - worker_is_busy(WORKER_DISCOVERY_PROCESS_NETWORK);
2741 - read_cgroup_network_interfaces(cg);
2742 -}
2743 -
2744 -static inline void discovery_find_all_cgroups() {
2745 - netdata_log_debug(D_CGROUP, "searching for cgroups");
2746 -
2747 - worker_is_busy(WORKER_DISCOVERY_INIT);
2748 - discovery_mark_all_cgroups_as_unavailable();
2749 -
2750 - worker_is_busy(WORKER_DISCOVERY_FIND);
2751 - if (!cgroup_use_unified_cgroups) {
2752 - discovery_find_all_cgroups_v1();
2753 - } else {
2754 - discovery_find_all_cgroups_v2();
2755 - }
2756 -
2757 - struct cgroup *cg;
2758 - for (cg = discovered_cgroup_root; cg; cg = cg->discovered_next) {
2759 - worker_is_busy(WORKER_DISCOVERY_PROCESS);
2760 - discovery_process_cgroup(cg);
2761 - }
2762 -
2763 - worker_is_busy(WORKER_DISCOVERY_UPDATE);
2764 - discovery_update_filenames();
2765 -
2766 - worker_is_busy(WORKER_DISCOVERY_LOCK);
2767 - uv_mutex_lock(&cgroup_root_mutex);
2768 -
2769 - worker_is_busy(WORKER_DISCOVERY_CLEANUP);
2770 - discovery_cleanup_all_cgroups();
2771 -
2772 - worker_is_busy(WORKER_DISCOVERY_COPY);
2773 - discovery_copy_discovered_cgroups_to_reader();
2774 -
2775 - uv_mutex_unlock(&cgroup_root_mutex);
2776 -
2777 - worker_is_busy(WORKER_DISCOVERY_SHARE);
2778 - discovery_share_cgroups_with_ebpf();
2779 -
2780 - netdata_log_debug(D_CGROUP, "done searching for cgroups");
2781 -}
2782 -
2783 -static inline char *cgroup_chart_type(char *buffer, struct cgroup *cg) {
2784 - if(buffer[0]) return buffer;
2785 -
2786 - if (cg->chart_id[0] == '\0' || (cg->chart_id[0] == '/' && cg->chart_id[1] == '\0'))
2787 - strncpy(buffer, "cgroup_root", RRD_ID_LENGTH_MAX);
2788 - else if (is_cgroup_systemd_service(cg))
2789 - snprintfz(buffer, RRD_ID_LENGTH_MAX, "%s%s", services_chart_id_prefix, cg->chart_id);
2790 - else
2791 - snprintfz(buffer, RRD_ID_LENGTH_MAX, "%s%s", cgroup_chart_id_prefix, cg->chart_id);
2792 -
2793 - return buffer;
2794 -}
2795 -
2796 -void cgroup_discovery_worker(void *ptr)
2797 -{
2798 - UNUSED(ptr);
2799 -
2800 - worker_register("CGROUPSDISC");
2801 - worker_register_job_name(WORKER_DISCOVERY_INIT, "init");
2802 - worker_register_job_name(WORKER_DISCOVERY_FIND, "find");
2803 - worker_register_job_name(WORKER_DISCOVERY_PROCESS, "process");
2804 - worker_register_job_name(WORKER_DISCOVERY_PROCESS_RENAME, "rename");
2805 - worker_register_job_name(WORKER_DISCOVERY_PROCESS_NETWORK, "network");
2806 - worker_register_job_name(WORKER_DISCOVERY_PROCESS_FIRST_TIME, "new");
2807 - worker_register_job_name(WORKER_DISCOVERY_UPDATE, "update");
2808 - worker_register_job_name(WORKER_DISCOVERY_CLEANUP, "cleanup");
2809 - worker_register_job_name(WORKER_DISCOVERY_COPY, "copy");
2810 - worker_register_job_name(WORKER_DISCOVERY_SHARE, "share");
2811 - worker_register_job_name(WORKER_DISCOVERY_LOCK, "lock");
2812 -
2813 - entrypoint_parent_process_comm = simple_pattern_create(
2814 - " runc:[* " // http://terenceli.github.io/%E6%8A%80%E6%9C%AF/2021/12/28/runc-internals-3)
2815 - " exe ", // https://github.com/falcosecurity/falco/blob/9d41b0a151b83693929d3a9c84f7c5c85d070d3a/rules/falco_rules.yaml#L1961
2816 - NULL,
2817 - SIMPLE_PATTERN_EXACT, true);
2818 -
2819 - service_register(SERVICE_THREAD_TYPE_LIBUV, NULL, NULL, NULL, false);
2820 -
2821 - while (service_running(SERVICE_COLLECTORS)) {
2822 - worker_is_idle();
2823 -
2824 - uv_mutex_lock(&discovery_thread.mutex);
2825 - uv_cond_wait(&discovery_thread.cond_var, &discovery_thread.mutex);
2826 - uv_mutex_unlock(&discovery_thread.mutex);
2827 -
2828 - if (unlikely(!service_running(SERVICE_COLLECTORS)))
2829 - break;
2830 -
2831 - discovery_find_all_cgroups();
2832 - }
2833 - collector_info("discovery thread stopped");
2834 - worker_unregister();
2835 - service_exits();
2836 - __atomic_store_n(&discovery_thread.exited,1,__ATOMIC_RELAXED);
2837 -}
2838 -
2839 -// ----------------------------------------------------------------------------
2840 -// generate charts
2841 -
2842 -#define CHART_TITLE_MAX 300
2843 -
2844 -void update_systemd_services_charts(
2845 - int update_every,
2846 - int do_cpu,
2847 - int do_mem_usage,
2848 - int do_mem_detailed,
2849 - int do_mem_failcnt,
2850 - int do_swap_usage,
2851 - int do_io,
2852 - int do_io_ops,
2853 - int do_throttle_io,
2854 - int do_throttle_ops,
2855 - int do_queued_ops,
2856 - int do_merged_ops)
2857 -{
2858 - // update the values
2859 - struct cgroup *cg;
2860 - int systemd_cgroup_chart_priority = NETDATA_CHART_PRIO_CGROUPS_SYSTEMD;
2861 - char type[RRD_ID_LENGTH_MAX + 1];
2862 -
2863 - for (cg = cgroup_root; cg; cg = cg->next) {
2864 - if (unlikely(!cg->enabled || cg->pending_renames || !is_cgroup_systemd_service(cg)))
2865 - continue;
2866 -
2867 - type[0] = '\0';
2868 - if (likely(do_cpu && cg->cpuacct_stat.updated)) {
2869 - if (unlikely(!cg->st_cpu)) {
2870 - cg->st_cpu = rrdset_create_localhost(
2871 - cgroup_chart_type(type, cg),
2872 - "cpu_utilization",
2873 - NULL,
2874 - "cpu",
2875 - "systemd.service.cpu.utilization",
2876 - "Systemd Services CPU utilization (100%% = 1 core)",
2877 - "percentage",
2878 - PLUGIN_CGROUPS_NAME,
2879 - PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME,
2880 - systemd_cgroup_chart_priority,
2881 - update_every,
2882 - RRDSET_TYPE_STACKED);
2883 -
2884 - rrdset_update_rrdlabels(cg->st_cpu, cg->chart_labels);
2885 - if (!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
2886 - rrddim_add(cg->st_cpu, "user", NULL, 100, system_hz, RRD_ALGORITHM_INCREMENTAL);
2887 - rrddim_add(cg->st_cpu, "system", NULL, 100, system_hz, RRD_ALGORITHM_INCREMENTAL);
2888 - } else {
2889 - rrddim_add(cg->st_cpu, "user", NULL, 100, 1000000, RRD_ALGORITHM_INCREMENTAL);
2890 - rrddim_add(cg->st_cpu, "system", NULL, 100, 1000000, RRD_ALGORITHM_INCREMENTAL);
2891 - }
2892 - }
2893 -
2894 - // complete the iteration
2895 - rrddim_set(cg->st_cpu, "user", cg->cpuacct_stat.user);
2896 - rrddim_set(cg->st_cpu, "system", cg->cpuacct_stat.system);
2897 - rrdset_done(cg->st_cpu);
2898 - }
2899 -
2900 - if (unlikely(do_mem_usage && cg->memory.updated_usage_in_bytes)) {
2901 - if (unlikely(!cg->st_mem_usage)) {
2902 - cg->st_mem_usage = rrdset_create_localhost(
2903 - cgroup_chart_type(type, cg),
2904 - "mem_usage",
2905 - NULL,
2906 - "mem",
2907 - "systemd.service.memory.usage",
2908 - "Systemd Services Used Memory",
2909 - "MiB",
2910 - PLUGIN_CGROUPS_NAME,
2911 - PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME,
2912 - systemd_cgroup_chart_priority + 5,
2913 - update_every,
2914 - RRDSET_TYPE_STACKED);
2915 -
2916 - rrdset_update_rrdlabels(cg->st_mem_usage, cg->chart_labels);
2917 - rrddim_add(cg->st_mem_usage, "ram", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
2918 - if (likely(do_swap_usage))
2919 - rrddim_add(cg->st_mem_usage, "swap", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
2920 - }
2921 -
2922 - rrddim_set(cg->st_mem_usage, "ram", cg->memory.usage_in_bytes);
2923 - if (likely(do_swap_usage)) {
2924 - if (!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
2925 - rrddim_set(
2926 - cg->st_mem_usage,
2927 - "swap",
2928 - cg->memory.msw_usage_in_bytes > (cg->memory.usage_in_bytes + cg->memory.total_inactive_file) ?
2929 - cg->memory.msw_usage_in_bytes -
2930 - (cg->memory.usage_in_bytes + cg->memory.total_inactive_file) :
2931 - 0);
2932 - } else {
2933 - rrddim_set(cg->st_mem_usage, "swap", cg->memory.msw_usage_in_bytes);
2934 - }
2935 - }
2936 - rrdset_done(cg->st_mem_usage);
2937 - }
2938 -
2939 - if (likely(do_mem_failcnt && cg->memory.updated_failcnt)) {
2940 - if (unlikely(do_mem_failcnt && !cg->st_mem_failcnt)) {
2941 - cg->st_mem_failcnt = rrdset_create_localhost(
2942 - cgroup_chart_type(type, cg),
2943 - "mem_failcnt",
2944 - NULL,
2945 - "mem",
2946 - "systemd.service.memory.failcnt",
2947 - "Systemd Services Memory Limit Failures",
2948 - "failures/s",
2949 - PLUGIN_CGROUPS_NAME,
2950 - PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME,
2951 - systemd_cgroup_chart_priority + 10,
2952 - update_every,
2953 - RRDSET_TYPE_LINE);
2954 -
2955 - rrdset_update_rrdlabels(cg->st_mem_failcnt, cg->chart_labels);
2956 - rrddim_add(cg->st_mem_failcnt, "fail", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
2957 - }
2958 -
2959 - rrddim_set(cg->st_mem_failcnt, "fail", cg->memory.failcnt);
2960 - rrdset_done(cg->st_mem_failcnt);
2961 - }
2962 -
2963 - if (likely(do_mem_detailed && cg->memory.updated_detailed)) {
2964 - if (unlikely(!cg->st_mem)) {
2965 - cg->st_mem = rrdset_create_localhost(
2966 - cgroup_chart_type(type, cg),
2967 - "mem_ram_usage",
2968 - NULL,
2969 - "mem",
2970 - "systemd.service.memory.ram.usage",
2971 - "Systemd Services Memory",
2972 - "MiB",
2973 - PLUGIN_CGROUPS_NAME,
2974 - PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME,
2975 - systemd_cgroup_chart_priority + 15,
2976 - update_every,
2977 - RRDSET_TYPE_STACKED);
2978 -
2979 - rrdset_update_rrdlabels(cg->st_mem, cg->chart_labels);
2980 - rrddim_add(cg->st_mem, "rss", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
2981 - rrddim_add(cg->st_mem, "cache", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
2982 - rrddim_add(cg->st_mem, "mapped_file", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
2983 - rrddim_add(cg->st_mem, "rss_huge", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
2984 - }
2985 -
2986 - rrddim_set(cg->st_mem, "rss", cg->memory.total_rss);
2987 - rrddim_set(cg->st_mem, "cache", cg->memory.total_cache);
2988 - rrddim_set(cg->st_mem, "mapped_file", cg->memory.total_mapped_file);
2989 - rrddim_set(cg->st_mem, "rss_huge", cg->memory.total_rss_huge);
2990 - rrdset_done(cg->st_mem);
2991 -
2992 - if (unlikely(!cg->st_writeback)) {
2993 - cg->st_writeback = rrdset_create_localhost(
2994 - cgroup_chart_type(type, cg),
2995 - "mem_writeback",
2996 - NULL,
2997 - "mem",
2998 - "systemd.service.memory.writeback",
2999 - "Systemd Services Writeback Memory",
3000 - "MiB",
3001 - PLUGIN_CGROUPS_NAME,
3002 - PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME,
3003 - systemd_cgroup_chart_priority + 20,
3004 - update_every,
3005 - RRDSET_TYPE_STACKED);
3006 -
3007 - rrdset_update_rrdlabels(cg->st_writeback, cg->chart_labels);
3008 - rrddim_add(cg->st_writeback, "writeback", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
3009 - rrddim_add(cg->st_writeback, "dirty", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
3010 - }
3011 -
3012 - rrddim_set(cg->st_writeback, "writeback", cg->memory.total_writeback);
3013 - rrddim_set(cg->st_writeback, "dirty", cg->memory.total_dirty);
3014 - rrdset_done(cg->st_writeback);
3015 -
3016 - if (unlikely(!cg->st_pgfaults)) {
3017 - cg->st_pgfaults = rrdset_create_localhost(
3018 - cgroup_chart_type(type, cg),
3019 - "mem_pgfault",
3020 - NULL,
3021 - "mem",
3022 - "systemd.service.memory.paging.faults",
3023 - "Systemd Services Memory Minor and Major Page Faults",
3024 - "MiB/s",
3025 - PLUGIN_CGROUPS_NAME,
3026 - PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME,
3027 - systemd_cgroup_chart_priority + 25,
3028 - update_every,
3029 - RRDSET_TYPE_AREA);
3030 -
3031 - rrdset_update_rrdlabels(cg->st_pgfaults, cg->chart_labels);
3032 - rrddim_add(cg->st_pgfaults, "minor", NULL, system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
3033 - rrddim_add(cg->st_pgfaults, "major", NULL, system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
3034 - }
3035 -
3036 - rrddim_set(cg->st_pgfaults, "minor", cg->memory.total_pgfault);
3037 - rrddim_set(cg->st_pgfaults, "major", cg->memory.total_pgmajfault);
3038 - rrdset_done(cg->st_pgfaults);
3039 -
3040 - if (unlikely(!cg->st_mem_activity)) {
3041 - cg->st_mem_activity = rrdset_create_localhost(
3042 - cgroup_chart_type(type, cg),
3043 - "mem_paging_io",
3044 - NULL,
3045 - "mem",
3046 - "systemd.service.memory.paging.io",
3047 - "Systemd Services Memory Paging IO",
3048 - "MiB/s",
3049 - PLUGIN_CGROUPS_NAME,
3050 - PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME,
3051 - systemd_cgroup_chart_priority + 30,
3052 - update_every,
3053 - RRDSET_TYPE_AREA);
3054 -
3055 - rrdset_update_rrdlabels(cg->st_mem_activity, cg->chart_labels);
3056 - rrddim_add(cg->st_mem_activity, "in", NULL, system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
3057 - rrddim_add(cg->st_mem_activity, "out", NULL, -system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
3058 - }
3059 -
3060 - rrddim_set(cg->st_mem_activity, "in", cg->memory.total_pgpgin);
3061 - rrddim_set(cg->st_mem_activity, "out", cg->memory.total_pgpgout);
3062 - rrdset_done(cg->st_mem_activity);
3063 - }
3064 -
3065 - if (likely(do_io && cg->io_service_bytes.updated)) {
3066 - if (unlikely(!cg->st_io)) {
3067 - cg->st_io = rrdset_create_localhost(
3068 - cgroup_chart_type(type, cg),
3069 - "disk_io",
3070 - NULL,
3071 - "disk",
3072 - "systemd.service.disk.io",
3073 - "Systemd Services Disk Read/Write Bandwidth",
3074 - "KiB/s",
3075 - PLUGIN_CGROUPS_NAME,
3076 - PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME,
3077 - systemd_cgroup_chart_priority + 35,
3078 - update_every,
3079 - RRDSET_TYPE_AREA);
3080 -
3081 - rrdset_update_rrdlabels(cg->st_io, cg->chart_labels);
3082 - rrddim_add(cg->st_io, "read", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
3083 - rrddim_add(cg->st_io, "write", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
3084 - }
3085 - rrddim_set(cg->st_io, "read", cg->io_service_bytes.Read);
3086 - rrddim_set(cg->st_io, "write", cg->io_service_bytes.Write);
3087 - rrdset_done(cg->st_io);
3088 - }
3089 -
3090 - if (likely(do_io_ops && cg->io_serviced.updated)) {
3091 - if (unlikely(!cg->st_serviced_ops)) {
3092 - cg->st_serviced_ops = rrdset_create_localhost(
3093 - cgroup_chart_type(type, cg),
3094 - "disk_iops",
3095 - NULL,
3096 - "disk",
3097 - "systemd.service.disk.iops",
3098 - "Systemd Services Disk Read/Write Operations",
3099 - "operations/s",
3100 - PLUGIN_CGROUPS_NAME,
3101 - PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME,
3102 - systemd_cgroup_chart_priority + 40,
3103 - update_every,
3104 - RRDSET_TYPE_LINE);
3105 -
3106 - rrdset_update_rrdlabels(cg->st_serviced_ops, cg->chart_labels);
3107 - rrddim_add(cg->st_serviced_ops, "read", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
3108 - rrddim_add(cg->st_serviced_ops, "write", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
3109 - }
3110 - rrddim_set(cg->st_serviced_ops, "read", cg->io_serviced.Read);
3111 - rrddim_set(cg->st_serviced_ops, "write", cg->io_serviced.Write);
3112 - rrdset_done(cg->st_serviced_ops);
3113 - }
3114 -
3115 - if (likely(do_throttle_io && cg->throttle_io_service_bytes.updated)) {
3116 - if (unlikely(!cg->st_throttle_io)) {
3117 - cg->st_throttle_io = rrdset_create_localhost(
3118 - cgroup_chart_type(type, cg),
3119 - "disk_throttle_io",
3120 - NULL,
3121 - "disk",
3122 - "systemd.service.disk.throttle.io",
3123 - "Systemd Services Throttle Disk Read/Write Bandwidth",
3124 - "KiB/s",
3125 - PLUGIN_CGROUPS_NAME,
3126 - PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME,
3127 - systemd_cgroup_chart_priority + 45,
3128 - update_every,
3129 - RRDSET_TYPE_AREA);
3130 -
3131 - rrdset_update_rrdlabels(cg->st_throttle_io, cg->chart_labels);
3132 - rrddim_add(cg->st_throttle_io, "read", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
3133 - rrddim_add(cg->st_throttle_io, "write", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
3134 - }
3135 - rrddim_set(cg->st_throttle_io, "read", cg->throttle_io_service_bytes.Read);
3136 - rrddim_set(cg->st_throttle_io, "write", cg->throttle_io_service_bytes.Write);
3137 - rrdset_done(cg->st_throttle_io);
3138 - }
1309 +void update_cgroup_systemd_services_charts() {
1310 + for (struct cgroup *cg = cgroup_root; cg; cg = cg->next) {
1311 + if (unlikely(!cg->enabled || cg->pending_renames || !is_cgroup_systemd_service(cg)))
1312 + continue;
1313
3140 - if (likely(do_throttle_ops && cg->throttle_io_serviced.updated)) {
3141 - if (unlikely(!cg->st_throttle_serviced_ops)) {
3142 - cg->st_throttle_serviced_ops = rrdset_create_localhost(
3143 - cgroup_chart_type(type, cg),
3144 - "disk_throttle_iops",
3145 - NULL,
3146 - "disk",
3147 - "systemd.service.disk.throttle.iops",
3148 - "Systemd Services Throttle Disk Read/Write Operations",
3149 - "operations/s",
3150 - PLUGIN_CGROUPS_NAME,
3151 - PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME,
3152 - systemd_cgroup_chart_priority + 50,
3153 - update_every,
3154 - RRDSET_TYPE_LINE);
3155 -
3156 - rrdset_update_rrdlabels(cg->st_throttle_serviced_ops, cg->chart_labels);
3157 - rrddim_add(cg->st_throttle_serviced_ops, "read", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
3158 - rrddim_add(cg->st_throttle_serviced_ops, "write", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
3159 - }
3160 - rrddim_set(cg->st_throttle_serviced_ops, "read", cg->throttle_io_serviced.Read);
3161 - rrddim_set(cg->st_throttle_serviced_ops, "write", cg->throttle_io_serviced.Write);
3162 - rrdset_done(cg->st_throttle_serviced_ops);
1314 + if (likely(cg->cpuacct_stat.updated)) {
1315 + update_cpu_utilization_chart(cg);
1316 }
3164 -
3165 - if (likely(do_queued_ops && cg->io_queued.updated)) {
3166 - if (unlikely(!cg->st_queued_ops)) {
3167 - cg->st_queued_ops = rrdset_create_localhost(
3168 - cgroup_chart_type(type, cg),
3169 - "disk_queued_iops",
3170 - NULL,
3171 - "disk",
3172 - "systemd.service.disk.queued_iops",
3173 - "Systemd Services Queued Disk Read/Write Operations",
3174 - "operations/s",
3175 - PLUGIN_CGROUPS_NAME,
3176 - PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME,
3177 - systemd_cgroup_chart_priority + 55,
3178 - update_every,
3179 - RRDSET_TYPE_LINE);
3180 -
3181 - rrdset_update_rrdlabels(cg->st_queued_ops, cg->chart_labels);
3182 - rrddim_add(cg->st_queued_ops, "read", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
3183 - rrddim_add(cg->st_queued_ops, "write", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
3184 - }
3185 - rrddim_set(cg->st_queued_ops, "read", cg->io_queued.Read);
3186 - rrddim_set(cg->st_queued_ops, "write", cg->io_queued.Write);
3187 - rrdset_done(cg->st_queued_ops);
1317 + if (likely(cg->memory.updated_msw_usage_in_bytes)) {
1318 + update_mem_usage_chart(cg);
1319 }
3189 -
3190 - if (likely(do_merged_ops && cg->io_merged.updated)) {
3191 - if (unlikely(!cg->st_merged_ops)) {
3192 - cg->st_merged_ops = rrdset_create_localhost(
3193 - cgroup_chart_type(type, cg),
3194 - "disk_merged_iops",
3195 - NULL,
3196 - "disk",
3197 - "systemd.service.disk.merged_iops",
3198 - "Systemd Services Merged Disk Read/Write Operations",
3199 - "operations/s",
3200 - PLUGIN_CGROUPS_NAME,
3201 - PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME,
3202 - systemd_cgroup_chart_priority + 60,
3203 - update_every,
3204 - RRDSET_TYPE_LINE);
3205 -
3206 - rrdset_update_rrdlabels(cg->st_merged_ops, cg->chart_labels);
3207 - rrddim_add(cg->st_merged_ops, "read", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
3208 - rrddim_add(cg->st_merged_ops, "write", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
3209 - }
3210 - rrddim_set(cg->st_merged_ops, "read", cg->io_merged.Read);
3211 - rrddim_set(cg->st_merged_ops, "write", cg->io_merged.Write);
3212 - rrdset_done(cg->st_merged_ops);
1320 + if (likely(cg->memory.updated_failcnt)) {
1321 + update_mem_failcnt_chart(cg);
1322 }
3214 - }
3215 -}
3216 -
3217 -static inline void update_cpu_limits(char **filename, unsigned long long *value, struct cgroup *cg) {
3218 - if(*filename) {
3219 - int ret = -1;
3220 -
3221 - if(value == &cg->cpuset_cpus) {
3222 - unsigned long ncpus = read_cpuset_cpus(*filename, get_system_cpus());
3223 - if(ncpus) {
3224 - *value = ncpus;
3225 - ret = 0;
1323 + if (likely(cg->memory.updated_detailed)) {
1324 + update_mem_usage_detailed_chart(cg);
1325 + update_mem_writeback_chart(cg);
1326 + update_mem_pgfaults_chart(cg);
1327 + if (!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
1328 + update_mem_activity_chart(cg);
1329 }
1330 }
3228 - else if(value == &cg->cpu_cfs_period) {
3229 - ret = read_single_number_file(*filename, value);
3230 - }
3231 - else if(value == &cg->cpu_cfs_quota) {
3232 - ret = read_single_number_file(*filename, value);
3233 - }
3234 - else ret = -1;
3235 -
3236 - if(ret) {
3237 - collector_error("Cannot refresh cgroup %s cpu limit by reading '%s'. Will not update its limit anymore.", cg->id, *filename);
3238 - freez(*filename);
3239 - *filename = NULL;
1331 + if (likely(cg->io_service_bytes.updated)) {
1332 + update_io_serviced_bytes_chart(cg);
1333 }
3241 - }
3242 -}
3243 -
3244 -static inline void update_cpu_limits2(struct cgroup *cg) {
3245 - if(cg->filename_cpu_cfs_quota){
3246 - static procfile *ff = NULL;
3247 -
3248 - ff = procfile_reopen(ff, cg->filename_cpu_cfs_quota, NULL, CGROUP_PROCFILE_FLAG);
3249 - if(unlikely(!ff)) {
3250 - goto cpu_limits2_err;
1334 + if (likely(cg->io_serviced.updated)) {
1335 + update_io_serviced_ops_chart(cg);
1336 }
3252 -
3253 - ff = procfile_readall(ff);
3254 - if(unlikely(!ff)) {
3255 - goto cpu_limits2_err;
1337 + if (likely(cg->throttle_io_service_bytes.updated)) {
1338 + update_throttle_io_serviced_bytes_chart(cg);
1339 }
3257 -
3258 - unsigned long lines = procfile_lines(ff);
3259 -
3260 - if (unlikely(lines < 1)) {
3261 - collector_error("CGROUP: file '%s' should have 1 lines.", cg->filename_cpu_cfs_quota);
3262 - return;
1340 + if (likely(cg->throttle_io_serviced.updated)) {
1341 + update_throttle_io_serviced_ops_chart(cg);
1342 }
3264 -
3265 - cg->cpu_cfs_period = str2ull(procfile_lineword(ff, 0, 1), NULL);
3266 - cg->cpuset_cpus = get_system_cpus();
3267 -
3268 - char *s = "max\n\0";
3269 - if(strcmp(s, procfile_lineword(ff, 0, 0)) == 0){
3270 - cg->cpu_cfs_quota = cg->cpu_cfs_period * cg->cpuset_cpus;
3271 - } else {
3272 - cg->cpu_cfs_quota = str2ull(procfile_lineword(ff, 0, 0), NULL);
1343 + if (likely(cg->io_queued.updated)) {
1344 + update_io_queued_ops_chart(cg);
1345 }
3274 - netdata_log_debug(D_CGROUP, "CPU limits values: %llu %llu %llu", cg->cpu_cfs_period, cg->cpuset_cpus, cg->cpu_cfs_quota);
3275 - return;
3276 -
3277 -cpu_limits2_err:
3278 - collector_error("Cannot refresh cgroup %s cpu limit by reading '%s'. Will not update its limit anymore.", cg->id, cg->filename_cpu_cfs_quota);
3279 - freez(cg->filename_cpu_cfs_quota);
3280 - cg->filename_cpu_cfs_quota = NULL;
3281 -
3282 - }
3283 -}
3284 -
3285 -static inline int update_memory_limits(char **filename, const RRDSETVAR_ACQUIRED **chart_var, unsigned long long *value, const char *chart_var_name, struct cgroup *cg) {
3286 - if(*filename) {
3287 - if(unlikely(!*chart_var)) {
3288 - *chart_var = rrdsetvar_custom_chart_variable_add_and_acquire(cg->st_mem_usage, chart_var_name);
3289 - if(!*chart_var) {
3290 - collector_error("Cannot create cgroup %s chart variable '%s'. Will not update its limit anymore.", cg->id, chart_var_name);
3291 - freez(*filename);
3292 - *filename = NULL;
3293 - }
1346 + if (likely(cg->io_merged.updated)) {
1347 + update_io_merged_ops_chart(cg);
1348 }
1349
3296 - if(*filename && *chart_var) {
3297 - if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
3298 - if(read_single_number_file(*filename, value)) {
3299 - collector_error("Cannot refresh cgroup %s memory limit by reading '%s'. Will not update its limit anymore.", cg->id, *filename);
3300 - freez(*filename);
3301 - *filename = NULL;
3302 - }
3303 - else {
3304 - rrdsetvar_custom_chart_variable_set(cg->st_mem_usage, *chart_var, (NETDATA_DOUBLE)(*value / (1024 * 1024)));
3305 - return 1;
3306 - }
3307 - } else {
3308 - char buffer[30 + 1];
3309 - int ret = read_file(*filename, buffer, 30);
3310 - if(ret) {
3311 - collector_error("Cannot refresh cgroup %s memory limit by reading '%s'. Will not update its limit anymore.", cg->id, *filename);
3312 - freez(*filename);
3313 - *filename = NULL;
3314 - return 0;
3315 - }
3316 - char *s = "max\n\0";
3317 - if(strcmp(s, buffer) == 0){
3318 - *value = UINT64_MAX;
3319 - rrdsetvar_custom_chart_variable_set(cg->st_mem_usage, *chart_var, (NETDATA_DOUBLE)(*value / (1024 * 1024)));
3320 - return 1;
3321 - }
3322 - *value = str2ull(buffer, NULL);
3323 - rrdsetvar_custom_chart_variable_set(cg->st_mem_usage, *chart_var, (NETDATA_DOUBLE)(*value / (1024 * 1024)));
3324 - return 1;
3325 - }
3326 - }
1350 + cg->function_ready = true;
1351 }
3328 - return 0;
1352 }
1353
3331 -void update_cgroup_charts(int update_every) {
3332 - netdata_log_debug(D_CGROUP, "updating cgroups charts");
3333 -
3334 - char type[RRD_ID_LENGTH_MAX + 1];
3335 - char title[CHART_TITLE_MAX + 1];
3336 -
3337 - int services_do_cpu = 0,
3338 - services_do_mem_usage = 0,
3339 - services_do_mem_detailed = 0,
3340 - services_do_mem_failcnt = 0,
3341 - services_do_swap_usage = 0,
3342 - services_do_io = 0,
3343 - services_do_io_ops = 0,
3344 - services_do_throttle_io = 0,
3345 - services_do_throttle_ops = 0,
3346 - services_do_queued_ops = 0,
3347 - services_do_merged_ops = 0;
3348 -
3349 - struct cgroup *cg;
3350 - for(cg = cgroup_root; cg ; cg = cg->next) {
3351 - if(unlikely(!cg->enabled || cg->pending_renames))
3352 - continue;
3353 -
3354 - if(likely(cgroup_enable_systemd_services && is_cgroup_systemd_service(cg))) {
3355 - if(cg->cpuacct_stat.updated && cg->cpuacct_stat.enabled == CONFIG_BOOLEAN_YES) services_do_cpu++;
3356 -
3357 - if(cgroup_enable_systemd_services_detailed_memory && cg->memory.updated_detailed && cg->memory.enabled_detailed) services_do_mem_detailed++;
3358 - if(cg->memory.updated_usage_in_bytes && cg->memory.enabled_usage_in_bytes == CONFIG_BOOLEAN_YES) services_do_mem_usage++;
3359 - if(cg->memory.updated_failcnt && cg->memory.enabled_failcnt == CONFIG_BOOLEAN_YES) services_do_mem_failcnt++;
3360 - if(cg->memory.updated_msw_usage_in_bytes && cg->memory.enabled_msw_usage_in_bytes == CONFIG_BOOLEAN_YES) services_do_swap_usage++;
3361 -
3362 - if(cg->io_service_bytes.updated && cg->io_service_bytes.enabled == CONFIG_BOOLEAN_YES) services_do_io++;
3363 - if(cg->io_serviced.updated && cg->io_serviced.enabled == CONFIG_BOOLEAN_YES) services_do_io_ops++;
3364 - if(cg->throttle_io_service_bytes.updated && cg->throttle_io_service_bytes.enabled == CONFIG_BOOLEAN_YES) services_do_throttle_io++;
3365 - if(cg->throttle_io_serviced.updated && cg->throttle_io_serviced.enabled == CONFIG_BOOLEAN_YES) services_do_throttle_ops++;
3366 - if(cg->io_queued.updated && cg->io_queued.enabled == CONFIG_BOOLEAN_YES) services_do_queued_ops++;
3367 - if(cg->io_merged.updated && cg->io_merged.enabled == CONFIG_BOOLEAN_YES) services_do_merged_ops++;
1354 +void update_cgroup_charts() {
1355 + for (struct cgroup *cg = cgroup_root; cg; cg = cg->next) {
1356 + if(unlikely(!cg->enabled || cg->pending_renames || is_cgroup_systemd_service(cg)))
1357 continue;
3369 - }
1358
3371 - type[0] = '\0';
3372 -
3373 - if(likely(cg->cpuacct_stat.updated && cg->cpuacct_stat.enabled == CONFIG_BOOLEAN_YES)) {
3374 - if(unlikely(!cg->st_cpu)) {
3375 - snprintfz(
3376 - title,
3377 - CHART_TITLE_MAX,
3378 - k8s_is_kubepod(cg) ? "CPU Usage (100%% = 1000 mCPU)" : "CPU Usage (100%% = 1 core)");
3379 -
3380 - cg->st_cpu = rrdset_create_localhost(
3381 - cgroup_chart_type(type, cg)
3382 - , "cpu"
3383 - , NULL
3384 - , "cpu"
3385 - , k8s_is_kubepod(cg) ? "k8s.cgroup.cpu" : "cgroup.cpu"
3386 - , title
3387 - , "percentage"
3388 - , PLUGIN_CGROUPS_NAME
3389 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
3390 - , cgroup_containers_chart_priority
3391 - , update_every
3392 - , RRDSET_TYPE_STACKED
3393 - );
3394 -
3395 - rrdset_update_rrdlabels(cg->st_cpu, cg->chart_labels);
3396 -
3397 - if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
3398 - rrddim_add(cg->st_cpu, "user", NULL, 100, system_hz, RRD_ALGORITHM_INCREMENTAL);
3399 - rrddim_add(cg->st_cpu, "system", NULL, 100, system_hz, RRD_ALGORITHM_INCREMENTAL);
3400 - }
3401 - else {
3402 - rrddim_add(cg->st_cpu, "user", NULL, 100, 1000000, RRD_ALGORITHM_INCREMENTAL);
3403 - rrddim_add(cg->st_cpu, "system", NULL, 100, 1000000, RRD_ALGORITHM_INCREMENTAL);
3404 - }
3405 - }
3406 -
3407 - rrddim_set(cg->st_cpu, "user", cg->cpuacct_stat.user);
3408 - rrddim_set(cg->st_cpu, "system", cg->cpuacct_stat.system);
3409 - rrdset_done(cg->st_cpu);
1359 + if (likely(cg->cpuacct_stat.updated && cg->cpuacct_stat.enabled == CONFIG_BOOLEAN_YES)) {
1360 + update_cpu_utilization_chart(cg);
1361
1362 if(likely(cg->filename_cpuset_cpus || cg->filename_cpu_cfs_period || cg->filename_cpu_cfs_quota)) {
1363 if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
@@ -3428,8 +1379,7 @@ void update_cgroup_charts(int update_every) {
1379 if(cg->filename_cpu_cfs_quota) freez(cg->filename_cpu_cfs_quota);
1380 cg->filename_cpu_cfs_quota = NULL;
1381 }
3431 - }
3432 - else {
1382 + } else {
1383 NETDATA_DOUBLE value = 0, quota = 0;
1384
1385 if(likely( ((!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) && (cg->filename_cpuset_cpus || (cg->filename_cpu_cfs_period && cg->filename_cpu_cfs_quota)))
@@ -3443,48 +1393,9 @@ void update_cgroup_charts(int update_every) {
1393 value = (NETDATA_DOUBLE)cg->cpuset_cpus * 100;
1394 }
1395 if(likely(value)) {
3446 - if(unlikely(!cg->st_cpu_limit)) {
3447 - snprintfz(title, CHART_TITLE_MAX, "CPU Usage within the limits");
3448 -
3449 - cg->st_cpu_limit = rrdset_create_localhost(
3450 - cgroup_chart_type(type, cg)
3451 - , "cpu_limit"
3452 - , NULL
3453 - , "cpu"
3454 - , k8s_is_kubepod(cg) ? "k8s.cgroup.cpu_limit" : "cgroup.cpu_limit"
3455 - , title
3456 - , "percentage"
3457 - , PLUGIN_CGROUPS_NAME
3458 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
3459 - , cgroup_containers_chart_priority - 1
3460 - , update_every
3461 - , RRDSET_TYPE_LINE
3462 - );
3463 -
3464 - rrdset_update_rrdlabels(cg->st_cpu_limit, cg->chart_labels);
3465 -
3466 - if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED))
3467 - rrddim_add(cg->st_cpu_limit, "used", NULL, 1, system_hz, RRD_ALGORITHM_ABSOLUTE);
3468 - else
3469 - rrddim_add(cg->st_cpu_limit, "used", NULL, 1, 1000000, RRD_ALGORITHM_ABSOLUTE);
3470 - cg->prev_cpu_usage = (NETDATA_DOUBLE)(cg->cpuacct_stat.user + cg->cpuacct_stat.system) * 100;
3471 - }
3472 -
3473 - NETDATA_DOUBLE cpu_usage = 0;
3474 - cpu_usage = (NETDATA_DOUBLE)(cg->cpuacct_stat.user + cg->cpuacct_stat.system) * 100;
3475 - NETDATA_DOUBLE cpu_used = 100 * (cpu_usage - cg->prev_cpu_usage) / (value * update_every);
3476 -
3477 - rrdset_isnot_obsolete___safe_from_collector_thread(cg->st_cpu_limit);
3478 -
3479 - rrddim_set(cg->st_cpu_limit, "used", (cpu_used > 0)?cpu_used:0);
3480 -
3481 - cg->prev_cpu_usage = cpu_usage;
3482 -
3483 - rrdsetvar_custom_chart_variable_set(cg->st_cpu, cg->chart_var_cpu_limit, value);
3484 - rrdset_done(cg->st_cpu_limit);
3485 - }
3486 - else {
3487 - if(unlikely(cg->st_cpu_limit)) {
1396 + update_cpu_utilization_limit_chart(cg, value);
1397 + } else {
1398 + if (unlikely(cg->st_cpu_limit)) {
1399 rrdset_is_obsolete___safe_from_collector_thread(cg->st_cpu_limit);
1400 cg->st_cpu_limit = NULL;
1401 }
@@ -3495,1056 +1406,133 @@ void update_cgroup_charts(int update_every) {
1406 }
1407
1408 if (likely(cg->cpuacct_cpu_throttling.updated && cg->cpuacct_cpu_throttling.enabled == CONFIG_BOOLEAN_YES)) {
3498 - if (unlikely(!cg->st_cpu_nr_throttled)) {
3499 - snprintfz(title, CHART_TITLE_MAX, "CPU Throttled Runnable Periods");
3500 -
3501 - cg->st_cpu_nr_throttled = rrdset_create_localhost(
3502 - cgroup_chart_type(type, cg)
3503 - , "throttled"
3504 - , NULL
3505 - , "cpu"
3506 - , k8s_is_kubepod(cg) ? "k8s.cgroup.throttled" : "cgroup.throttled"
3507 - , title
3508 - , "percentage"
3509 - , PLUGIN_CGROUPS_NAME
3510 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
3511 - , cgroup_containers_chart_priority + 10
3512 - , update_every
3513 - , RRDSET_TYPE_LINE
3514 - );
3515 -
3516 - rrdset_update_rrdlabels(cg->st_cpu_nr_throttled, cg->chart_labels);
3517 - rrddim_add(cg->st_cpu_nr_throttled, "throttled", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
3518 - } else {
3519 - rrddim_set(cg->st_cpu_nr_throttled, "throttled", cg->cpuacct_cpu_throttling.nr_throttled_perc);
3520 - rrdset_done(cg->st_cpu_nr_throttled);
3521 - }
3522 -
3523 - if (unlikely(!cg->st_cpu_throttled_time)) {
3524 - snprintfz(title, CHART_TITLE_MAX, "CPU Throttled Time Duration");
3525 -
3526 - cg->st_cpu_throttled_time = rrdset_create_localhost(
3527 - cgroup_chart_type(type, cg)
3528 - , "throttled_duration"
3529 - , NULL
3530 - , "cpu"
3531 - , k8s_is_kubepod(cg) ? "k8s.cgroup.throttled_duration" : "cgroup.throttled_duration"
3532 - , title
3533 - , "ms"
3534 - , PLUGIN_CGROUPS_NAME
3535 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
3536 - , cgroup_containers_chart_priority + 15
3537 - , update_every
3538 - , RRDSET_TYPE_LINE
3539 - );
3540 -
3541 - rrdset_update_rrdlabels(cg->st_cpu_throttled_time, cg->chart_labels);
3542 - rrddim_add(cg->st_cpu_throttled_time, "duration", NULL, 1, 1000000, RRD_ALGORITHM_INCREMENTAL);
3543 - } else {
3544 - rrddim_set(cg->st_cpu_throttled_time, "duration", cg->cpuacct_cpu_throttling.throttled_time);
3545 - rrdset_done(cg->st_cpu_throttled_time);
3546 - }
1409 + update_cpu_throttled_chart(cg);
1410 + update_cpu_throttled_duration_chart(cg);
1411 }
1412
1413 if (likely(cg->cpuacct_cpu_shares.updated && cg->cpuacct_cpu_shares.enabled == CONFIG_BOOLEAN_YES)) {
3550 - if (unlikely(!cg->st_cpu_shares)) {
3551 - snprintfz(title, CHART_TITLE_MAX, "CPU Time Relative Share");
3552 -
3553 - cg->st_cpu_shares = rrdset_create_localhost(
3554 - cgroup_chart_type(type, cg)
3555 - , "cpu_shares"
3556 - , NULL
3557 - , "cpu"
3558 - , k8s_is_kubepod(cg) ? "k8s.cgroup.cpu_shares" : "cgroup.cpu_shares"
3559 - , title
3560 - , "shares"
3561 - , PLUGIN_CGROUPS_NAME
3562 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
3563 - , cgroup_containers_chart_priority + 20
3564 - , update_every
3565 - , RRDSET_TYPE_LINE
3566 - );
3567 -
3568 - rrdset_update_rrdlabels(cg->st_cpu_shares, cg->chart_labels);
3569 - rrddim_add(cg->st_cpu_shares, "shares", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
3570 - } else {
3571 - rrddim_set(cg->st_cpu_shares, "shares", cg->cpuacct_cpu_shares.shares);
3572 - rrdset_done(cg->st_cpu_shares);
3573 - }
1414 + update_cpu_shares_chart(cg);
1415 }
1416
3576 - if(likely(cg->cpuacct_usage.updated && cg->cpuacct_usage.enabled == CONFIG_BOOLEAN_YES)) {
3577 - char id[RRD_ID_LENGTH_MAX + 1];
3578 - unsigned int i;
3579 -
3580 - if(unlikely(!cg->st_cpu_per_core)) {
3581 - snprintfz(
3582 - title,
3583 - CHART_TITLE_MAX,
3584 - k8s_is_kubepod(cg) ? "CPU Usage (100%% = 1000 mCPU) Per Core" :
3585 - "CPU Usage (100%% = 1 core) Per Core");
3586 -
3587 - cg->st_cpu_per_core = rrdset_create_localhost(
3588 - cgroup_chart_type(type, cg)
3589 - , "cpu_per_core"
3590 - , NULL
3591 - , "cpu"
3592 - , k8s_is_kubepod(cg) ? "k8s.cgroup.cpu_per_core" : "cgroup.cpu_per_core"
3593 - , title
3594 - , "percentage"
3595 - , PLUGIN_CGROUPS_NAME
3596 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
3597 - , cgroup_containers_chart_priority + 100
3598 - , update_every
3599 - , RRDSET_TYPE_STACKED
3600 - );
3601 -
3602 - rrdset_update_rrdlabels(cg->st_cpu_per_core, cg->chart_labels);
3603 -
3604 - for(i = 0; i < cg->cpuacct_usage.cpus; i++) {
3605 - snprintfz(id, RRD_ID_LENGTH_MAX, "cpu%u", i);
3606 - rrddim_add(cg->st_cpu_per_core, id, NULL, 100, 1000000000, RRD_ALGORITHM_INCREMENTAL);
3607 - }
3608 - }
3609 -
3610 - for(i = 0; i < cg->cpuacct_usage.cpus ;i++) {
3611 - snprintfz(id, RRD_ID_LENGTH_MAX, "cpu%u", i);
3612 - rrddim_set(cg->st_cpu_per_core, id, cg->cpuacct_usage.cpu_percpu[i]);
3613 - }
3614 - rrdset_done(cg->st_cpu_per_core);
1417 + if (likely(cg->cpuacct_usage.updated && cg->cpuacct_usage.enabled == CONFIG_BOOLEAN_YES)) {
1418 + update_cpu_per_core_usage_chart(cg);
1419 }
1420
3617 - if(likely(cg->memory.updated_detailed && cg->memory.enabled_detailed == CONFIG_BOOLEAN_YES)) {
3618 - if(unlikely(!cg->st_mem)) {
3619 - snprintfz(title, CHART_TITLE_MAX, "Memory Usage");
3620 -
3621 - cg->st_mem = rrdset_create_localhost(
3622 - cgroup_chart_type(type, cg)
3623 - , "mem"
3624 - , NULL
3625 - , "mem"
3626 - , k8s_is_kubepod(cg) ? "k8s.cgroup.mem" : "cgroup.mem"
3627 - , title
3628 - , "MiB"
3629 - , PLUGIN_CGROUPS_NAME
3630 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
3631 - , cgroup_containers_chart_priority + 220
3632 - , update_every
3633 - , RRDSET_TYPE_STACKED
3634 - );
3635 -
3636 - rrdset_update_rrdlabels(cg->st_mem, cg->chart_labels);
3637 -
3638 - if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
3639 - rrddim_add(cg->st_mem, "cache", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
3640 - rrddim_add(cg->st_mem, "rss", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
3641 -
3642 - if(cg->memory.detailed_has_swap)
3643 - rrddim_add(cg->st_mem, "swap", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
3644 -
3645 - rrddim_add(cg->st_mem, "rss_huge", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
3646 - rrddim_add(cg->st_mem, "mapped_file", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
3647 - } else {
3648 - rrddim_add(cg->st_mem, "anon", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
3649 - rrddim_add(cg->st_mem, "kernel_stack", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
3650 - rrddim_add(cg->st_mem, "slab", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
3651 - rrddim_add(cg->st_mem, "sock", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
3652 - rrddim_add(cg->st_mem, "anon_thp", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
3653 - rrddim_add(cg->st_mem, "file", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
3654 - }
3655 - }
3656 -
3657 - if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
3658 - rrddim_set(cg->st_mem, "cache", cg->memory.total_cache);
3659 - rrddim_set(cg->st_mem, "rss", (cg->memory.total_rss > cg->memory.total_rss_huge)?(cg->memory.total_rss - cg->memory.total_rss_huge):0);
3660 -
3661 - if(cg->memory.detailed_has_swap)
3662 - rrddim_set(cg->st_mem, "swap", cg->memory.total_swap);
3663 -
3664 - rrddim_set(cg->st_mem, "rss_huge", cg->memory.total_rss_huge);
3665 - rrddim_set(cg->st_mem, "mapped_file", cg->memory.total_mapped_file);
3666 - } else {
3667 - rrddim_set(cg->st_mem, "anon", cg->memory.anon);
3668 - rrddim_set(cg->st_mem, "kernel_stack", cg->memory.kernel_stack);
3669 - rrddim_set(cg->st_mem, "slab", cg->memory.slab);
3670 - rrddim_set(cg->st_mem, "sock", cg->memory.sock);
3671 - rrddim_set(cg->st_mem, "anon_thp", cg->memory.anon_thp);
3672 - rrddim_set(cg->st_mem, "file", cg->memory.total_mapped_file);
3673 - }
3674 - rrdset_done(cg->st_mem);
3675 -
3676 - if(unlikely(!cg->st_writeback)) {
3677 - snprintfz(title, CHART_TITLE_MAX, "Writeback Memory");
3678 -
3679 - cg->st_writeback = rrdset_create_localhost(
3680 - cgroup_chart_type(type, cg)
3681 - , "writeback"
3682 - , NULL
3683 - , "mem"
3684 - , k8s_is_kubepod(cg) ? "k8s.cgroup.writeback" : "cgroup.writeback"
3685 - , title
3686 - , "MiB"
3687 - , PLUGIN_CGROUPS_NAME
3688 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
3689 - , cgroup_containers_chart_priority + 300
3690 - , update_every
3691 - , RRDSET_TYPE_AREA
3692 - );
3693 -
3694 - rrdset_update_rrdlabels(cg->st_writeback, cg->chart_labels);
3695 -
3696 - if(cg->memory.detailed_has_dirty)
3697 - rrddim_add(cg->st_writeback, "dirty", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
3698 -
3699 - rrddim_add(cg->st_writeback, "writeback", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
3700 - }
3701 -
3702 - if(cg->memory.detailed_has_dirty)
3703 - rrddim_set(cg->st_writeback, "dirty", cg->memory.total_dirty);
3704 -
3705 - rrddim_set(cg->st_writeback, "writeback", cg->memory.total_writeback);
3706 - rrdset_done(cg->st_writeback);
1421 + if (likely(cg->memory.updated_detailed && cg->memory.enabled_detailed == CONFIG_BOOLEAN_YES)) {
1422 + update_mem_usage_detailed_chart(cg);
1423 + update_mem_writeback_chart(cg);
1424
1425 if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
3709 - if(unlikely(!cg->st_mem_activity)) {
3710 - snprintfz(title, CHART_TITLE_MAX, "Memory Activity");
3711 -
3712 - cg->st_mem_activity = rrdset_create_localhost(
3713 - cgroup_chart_type(type, cg)
3714 - , "mem_activity"
3715 - , NULL
3716 - , "mem"
3717 - , k8s_is_kubepod(cg) ? "k8s.cgroup.mem_activity" : "cgroup.mem_activity"
3718 - , title
3719 - , "MiB/s"
3720 - , PLUGIN_CGROUPS_NAME
3721 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
3722 - , cgroup_containers_chart_priority + 400
3723 - , update_every
3724 - , RRDSET_TYPE_LINE
3725 - );
3726 -
3727 - rrdset_update_rrdlabels(cg->st_mem_activity, cg->chart_labels);
3728 -
3729 - rrddim_add(cg->st_mem_activity, "pgpgin", "in", system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
3730 - rrddim_add(cg->st_mem_activity, "pgpgout", "out", -system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
3731 - }
3732 -
3733 - rrddim_set(cg->st_mem_activity, "pgpgin", cg->memory.total_pgpgin);
3734 - rrddim_set(cg->st_mem_activity, "pgpgout", cg->memory.total_pgpgout);
3735 - rrdset_done(cg->st_mem_activity);
3736 - }
3737 -
3738 - if(unlikely(!cg->st_pgfaults)) {
3739 - snprintfz(title, CHART_TITLE_MAX, "Memory Page Faults");
3740 -
3741 - cg->st_pgfaults = rrdset_create_localhost(
3742 - cgroup_chart_type(type, cg)
3743 - , "pgfaults"
3744 - , NULL
3745 - , "mem"
3746 - , k8s_is_kubepod(cg) ? "k8s.cgroup.pgfaults" : "cgroup.pgfaults"
3747 - , title
3748 - , "MiB/s"
3749 - , PLUGIN_CGROUPS_NAME
3750 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
3751 - , cgroup_containers_chart_priority + 500
3752 - , update_every
3753 - , RRDSET_TYPE_LINE
3754 - );
3755 -
3756 - rrdset_update_rrdlabels(cg->st_pgfaults, cg->chart_labels);
3757 -
3758 - rrddim_add(cg->st_pgfaults, "pgfault", NULL, system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
3759 - rrddim_add(cg->st_pgfaults, "pgmajfault", "swap", -system_page_size, 1024 * 1024, RRD_ALGORITHM_INCREMENTAL);
1426 + update_mem_activity_chart(cg);
1427 }
1428
3762 - rrddim_set(cg->st_pgfaults, "pgfault", cg->memory.total_pgfault);
3763 - rrddim_set(cg->st_pgfaults, "pgmajfault", cg->memory.total_pgmajfault);
3764 - rrdset_done(cg->st_pgfaults);
1429 + update_mem_pgfaults_chart(cg);
1430 }
1431
3767 - if(likely(cg->memory.updated_usage_in_bytes && cg->memory.enabled_usage_in_bytes == CONFIG_BOOLEAN_YES)) {
3768 - if(unlikely(!cg->st_mem_usage)) {
3769 - snprintfz(title, CHART_TITLE_MAX, "Used Memory");
3770 -
3771 - cg->st_mem_usage = rrdset_create_localhost(
3772 - cgroup_chart_type(type, cg)
3773 - , "mem_usage"
3774 - , NULL
3775 - , "mem"
3776 - , k8s_is_kubepod(cg) ? "k8s.cgroup.mem_usage" : "cgroup.mem_usage"
3777 - , title
3778 - , "MiB"
3779 - , PLUGIN_CGROUPS_NAME
3780 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
3781 - , cgroup_containers_chart_priority + 210
3782 - , update_every
3783 - , RRDSET_TYPE_STACKED
3784 - );
3785 -
3786 - rrdset_update_rrdlabels(cg->st_mem_usage, cg->chart_labels);
3787 -
3788 - rrddim_add(cg->st_mem_usage, "ram", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
3789 - rrddim_add(cg->st_mem_usage, "swap", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
3790 - }
3791 -
3792 - rrddim_set(cg->st_mem_usage, "ram", cg->memory.usage_in_bytes);
3793 - if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
3794 - rrddim_set(
3795 - cg->st_mem_usage,
3796 - "swap",
3797 - cg->memory.msw_usage_in_bytes > (cg->memory.usage_in_bytes + cg->memory.total_inactive_file) ?
3798 - cg->memory.msw_usage_in_bytes - (cg->memory.usage_in_bytes + cg->memory.total_inactive_file) : 0);
3799 - } else {
3800 - rrddim_set(cg->st_mem_usage, "swap", cg->memory.msw_usage_in_bytes);
3801 - }
3802 - rrdset_done(cg->st_mem_usage);
3803 -
3804 - if (likely(update_memory_limits(&cg->filename_memory_limit, &cg->chart_var_memory_limit, &cg->memory_limit, "memory_limit", cg))) {
3805 - static unsigned long long ram_total = 0;
3806 -
3807 - if(unlikely(!ram_total)) {
3808 - procfile *ff = NULL;
3809 -
3810 - char filename[FILENAME_MAX + 1];
3811 - snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/meminfo");
3812 - ff = procfile_open(config_get("plugin:cgroups", "meminfo filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
3813 -
3814 - if(likely(ff))
3815 - ff = procfile_readall(ff);
3816 - if(likely(ff && procfile_lines(ff) && !strncmp(procfile_word(ff, 0), "MemTotal", 8)))
3817 - ram_total = str2ull(procfile_word(ff, 1), NULL) * 1024;
3818 - else {
3819 - collector_error("Cannot read file %s. Will not update cgroup %s RAM limit anymore.", filename, cg->id);
3820 - freez(cg->filename_memory_limit);
3821 - cg->filename_memory_limit = NULL;
3822 - }
3823 -
3824 - procfile_close(ff);
3825 - }
1432 + if (likely(cg->memory.updated_usage_in_bytes && cg->memory.enabled_usage_in_bytes == CONFIG_BOOLEAN_YES)) {
1433 + update_mem_usage_chart(cg);
1434
3827 - if(likely(ram_total)) {
3828 - unsigned long long memory_limit = ram_total;
1435 + // FIXME: this if should be only for unlimited charts
1436 + if(likely(host_ram_total)) {
1437 + // FIXME: do we need to update mem limits on every data collection?
1438 + if (likely(update_memory_limits(cg))) {
1439
3830 - if(unlikely(cg->memory_limit < ram_total))
1440 + unsigned long long memory_limit = host_ram_total;
1441 + if (unlikely(cg->memory_limit < host_ram_total))
1442 memory_limit = cg->memory_limit;
1443
3833 - if(unlikely(!cg->st_mem_usage_limit)) {
3834 - snprintfz(title, CHART_TITLE_MAX, "Used RAM within the limits");
3835 -
3836 - cg->st_mem_usage_limit = rrdset_create_localhost(
3837 - cgroup_chart_type(type, cg)
3838 - , "mem_usage_limit"
3839 - , NULL
3840 - , "mem"
3841 - , k8s_is_kubepod(cg) ? "k8s.cgroup.mem_usage_limit": "cgroup.mem_usage_limit"
3842 - , title
3843 - , "MiB"
3844 - , PLUGIN_CGROUPS_NAME
3845 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
3846 - , cgroup_containers_chart_priority + 200
3847 - , update_every
3848 - , RRDSET_TYPE_STACKED
3849 - );
3850 -
3851 - rrdset_update_rrdlabels(cg->st_mem_usage_limit, cg->chart_labels);
3852 -
3853 - rrddim_add(cg->st_mem_usage_limit, "available", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
3854 - rrddim_add(cg->st_mem_usage_limit, "used", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
3855 - }
3856 -
3857 - rrdset_isnot_obsolete___safe_from_collector_thread(cg->st_mem_usage_limit);
3858 -
3859 - rrddim_set(cg->st_mem_usage_limit, "available", memory_limit - cg->memory.usage_in_bytes);
3860 - rrddim_set(cg->st_mem_usage_limit, "used", cg->memory.usage_in_bytes);
3861 - rrdset_done(cg->st_mem_usage_limit);
3862 -
3863 - if (unlikely(!cg->st_mem_utilization)) {
3864 - snprintfz(title, CHART_TITLE_MAX, "Memory Utilization");
3865 -
3866 - cg->st_mem_utilization = rrdset_create_localhost(
3867 - cgroup_chart_type(type, cg)
3868 - , "mem_utilization"
3869 - , NULL
3870 - , "mem"
3871 - , k8s_is_kubepod(cg) ? "k8s.cgroup.mem_utilization" : "cgroup.mem_utilization"
3872 - , title
3873 - , "percentage"
3874 - , PLUGIN_CGROUPS_NAME
3875 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
3876 - , cgroup_containers_chart_priority + 199
3877 - , update_every
3878 - , RRDSET_TYPE_AREA
3879 - );
3880 -
3881 - rrdset_update_rrdlabels(cg->st_mem_utilization, cg->chart_labels);
3882 -
3883 - rrddim_add(cg->st_mem_utilization, "utilization", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
1444 + update_mem_usage_limit_chart(cg, memory_limit);
1445 + update_mem_utilization_chart(cg, memory_limit);
1446 + } else {
1447 + if (unlikely(cg->st_mem_usage_limit)) {
1448 + rrdset_is_obsolete___safe_from_collector_thread(cg->st_mem_usage_limit);
1449 + cg->st_mem_usage_limit = NULL;
1450 }
1451
3886 - if (memory_limit) {
3887 - rrdset_isnot_obsolete___safe_from_collector_thread(cg->st_mem_utilization);
3888 -
3889 - rrddim_set(
3890 - cg->st_mem_utilization, "utilization", cg->memory.usage_in_bytes * 100 / memory_limit);
3891 - rrdset_done(cg->st_mem_utilization);
1452 + if (unlikely(cg->st_mem_utilization)) {
1453 + rrdset_is_obsolete___safe_from_collector_thread(cg->st_mem_utilization);
1454 + cg->st_mem_utilization = NULL;
1455 }
1456 }
1457 }
3895 - else {
3896 - if(unlikely(cg->st_mem_usage_limit)) {
3897 - rrdset_is_obsolete___safe_from_collector_thread(cg->st_mem_usage_limit);
3898 - cg->st_mem_usage_limit = NULL;
3899 - }
3900 -
3901 - if(unlikely(cg->st_mem_utilization)) {
3902 - rrdset_is_obsolete___safe_from_collector_thread(cg->st_mem_utilization);
3903 - cg->st_mem_utilization = NULL;
3904 - }
3905 - }
3906 -
3907 - update_memory_limits(&cg->filename_memoryswap_limit, &cg->chart_var_memoryswap_limit, &cg->memoryswap_limit, "memory_and_swap_limit", cg);
1458 }
1459
3910 - if(likely(cg->memory.updated_failcnt && cg->memory.enabled_failcnt == CONFIG_BOOLEAN_YES)) {
3911 - if(unlikely(!cg->st_mem_failcnt)) {
3912 - snprintfz(title, CHART_TITLE_MAX, "Memory Limit Failures");
3913 -
3914 - cg->st_mem_failcnt = rrdset_create_localhost(
3915 - cgroup_chart_type(type, cg)
3916 - , "mem_failcnt"
3917 - , NULL
3918 - , "mem"
3919 - , k8s_is_kubepod(cg) ? "k8s.cgroup.mem_failcnt" : "cgroup.mem_failcnt"
3920 - , title
3921 - , "count"
3922 - , PLUGIN_CGROUPS_NAME
3923 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
3924 - , cgroup_containers_chart_priority + 250
3925 - , update_every
3926 - , RRDSET_TYPE_LINE
3927 - );
3928 -
3929 - rrdset_update_rrdlabels(cg->st_mem_failcnt, cg->chart_labels);
3930 -
3931 - rrddim_add(cg->st_mem_failcnt, "failures", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
3932 - }
3933 -
3934 - rrddim_set(cg->st_mem_failcnt, "failures", cg->memory.failcnt);
3935 - rrdset_done(cg->st_mem_failcnt);
1460 + if (likely(cg->memory.updated_failcnt && cg->memory.enabled_failcnt == CONFIG_BOOLEAN_YES)) {
1461 + update_mem_failcnt_chart(cg);
1462 }
1463
3938 - if(likely(cg->io_service_bytes.updated && cg->io_service_bytes.enabled == CONFIG_BOOLEAN_YES)) {
3939 - if(unlikely(!cg->st_io)) {
3940 - snprintfz(title, CHART_TITLE_MAX, "I/O Bandwidth (all disks)");
3941 -
3942 - cg->st_io = rrdset_create_localhost(
3943 - cgroup_chart_type(type, cg)
3944 - , "io"
3945 - , NULL
3946 - , "disk"
3947 - , k8s_is_kubepod(cg) ? "k8s.cgroup.io" : "cgroup.io"
3948 - , title
3949 - , "KiB/s"
3950 - , PLUGIN_CGROUPS_NAME
3951 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
3952 - , cgroup_containers_chart_priority + 1200
3953 - , update_every
3954 - , RRDSET_TYPE_AREA
3955 - );
3956 -
3957 - rrdset_update_rrdlabels(cg->st_io, cg->chart_labels);
3958 -
3959 - rrddim_add(cg->st_io, "read", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
3960 - rrddim_add(cg->st_io, "write", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
3961 - }
3962 -
3963 - rrddim_set(cg->st_io, "read", cg->io_service_bytes.Read);
3964 - rrddim_set(cg->st_io, "write", cg->io_service_bytes.Write);
3965 - rrdset_done(cg->st_io);
1464 + if (likely(cg->io_service_bytes.updated && cg->io_service_bytes.enabled == CONFIG_BOOLEAN_YES)) {
1465 + update_io_serviced_bytes_chart(cg);
1466 }
1467
3968 - if(likely(cg->io_serviced.updated && cg->io_serviced.enabled == CONFIG_BOOLEAN_YES)) {
3969 - if(unlikely(!cg->st_serviced_ops)) {
3970 - snprintfz(title, CHART_TITLE_MAX, "Serviced I/O Operations (all disks)");
3971 -
3972 - cg->st_serviced_ops = rrdset_create_localhost(
3973 - cgroup_chart_type(type, cg)
3974 - , "serviced_ops"
3975 - , NULL
3976 - , "disk"
3977 - , k8s_is_kubepod(cg) ? "k8s.cgroup.serviced_ops" : "cgroup.serviced_ops"
3978 - , title
3979 - , "operations/s"
3980 - , PLUGIN_CGROUPS_NAME
3981 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
3982 - , cgroup_containers_chart_priority + 1200
3983 - , update_every
3984 - , RRDSET_TYPE_LINE
3985 - );
3986 -
3987 - rrdset_update_rrdlabels(cg->st_serviced_ops, cg->chart_labels);
3988 -
3989 - rrddim_add(cg->st_serviced_ops, "read", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
3990 - rrddim_add(cg->st_serviced_ops, "write", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
3991 - }
3992 -
3993 - rrddim_set(cg->st_serviced_ops, "read", cg->io_serviced.Read);
3994 - rrddim_set(cg->st_serviced_ops, "write", cg->io_serviced.Write);
3995 - rrdset_done(cg->st_serviced_ops);
1468 + if (likely(cg->io_serviced.updated && cg->io_serviced.enabled == CONFIG_BOOLEAN_YES)) {
1469 + update_io_serviced_ops_chart(cg);
1470 }
1471
3998 - if(likely(cg->throttle_io_service_bytes.updated && cg->throttle_io_service_bytes.enabled == CONFIG_BOOLEAN_YES)) {
3999 - if(unlikely(!cg->st_throttle_io)) {
4000 - snprintfz(title, CHART_TITLE_MAX, "Throttle I/O Bandwidth (all disks)");
4001 -
4002 - cg->st_throttle_io = rrdset_create_localhost(
4003 - cgroup_chart_type(type, cg)
4004 - , "throttle_io"
4005 - , NULL
4006 - , "disk"
4007 - , k8s_is_kubepod(cg) ? "k8s.cgroup.throttle_io" : "cgroup.throttle_io"
4008 - , title
4009 - , "KiB/s"
4010 - , PLUGIN_CGROUPS_NAME
4011 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
4012 - , cgroup_containers_chart_priority + 1200
4013 - , update_every
4014 - , RRDSET_TYPE_AREA
4015 - );
4016 -
4017 - rrdset_update_rrdlabels(cg->st_throttle_io, cg->chart_labels);
4018 -
4019 - rrddim_add(cg->st_throttle_io, "read", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
4020 - rrddim_add(cg->st_throttle_io, "write", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
4021 - }
4022 -
4023 - rrddim_set(cg->st_throttle_io, "read", cg->throttle_io_service_bytes.Read);
4024 - rrddim_set(cg->st_throttle_io, "write", cg->throttle_io_service_bytes.Write);
4025 - rrdset_done(cg->st_throttle_io);
1472 + if (likely(cg->throttle_io_service_bytes.updated && cg->throttle_io_service_bytes.enabled == CONFIG_BOOLEAN_YES)) {
1473 + update_throttle_io_serviced_bytes_chart(cg);
1474 }
1475
4028 - if(likely(cg->throttle_io_serviced.updated && cg->throttle_io_serviced.enabled == CONFIG_BOOLEAN_YES)) {
4029 - if(unlikely(!cg->st_throttle_serviced_ops)) {
4030 - snprintfz(title, CHART_TITLE_MAX, "Throttle Serviced I/O Operations (all disks)");
4031 -
4032 - cg->st_throttle_serviced_ops = rrdset_create_localhost(
4033 - cgroup_chart_type(type, cg)
4034 - , "throttle_serviced_ops"
4035 - , NULL
4036 - , "disk"
4037 - , k8s_is_kubepod(cg) ? "k8s.cgroup.throttle_serviced_ops" : "cgroup.throttle_serviced_ops"
4038 - , title
4039 - , "operations/s"
4040 - , PLUGIN_CGROUPS_NAME
4041 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
4042 - , cgroup_containers_chart_priority + 1200
4043 - , update_every
4044 - , RRDSET_TYPE_LINE
4045 - );
4046 -
4047 - rrdset_update_rrdlabels(cg->st_throttle_serviced_ops, cg->chart_labels);
4048 -
4049 - rrddim_add(cg->st_throttle_serviced_ops, "read", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
4050 - rrddim_add(cg->st_throttle_serviced_ops, "write", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
4051 - }
4052 -
4053 - rrddim_set(cg->st_throttle_serviced_ops, "read", cg->throttle_io_serviced.Read);
4054 - rrddim_set(cg->st_throttle_serviced_ops, "write", cg->throttle_io_serviced.Write);
4055 - rrdset_done(cg->st_throttle_serviced_ops);
1476 + if (likely(cg->throttle_io_serviced.updated && cg->throttle_io_serviced.enabled == CONFIG_BOOLEAN_YES)) {
1477 + update_throttle_io_serviced_ops_chart(cg);
1478 }
1479
4058 - if(likely(cg->io_queued.updated && cg->io_queued.enabled == CONFIG_BOOLEAN_YES)) {
4059 - if(unlikely(!cg->st_queued_ops)) {
4060 - snprintfz(title, CHART_TITLE_MAX, "Queued I/O Operations (all disks)");
4061 -
4062 - cg->st_queued_ops = rrdset_create_localhost(
4063 - cgroup_chart_type(type, cg)
4064 - , "queued_ops"
4065 - , NULL
4066 - , "disk"
4067 - , k8s_is_kubepod(cg) ? "k8s.cgroup.queued_ops" : "cgroup.queued_ops"
4068 - , title
4069 - , "operations"
4070 - , PLUGIN_CGROUPS_NAME
4071 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
4072 - , cgroup_containers_chart_priority + 2000
4073 - , update_every
4074 - , RRDSET_TYPE_LINE
4075 - );
4076 -
4077 - rrdset_update_rrdlabels(cg->st_queued_ops, cg->chart_labels);
4078 -
4079 - rrddim_add(cg->st_queued_ops, "read", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
4080 - rrddim_add(cg->st_queued_ops, "write", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE);
4081 - }
4082 -
4083 - rrddim_set(cg->st_queued_ops, "read", cg->io_queued.Read);
4084 - rrddim_set(cg->st_queued_ops, "write", cg->io_queued.Write);
4085 - rrdset_done(cg->st_queued_ops);
1480 + if (likely(cg->io_queued.updated && cg->io_queued.enabled == CONFIG_BOOLEAN_YES)) {
1481 + update_io_queued_ops_chart(cg);
1482 }
1483
4088 - if(likely(cg->io_merged.updated && cg->io_merged.enabled == CONFIG_BOOLEAN_YES)) {
4089 - if(unlikely(!cg->st_merged_ops)) {
4090 - snprintfz(title, CHART_TITLE_MAX, "Merged I/O Operations (all disks)");
4091 -
4092 - cg->st_merged_ops = rrdset_create_localhost(
4093 - cgroup_chart_type(type, cg)
4094 - , "merged_ops"
4095 - , NULL
4096 - , "disk"
4097 - , k8s_is_kubepod(cg) ? "k8s.cgroup.merged_ops" : "cgroup.merged_ops"
4098 - , title
4099 - , "operations/s"
4100 - , PLUGIN_CGROUPS_NAME
4101 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
4102 - , cgroup_containers_chart_priority + 2100
4103 - , update_every
4104 - , RRDSET_TYPE_LINE
4105 - );
4106 -
4107 - rrdset_update_rrdlabels(cg->st_merged_ops, cg->chart_labels);
4108 -
4109 - rrddim_add(cg->st_merged_ops, "read", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
4110 - rrddim_add(cg->st_merged_ops, "write", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
4111 - }
4112 -
4113 - rrddim_set(cg->st_merged_ops, "read", cg->io_merged.Read);
4114 - rrddim_set(cg->st_merged_ops, "write", cg->io_merged.Write);
4115 - rrdset_done(cg->st_merged_ops);
1484 + if (likely(cg->io_merged.updated && cg->io_merged.enabled == CONFIG_BOOLEAN_YES)) {
1485 + update_io_merged_ops_chart(cg);
1486 }
1487
1488 if (cg->options & CGROUP_OPTIONS_IS_UNIFIED) {
4119 - struct pressure *res = &cg->cpu_pressure;
4120 -
4121 - if (likely(res->updated && res->some.enabled)) {
4122 - struct pressure_charts *pcs;
4123 - pcs = &res->some;
4124 -
4125 - if (unlikely(!pcs->share_time.st)) {
4126 - RRDSET *chart;
4127 - snprintfz(title, CHART_TITLE_MAX, "CPU some pressure");
4128 - chart = pcs->share_time.st = rrdset_create_localhost(
4129 - cgroup_chart_type(type, cg)
4130 - , "cpu_some_pressure"
4131 - , NULL
4132 - , "cpu"
4133 - , k8s_is_kubepod(cg) ? "k8s.cgroup.cpu_some_pressure" : "cgroup.cpu_some_pressure"
4134 - , title
4135 - , "percentage"
4136 - , PLUGIN_CGROUPS_NAME
4137 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
4138 - , cgroup_containers_chart_priority + 2200
4139 - , update_every
4140 - , RRDSET_TYPE_LINE
4141 - );
4142 - rrdset_update_rrdlabels(chart = pcs->share_time.st, cg->chart_labels);
4143 - pcs->share_time.rd10 = rrddim_add(chart, "some 10", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
4144 - pcs->share_time.rd60 = rrddim_add(chart, "some 60", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
4145 - pcs->share_time.rd300 = rrddim_add(chart, "some 300", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
4146 - }
4147 -
4148 - if (unlikely(!pcs->total_time.st)) {
4149 - RRDSET *chart;
4150 - snprintfz(title, CHART_TITLE_MAX, "CPU some pressure stall time");
4151 - chart = pcs->total_time.st = rrdset_create_localhost(
4152 - cgroup_chart_type(type, cg)
4153 - , "cpu_some_pressure_stall_time"
4154 - , NULL
4155 - , "cpu"
4156 - , k8s_is_kubepod(cg) ? "k8s.cgroup.cpu_some_pressure_stall_time" : "cgroup.cpu_some_pressure_stall_time"
4157 - , title
4158 - , "ms"
4159 - , PLUGIN_CGROUPS_NAME
4160 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
4161 - , cgroup_containers_chart_priority + 2220
4162 - , update_every
4163 - , RRDSET_TYPE_LINE
4164 - );
4165 - rrdset_update_rrdlabels(chart = pcs->total_time.st, cg->chart_labels);
4166 - pcs->total_time.rdtotal = rrddim_add(chart, "time", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
4167 - }
4168 -
4169 - update_pressure_charts(pcs);
4170 - }
4171 - if (likely(res->updated && res->full.enabled)) {
4172 - struct pressure_charts *pcs;
4173 - pcs = &res->full;
4174 -
4175 - if (unlikely(!pcs->share_time.st)) {
4176 - RRDSET *chart;
4177 - snprintfz(title, CHART_TITLE_MAX, "CPU full pressure");
4178 - chart = pcs->share_time.st = rrdset_create_localhost(
4179 - cgroup_chart_type(type, cg)
4180 - , "cpu_full_pressure"
4181 - , NULL
4182 - , "cpu"
4183 - , k8s_is_kubepod(cg) ? "k8s.cgroup.cpu_full_pressure" : "cgroup.cpu_full_pressure"
4184 - , title
4185 - , "percentage"
4186 - , PLUGIN_CGROUPS_NAME
4187 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
4188 - , cgroup_containers_chart_priority + 2240
4189 - , update_every
4190 - , RRDSET_TYPE_LINE
4191 - );
4192 - rrdset_update_rrdlabels(chart = pcs->share_time.st, cg->chart_labels);
4193 - pcs->share_time.rd10 = rrddim_add(chart, "full 10", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
4194 - pcs->share_time.rd60 = rrddim_add(chart, "full 60", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
4195 - pcs->share_time.rd300 = rrddim_add(chart, "full 300", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
4196 - }
4197 -
4198 - if (unlikely(!pcs->total_time.st)) {
4199 - RRDSET *chart;
4200 - snprintfz(title, CHART_TITLE_MAX, "CPU full pressure stall time");
4201 - chart = pcs->total_time.st = rrdset_create_localhost(
4202 - cgroup_chart_type(type, cg)
4203 - , "cpu_full_pressure_stall_time"
4204 - , NULL
4205 - , "cpu"
4206 - , k8s_is_kubepod(cg) ? "k8s.cgroup.cpu_full_pressure_stall_time" : "cgroup.cpu_full_pressure_stall_time"
4207 - , title
4208 - , "ms"
4209 - , PLUGIN_CGROUPS_NAME
4210 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
4211 - , cgroup_containers_chart_priority + 2260
4212 - , update_every
4213 - , RRDSET_TYPE_LINE
4214 - );
4215 - rrdset_update_rrdlabels(chart = pcs->total_time.st, cg->chart_labels);
4216 - pcs->total_time.rdtotal = rrddim_add(chart, "time", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
4217 - }
4218 -
4219 - update_pressure_charts(pcs);
4220 - }
4221 -
4222 - res = &cg->memory_pressure;
4223 -
4224 - if (likely(res->updated && res->some.enabled)) {
4225 - struct pressure_charts *pcs;
4226 - pcs = &res->some;
4227 -
4228 - if (unlikely(!pcs->share_time.st)) {
4229 - RRDSET *chart;
4230 - snprintfz(title, CHART_TITLE_MAX, "Memory some pressure");
4231 - chart = pcs->share_time.st = rrdset_create_localhost(
4232 - cgroup_chart_type(type, cg)
4233 - , "mem_some_pressure"
4234 - , NULL
4235 - , "mem"
4236 - , k8s_is_kubepod(cg) ? "k8s.cgroup.memory_some_pressure" : "cgroup.memory_some_pressure"
4237 - , title
4238 - , "percentage"
4239 - , PLUGIN_CGROUPS_NAME
4240 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
4241 - , cgroup_containers_chart_priority + 2300
4242 - , update_every
4243 - , RRDSET_TYPE_LINE
4244 - );
4245 - rrdset_update_rrdlabels(chart = pcs->share_time.st, cg->chart_labels);
4246 - pcs->share_time.rd10 = rrddim_add(chart, "some 10", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
4247 - pcs->share_time.rd60 = rrddim_add(chart, "some 60", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
4248 - pcs->share_time.rd300 = rrddim_add(chart, "some 300", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
4249 - }
4250 -
4251 - if (unlikely(!pcs->total_time.st)) {
4252 - RRDSET *chart;
4253 - snprintfz(title, CHART_TITLE_MAX, "Memory some pressure stall time");
4254 - chart = pcs->total_time.st = rrdset_create_localhost(
4255 - cgroup_chart_type(type, cg)
4256 - , "memory_some_pressure_stall_time"
4257 - , NULL
4258 - , "mem"
4259 - , k8s_is_kubepod(cg) ? "k8s.cgroup.memory_some_pressure_stall_time" : "cgroup.memory_some_pressure_stall_time"
4260 - , title
4261 - , "ms"
4262 - , PLUGIN_CGROUPS_NAME
4263 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
4264 - , cgroup_containers_chart_priority + 2320
4265 - , update_every
4266 - , RRDSET_TYPE_LINE
4267 - );
4268 - rrdset_update_rrdlabels(chart = pcs->total_time.st, cg->chart_labels);
4269 - pcs->total_time.rdtotal = rrddim_add(chart, "time", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
4270 - }
4271 -
4272 - update_pressure_charts(pcs);
4273 - }
4274 -
4275 - if (likely(res->updated && res->full.enabled)) {
4276 - struct pressure_charts *pcs;
4277 - pcs = &res->full;
4278 -
4279 - if (unlikely(!pcs->share_time.st)) {
4280 - RRDSET *chart;
4281 - snprintfz(title, CHART_TITLE_MAX, "Memory full pressure");
4282 -
4283 - chart = pcs->share_time.st = rrdset_create_localhost(
4284 - cgroup_chart_type(type, cg)
4285 - , "mem_full_pressure"
4286 - , NULL
4287 - , "mem"
4288 - , k8s_is_kubepod(cg) ? "k8s.cgroup.memory_full_pressure" : "cgroup.memory_full_pressure"
4289 - , title
4290 - , "percentage"
4291 - , PLUGIN_CGROUPS_NAME
4292 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
4293 - , cgroup_containers_chart_priority + 2340
4294 - , update_every
4295 - , RRDSET_TYPE_LINE
4296 - );
4297 -
4298 - rrdset_update_rrdlabels(chart = pcs->share_time.st, cg->chart_labels);
4299 - pcs->share_time.rd10 = rrddim_add(chart, "full 10", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
4300 - pcs->share_time.rd60 = rrddim_add(chart, "full 60", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
4301 - pcs->share_time.rd300 = rrddim_add(chart, "full 300", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
4302 - }
4303 -
4304 - if (unlikely(!pcs->total_time.st)) {
4305 - RRDSET *chart;
4306 - snprintfz(title, CHART_TITLE_MAX, "Memory full pressure stall time");
4307 - chart = pcs->total_time.st = rrdset_create_localhost(
4308 - cgroup_chart_type(type, cg)
4309 - , "memory_full_pressure_stall_time"
4310 - , NULL
4311 - , "mem"
4312 - , k8s_is_kubepod(cg) ? "k8s.cgroup.memory_full_pressure_stall_time" : "cgroup.memory_full_pressure_stall_time"
4313 - , title
4314 - , "ms"
4315 - , PLUGIN_CGROUPS_NAME
4316 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
4317 - , cgroup_containers_chart_priority + 2360
4318 - , update_every
4319 - , RRDSET_TYPE_LINE
4320 - );
4321 - rrdset_update_rrdlabels(chart = pcs->total_time.st, cg->chart_labels);
4322 - pcs->total_time.rdtotal = rrddim_add(chart, "time", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
4323 - }
4324 -
4325 - update_pressure_charts(pcs);
4326 - }
4327 -
4328 - res = &cg->irq_pressure;
4329 -
4330 - if (likely(res->updated && res->some.enabled)) {
4331 - struct pressure_charts *pcs;
4332 - pcs = &res->some;
4333 -
4334 - if (unlikely(!pcs->share_time.st)) {
4335 - RRDSET *chart;
4336 - snprintfz(title, CHART_TITLE_MAX, "IRQ some pressure");
4337 - chart = pcs->share_time.st = rrdset_create_localhost(
4338 - cgroup_chart_type(type, cg)
4339 - , "irq_some_pressure"
4340 - , NULL
4341 - , "interrupts"
4342 - , k8s_is_kubepod(cg) ? "k8s.cgroup.irq_some_pressure" : "cgroup.irq_some_pressure"
4343 - , title
4344 - , "percentage"
4345 - , PLUGIN_CGROUPS_NAME
4346 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
4347 - , cgroup_containers_chart_priority + 2310
4348 - , update_every
4349 - , RRDSET_TYPE_LINE
4350 - );
4351 - rrdset_update_rrdlabels(chart = pcs->share_time.st, cg->chart_labels);
4352 - pcs->share_time.rd10 = rrddim_add(chart, "some 10", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
4353 - pcs->share_time.rd60 = rrddim_add(chart, "some 60", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
4354 - pcs->share_time.rd300 = rrddim_add(chart, "some 300", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
4355 - }
4356 -
4357 - if (unlikely(!pcs->total_time.st)) {
4358 - RRDSET *chart;
4359 - snprintfz(title, CHART_TITLE_MAX, "IRQ some pressure stall time");
4360 - chart = pcs->total_time.st = rrdset_create_localhost(
4361 - cgroup_chart_type(type, cg)
4362 - , "irq_some_pressure_stall_time"
4363 - , NULL
4364 - , "interrupts"
4365 - , k8s_is_kubepod(cg) ? "k8s.cgroup.irq_some_pressure_stall_time" : "cgroup.irq_some_pressure_stall_time"
4366 - , title
4367 - , "ms"
4368 - , PLUGIN_CGROUPS_NAME
4369 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
4370 - , cgroup_containers_chart_priority + 2330
4371 - , update_every
4372 - , RRDSET_TYPE_LINE
4373 - );
4374 - rrdset_update_rrdlabels(chart = pcs->total_time.st, cg->chart_labels);
4375 - pcs->total_time.rdtotal = rrddim_add(chart, "time", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
4376 - }
4377 -
4378 - update_pressure_charts(pcs);
1489 + if (likely(cg->cpu_pressure.updated)) {
1490 + if (cg->cpu_pressure.some.enabled) {
1491 + update_cpu_some_pressure_chart(cg);
1492 + update_cpu_some_pressure_stall_time_chart(cg);
1493 + }
1494 + if (cg->cpu_pressure.full.enabled) {
1495 + update_cpu_full_pressure_chart(cg);
1496 + update_cpu_full_pressure_stall_time_chart(cg);
1497 + }
1498 }
1499
4381 - if (likely(res->updated && res->full.enabled)) {
4382 - struct pressure_charts *pcs;
4383 - pcs = &res->full;
4384 -
4385 - if (unlikely(!pcs->share_time.st)) {
4386 - RRDSET *chart;
4387 - snprintfz(title, CHART_TITLE_MAX, "IRQ full pressure");
4388 -
4389 - chart = pcs->share_time.st = rrdset_create_localhost(
4390 - cgroup_chart_type(type, cg)
4391 - , "irq_full_pressure"
4392 - , NULL
4393 - , "interrupts"
4394 - , k8s_is_kubepod(cg) ? "k8s.cgroup.irq_full_pressure" : "cgroup.irq_full_pressure"
4395 - , title
4396 - , "percentage"
4397 - , PLUGIN_CGROUPS_NAME
4398 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
4399 - , cgroup_containers_chart_priority + 2350
4400 - , update_every
4401 - , RRDSET_TYPE_LINE
4402 - );
4403 -
4404 - rrdset_update_rrdlabels(chart = pcs->share_time.st, cg->chart_labels);
4405 - pcs->share_time.rd10 = rrddim_add(chart, "full 10", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
4406 - pcs->share_time.rd60 = rrddim_add(chart, "full 60", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
4407 - pcs->share_time.rd300 = rrddim_add(chart, "full 300", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1500 + if (likely(cg->memory_pressure.updated)) {
1501 + if (cg->memory_pressure.some.enabled) {
1502 + update_mem_some_pressure_chart(cg);
1503 + update_mem_some_pressure_stall_time_chart(cg);
1504 }
4409 -
4410 - if (unlikely(!pcs->total_time.st)) {
4411 - RRDSET *chart;
4412 - snprintfz(title, CHART_TITLE_MAX, "IRQ full pressure stall time");
4413 - chart = pcs->total_time.st = rrdset_create_localhost(
4414 - cgroup_chart_type(type, cg)
4415 - , "irq_full_pressure_stall_time"
4416 - , NULL
4417 - , "interrupts"
4418 - , k8s_is_kubepod(cg) ? "k8s.cgroup.irq_full_pressure_stall_time" : "cgroup.irq_full_pressure_stall_time"
4419 - , title
4420 - , "ms"
4421 - , PLUGIN_CGROUPS_NAME
4422 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
4423 - , cgroup_containers_chart_priority + 2370
4424 - , update_every
4425 - , RRDSET_TYPE_LINE
4426 - );
4427 - rrdset_update_rrdlabels(chart = pcs->total_time.st, cg->chart_labels);
4428 - pcs->total_time.rdtotal = rrddim_add(chart, "time", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1505 + if (cg->memory_pressure.full.enabled) {
1506 + update_mem_full_pressure_chart(cg);
1507 + update_mem_full_pressure_stall_time_chart(cg);
1508 }
4430 -
4431 - update_pressure_charts(pcs);
1509 }
1510
4434 - res = &cg->io_pressure;
4435 -
4436 - if (likely(res->updated && res->some.enabled)) {
4437 - struct pressure_charts *pcs;
4438 - pcs = &res->some;
4439 -
4440 - if (unlikely(!pcs->share_time.st)) {
4441 - RRDSET *chart;
4442 - snprintfz(title, CHART_TITLE_MAX, "I/O some pressure");
4443 - chart = pcs->share_time.st = rrdset_create_localhost(
4444 - cgroup_chart_type(type, cg)
4445 - , "io_some_pressure"
4446 - , NULL
4447 - , "disk"
4448 - , k8s_is_kubepod(cg) ? "k8s.cgroup.io_some_pressure" : "cgroup.io_some_pressure"
4449 - , title
4450 - , "percentage"
4451 - , PLUGIN_CGROUPS_NAME
4452 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
4453 - , cgroup_containers_chart_priority + 2400
4454 - , update_every
4455 - , RRDSET_TYPE_LINE
4456 - );
4457 - rrdset_update_rrdlabels(chart = pcs->share_time.st, cg->chart_labels);
4458 - pcs->share_time.rd10 = rrddim_add(chart, "some 10", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
4459 - pcs->share_time.rd60 = rrddim_add(chart, "some 60", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
4460 - pcs->share_time.rd300 = rrddim_add(chart, "some 300", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1511 + if (likely(cg->irq_pressure.updated)) {
1512 + if (cg->irq_pressure.some.enabled) {
1513 + update_irq_some_pressure_chart(cg);
1514 + update_irq_some_pressure_stall_time_chart(cg);
1515 }
4462 -
4463 - if (unlikely(!pcs->total_time.st)) {
4464 - RRDSET *chart;
4465 - snprintfz(title, CHART_TITLE_MAX, "I/O some pressure stall time");
4466 - chart = pcs->total_time.st = rrdset_create_localhost(
4467 - cgroup_chart_type(type, cg)
4468 - , "io_some_pressure_stall_time"
4469 - , NULL
4470 - , "disk"
4471 - , k8s_is_kubepod(cg) ? "k8s.cgroup.io_some_pressure_stall_time" : "cgroup.io_some_pressure_stall_time"
4472 - , title
4473 - , "ms"
4474 - , PLUGIN_CGROUPS_NAME
4475 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
4476 - , cgroup_containers_chart_priority + 2420
4477 - , update_every
4478 - , RRDSET_TYPE_LINE
4479 - );
4480 - rrdset_update_rrdlabels(chart = pcs->total_time.st, cg->chart_labels);
4481 - pcs->total_time.rdtotal = rrddim_add(chart, "time", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1516 + if (cg->irq_pressure.full.enabled) {
1517 + update_irq_full_pressure_chart(cg);
1518 + update_irq_full_pressure_stall_time_chart(cg);
1519 }
4483 -
4484 - update_pressure_charts(pcs);
1520 }
1521
4487 - if (likely(res->updated && res->full.enabled)) {
4488 - struct pressure_charts *pcs;
4489 - pcs = &res->full;
4490 -
4491 - if (unlikely(!pcs->share_time.st)) {
4492 - RRDSET *chart;
4493 - snprintfz(title, CHART_TITLE_MAX, "I/O full pressure");
4494 - chart = pcs->share_time.st = rrdset_create_localhost(
4495 - cgroup_chart_type(type, cg)
4496 - , "io_full_pressure"
4497 - , NULL
4498 - , "disk"
4499 - , k8s_is_kubepod(cg) ? "k8s.cgroup.io_full_pressure" : "cgroup.io_full_pressure"
4500 - , title
4501 - , "percentage"
4502 - , PLUGIN_CGROUPS_NAME
4503 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
4504 - , cgroup_containers_chart_priority + 2440
4505 - , update_every
4506 - , RRDSET_TYPE_LINE
4507 - );
4508 - rrdset_update_rrdlabels(chart = pcs->share_time.st, cg->chart_labels);
4509 - pcs->share_time.rd10 = rrddim_add(chart, "full 10", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
4510 - pcs->share_time.rd60 = rrddim_add(chart, "full 60", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
4511 - pcs->share_time.rd300 = rrddim_add(chart, "full 300", NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1522 + if (likely(cg->io_pressure.updated)) {
1523 + if (cg->io_pressure.some.enabled) {
1524 + update_io_some_pressure_chart(cg);
1525 + update_io_some_pressure_stall_time_chart(cg);
1526 }
4513 -
4514 - if (unlikely(!pcs->total_time.st)) {
4515 - RRDSET *chart;
4516 - snprintfz(title, CHART_TITLE_MAX, "I/O full pressure stall time");
4517 - chart = pcs->total_time.st = rrdset_create_localhost(
4518 - cgroup_chart_type(type, cg)
4519 - , "io_full_pressure_stall_time"
4520 - , NULL
4521 - , "disk"
4522 - , k8s_is_kubepod(cg) ? "k8s.cgroup.io_full_pressure_stall_time" : "cgroup.io_full_pressure_stall_time"
4523 - , title
4524 - , "ms"
4525 - , PLUGIN_CGROUPS_NAME
4526 - , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
4527 - , cgroup_containers_chart_priority + 2460
4528 - , update_every
4529 - , RRDSET_TYPE_LINE
4530 - );
4531 - rrdset_update_rrdlabels(chart = pcs->total_time.st, cg->chart_labels);
4532 - pcs->total_time.rdtotal = rrddim_add(chart, "time", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1527 + if (cg->io_pressure.full.enabled) {
1528 + update_io_full_pressure_chart(cg);
1529 + update_io_full_pressure_stall_time_chart(cg);
1530 }
4534 -
4535 - update_pressure_charts(pcs);
1531 }
1532 }
4538 - }
1533
4540 - if(likely(cgroup_enable_systemd_services))
4541 - update_systemd_services_charts(update_every, services_do_cpu, services_do_mem_usage, services_do_mem_detailed
4542 - , services_do_mem_failcnt, services_do_swap_usage, services_do_io
4543 - , services_do_io_ops, services_do_throttle_io, services_do_throttle_ops
4544 - , services_do_queued_ops, services_do_merged_ops
4545 - );
4546 -
4547 - netdata_log_debug(D_CGROUP, "done updating cgroups charts");
1534 + cg->function_ready = true;
1535 + }
1536 }
1537
1538 // ----------------------------------------------------------------------------
@@ -4587,6 +1575,22 @@ static void cgroup_main_cleanup(void *ptr) {
1575 static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
1576 }
1577
1578 +void cgroup_read_host_total_ram() {
1579 + procfile *ff = NULL;
1580 + char filename[FILENAME_MAX + 1];
1581 + snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/meminfo");
1582 +
1583 + ff = procfile_open(
1584 + config_get("plugin:cgroups", "meminfo filename to monitor", filename), " \t:", PROCFILE_FLAG_DEFAULT);
1585 +
1586 + if (likely((ff = procfile_readall(ff)) && procfile_lines(ff) && !strncmp(procfile_word(ff, 0), "MemTotal", 8)))
1587 + host_ram_total = str2ull(procfile_word(ff, 1), NULL) * 1024;
1588 + else
1589 + collector_error("Cannot read file %s. Will not create cgroup %s RAM limit charts.", filename);
1590 +
1591 + procfile_close(ff);
1592 +}
1593 +
1594 void *cgroups_main(void *ptr) {
1595 worker_register("CGROUPS");
1596 worker_register_job_name(WORKER_CGROUPS_LOCK, "lock");
@@ -4601,6 +1605,9 @@ void *cgroups_main(void *ptr) {
1605 }
1606
1607 read_cgroup_plugin_configuration();
1608 +
1609 + cgroup_read_host_total_ram();
1610 +
1611 netdata_cgroup_ebpf_initialize_shm();
1612
1613 if (uv_mutex_init(&cgroup_root_mutex)) {
@@ -4624,19 +1631,29 @@ void *cgroups_main(void *ptr) {
1631 collector_error("CGROUP: cannot create thread worker. uv_thread_create(): %s", uv_strerror(error));
1632 goto exit;
1633 }
1634 +
1635 uv_thread_set_name_np(discovery_thread.thread, "P[cgroups]");
1636
1637 + // we register this only on localhost
1638 + // for the other nodes, the origin server should register it
1639 + rrd_collector_started(); // this creates a collector that runs for as long as netdata runs
1640 + cgroup_netdev_link_init();
1641 + rrd_function_add(localhost, NULL, "TopCgroups", 10, RRDFUNCTIONS_CGTOP_HELP, true, cgroup_function_cgroup_top, NULL);
1642 + rrd_function_add(localhost, NULL, "TopSystemd", 10, RRDFUNCTIONS_CGTOP_HELP, true, cgroup_function_systemd_top, NULL);
1643 +
1644 heartbeat_t hb;
1645 heartbeat_init(&hb);
1646 usec_t step = cgroup_update_every * USEC_PER_SEC;
1647 usec_t find_every = cgroup_check_for_new_every * USEC_PER_SEC, find_dt = 0;
1648
1649 netdata_thread_disable_cancelability();
1650 +
1651 while(service_running(SERVICE_COLLECTORS)) {
1652 worker_is_idle();
1653
1654 usec_t hb_dt = heartbeat_next(&hb, step);
4639 - if(unlikely(!service_running(SERVICE_COLLECTORS))) break;
1655 + if (unlikely(!service_running(SERVICE_COLLECTORS)))
1656 + break;
1657
1658 find_dt += hb_dt;
1659 if (unlikely(find_dt >= find_every || (!is_inside_k8s && cgroups_check))) {
@@ -4652,12 +1669,18 @@ void *cgroups_main(void *ptr) {
1669
1670 worker_is_busy(WORKER_CGROUPS_READ);
1671 read_all_discovered_cgroups(cgroup_root);
1672 +
1673 if (unlikely(!service_running(SERVICE_COLLECTORS))) {
1674 uv_mutex_unlock(&cgroup_root_mutex);
1675 break;
1676 }
1677 +
1678 worker_is_busy(WORKER_CGROUPS_CHART);
4660 - update_cgroup_charts(cgroup_update_every);
1679 +
1680 + update_cgroup_charts();
1681 + if (cgroup_enable_systemd_services)
1682 + update_cgroup_systemd_services_charts();
1683 +
1684 if (unlikely(!service_running(SERVICE_COLLECTORS))) {
1685 uv_mutex_unlock(&cgroup_root_mutex);
1686 break;
collectors/cgroups.plugin/sys_fs_cgroup.h
+4
@@ -5,6 +5,10 @@
5
6 #include "daemon/common.h"
7
8 +#define PLUGIN_CGROUPS_NAME "cgroups.plugin"
9 +#define PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME "systemd"
10 +#define PLUGIN_CGROUPS_MODULE_CGROUPS_NAME "/sys/fs/cgroup"
11 +
12 #define CGROUP_OPTIONS_DISABLED_DUPLICATE 0x00000001
13 #define CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE 0x00000002
14 #define CGROUP_OPTIONS_IS_UNIFIED 0x00000004
collectors/proc.plugin/plugin_proc.h
+2 -1
@@ -59,7 +59,8 @@ void netdev_rename_device_add(
59 const char *container_device,
60 const char *container_name,
61 RRDLABELS *labels,
62 - const char *ctx_prefix);
62 + const char *ctx_prefix,
63 + const DICTIONARY_ITEM *cgroup_netdev_link);
64
65 void netdev_rename_device_del(const char *host_device);
66
collectors/proc.plugin/proc_net_dev.c
+25 -1
@@ -9,6 +9,11 @@
9
10 #define READ_RETRY_PERIOD 60 // seconds
11
12 +void cgroup_netdev_reset_all(void);
13 +void cgroup_netdev_release(const DICTIONARY_ITEM *link);
14 +const void *cgroup_netdev_dup(const DICTIONARY_ITEM *link);
15 +void cgroup_netdev_add_bandwidth(const DICTIONARY_ITEM *link, NETDATA_DOUBLE received, NETDATA_DOUBLE sent);
16 +
17 enum {
18 NETDEV_DUPLEX_UNKNOWN,
19 NETDEV_DUPLEX_HALF,
@@ -208,6 +213,8 @@ static struct netdev {
213 char *filename_carrier;
214 char *filename_mtu;
215
216 + const DICTIONARY_ITEM *cgroup_netdev_link;
217 +
218 struct netdev *next;
219 } *netdev_root = NULL, *netdev_last_used = NULL;
220
@@ -326,6 +333,7 @@ static void netdev_free(struct netdev *d) {
333 netdev_charts_release(d);
334 netdev_free_chart_strings(d);
335 rrdlabels_destroy(d->chart_labels);
336 + cgroup_netdev_release(d->cgroup_netdev_link);
337
338 freez((void *)d->name);
339 freez((void *)d->filename_speed);
@@ -352,6 +360,8 @@ static struct netdev_rename {
360
361 int processed;
362
363 + const DICTIONARY_ITEM *cgroup_netdev_link;
364 +
365 struct netdev_rename *next;
366 } *netdev_rename_root = NULL;
367
@@ -374,7 +384,8 @@ void netdev_rename_device_add(
384 const char *container_device,
385 const char *container_name,
386 RRDLABELS *labels,
377 - const char *ctx_prefix)
387 + const char *ctx_prefix,
388 + const DICTIONARY_ITEM *cgroup_netdev_link)
389 {
390 netdata_mutex_lock(&netdev_rename_mutex);
391
@@ -391,6 +402,8 @@ void netdev_rename_device_add(
402 r->hash = hash;
403 r->next = netdev_rename_root;
404 r->processed = 0;
405 + r->cgroup_netdev_link = cgroup_netdev_link;
406 +
407 netdev_rename_root = r;
408 netdev_pending_renames++;
409 collector_info("CGROUP: registered network interface rename for '%s' as '%s' under '%s'", r->host_device, r->container_device, r->container_name);
@@ -406,6 +419,8 @@ void netdev_rename_device_add(
419 rrdlabels_migrate_to_these(r->chart_labels, labels);
420
421 r->processed = 0;
422 + r->cgroup_netdev_link = cgroup_netdev_link;
423 +
424 netdev_pending_renames++;
425 collector_info("CGROUP: altered network interface rename for '%s' as '%s' under '%s'", r->host_device, r->container_device, r->container_name);
426 }
@@ -438,6 +453,7 @@ void netdev_rename_device_del(const char *host_device) {
453 freez((void *) r->container_device);
454 freez((void *) r->ctx_prefix);
455 rrdlabels_destroy(r->chart_labels);
456 + cgroup_netdev_release(r->cgroup_netdev_link);
457 freez((void *) r);
458 break;
459 }
@@ -451,6 +467,7 @@ static inline void netdev_rename_cgroup(struct netdev *d, struct netdev_rename *
467
468 netdev_charts_release(d);
469 netdev_free_chart_strings(d);
470 + d->cgroup_netdev_link = cgroup_netdev_dup(r->cgroup_netdev_link);
471
472 char buffer[RRD_ID_LENGTH_MAX + 1];
473
@@ -1009,6 +1026,11 @@ int do_proc_net_dev(int update_every, usec_t dt) {
1026 rrddim_set_by_pointer(d->st_bandwidth, d->rd_tbytes, (collected_number)d->tbytes);
1027 rrdset_done(d->st_bandwidth);
1028
1029 + if(d->cgroup_netdev_link)
1030 + cgroup_netdev_add_bandwidth(d->cgroup_netdev_link,
1031 + d->flipped ? d->rd_tbytes->collector.last_stored_value : -d->rd_rbytes->collector.last_stored_value,
1032 + d->flipped ? -d->rd_rbytes->collector.last_stored_value : d->rd_tbytes->collector.last_stored_value);
1033 +
1034 // update the interface speed
1035 if(d->filename_speed) {
1036 if(unlikely(!d->chart_var_speed)) {
@@ -1530,6 +1552,8 @@ void *netdev_main(void *ptr)
1552 if (unlikely(!service_running(SERVICE_COLLECTORS)))
1553 break;
1554
1555 + cgroup_netdev_reset_all();
1556 +
1557 worker_is_busy(0);
1558 if(do_proc_net_dev(localhost->rrd_update_every, hb_dt))
1559 break;