3 // ----------------------------------------------------------------------------
6 static int cgroup_enable_cpuacct_stat = CONFIG_ONDEMAND_ONDEMAND;
7 static int cgroup_enable_cpuacct_usage = CONFIG_ONDEMAND_ONDEMAND;
8 static int cgroup_enable_memory = CONFIG_ONDEMAND_ONDEMAND;
9 static int cgroup_enable_devices = CONFIG_ONDEMAND_ONDEMAND;
10 static int cgroup_enable_blkio = CONFIG_ONDEMAND_ONDEMAND;
11 static int cgroup_enable_systemd_services = CONFIG_ONDEMAND_YES;
12 static int cgroup_enable_new_cgroups_detected_at_runtime = 1;
13 static int cgroup_check_for_new_every = 10;
14 static int cgroup_update_every = 1;
15 static int cgroup_recheck_zero_blkio_every_iterations = 10;
16 static int cgroup_recheck_zero_mem_failcnt_every_iterations = 10;
18 static char *cgroup_cpuacct_base = NULL;
19 static char *cgroup_blkio_base = NULL;
20 static char *cgroup_memory_base = NULL;
21 static char *cgroup_devices_base = NULL;
23 static int cgroup_root_count = 0;
24 static int cgroup_root_max = 500;
25 static int cgroup_max_depth = 0;
27 static SIMPLE_PATTERN *disabled_cgroups_patterns = NULL;
28 static SIMPLE_PATTERN *disabled_cgroup_paths = NULL;
29 static SIMPLE_PATTERN *disabled_cgroup_renames = NULL;
30 static SIMPLE_PATTERN *systemd_services_cgroups = NULL;
32 static char *cgroups_rename_script = PLUGINS_DIR "/cgroup-name.sh";
34 static uint32_t Read_hash = 0;
35 static uint32_t Write_hash = 0;
36 static uint32_t Sync_hash = 0;
37 static uint32_t Async_hash = 0;
38 static uint32_t Total_hash = 0;
39 static uint32_t user_hash = 0;
40 static uint32_t system_hash = 0;
41 static uint32_t cache_hash = 0;
42 static uint32_t rss_hash = 0;
43 static uint32_t rss_huge_hash = 0;
44 static uint32_t mapped_file_hash = 0;
45 static uint32_t writeback_hash = 0;
46 static uint32_t dirty_hash = 0;
47 static uint32_t swap_hash = 0;
48 static uint32_t pgpgin_hash = 0;
49 static uint32_t pgpgout_hash = 0;
50 static uint32_t pgfault_hash = 0;
51 static uint32_t pgmajfault_hash = 0;
52 static uint32_t inactive_anon_hash = 0;
53 static uint32_t active_anon_hash = 0;
54 static uint32_t inactive_file_hash = 0;
55 static uint32_t active_file_hash = 0;
56 static uint32_t unevictable_hash = 0;
57 static uint32_t hierarchical_memory_limit_hash = 0;
58 static uint32_t total_cache_hash = 0;
59 static uint32_t total_rss_hash = 0;
60 static uint32_t total_rss_huge_hash = 0;
61 static uint32_t total_mapped_file_hash = 0;
62 static uint32_t total_writeback_hash = 0;
63 static uint32_t total_dirty_hash = 0;
64 static uint32_t total_swap_hash = 0;
65 static uint32_t total_pgpgin_hash = 0;
66 static uint32_t total_pgpgout_hash = 0;
67 static uint32_t total_pgfault_hash = 0;
68 static uint32_t total_pgmajfault_hash = 0;
69 static uint32_t total_inactive_anon_hash = 0;
70 static uint32_t total_active_anon_hash = 0;
71 static uint32_t total_inactive_file_hash = 0;
72 static uint32_t total_active_file_hash = 0;
73 static uint32_t total_unevictable_hash = 0;
75 void read_cgroup_plugin_configuration() {
76 Read_hash = simple_hash("Read");
77 Write_hash = simple_hash("Write");
78 Sync_hash = simple_hash("Sync");
79 Async_hash = simple_hash("Async");
80 Total_hash = simple_hash("Total");
81 user_hash = simple_hash("user");
82 system_hash = simple_hash("system");
83 cache_hash = simple_hash("cache");
84 rss_hash = simple_hash("rss");
85 rss_huge_hash = simple_hash("rss_huge");
86 mapped_file_hash = simple_hash("mapped_file");
87 writeback_hash = simple_hash("writeback");
88 dirty_hash = simple_hash("dirty");
89 swap_hash = simple_hash("swap");
90 pgpgin_hash = simple_hash("pgpgin");
91 pgpgout_hash = simple_hash("pgpgout");
92 pgfault_hash = simple_hash("pgfault");
93 pgmajfault_hash = simple_hash("pgmajfault");
94 inactive_anon_hash = simple_hash("inactive_anon");
95 active_anon_hash = simple_hash("active_anon");
96 inactive_file_hash = simple_hash("inactive_file");
97 active_file_hash = simple_hash("active_file");
98 unevictable_hash = simple_hash("unevictable");
99 hierarchical_memory_limit_hash = simple_hash("hierarchical_memory_limit");
100 total_cache_hash = simple_hash("total_cache");
101 total_rss_hash = simple_hash("total_rss");
102 total_rss_huge_hash = simple_hash("total_rss_huge");
103 total_mapped_file_hash = simple_hash("total_mapped_file");
104 total_writeback_hash = simple_hash("total_writeback");
105 total_dirty_hash = simple_hash("total_dirty");
106 total_swap_hash = simple_hash("total_swap");
107 total_pgpgin_hash = simple_hash("total_pgpgin");
108 total_pgpgout_hash = simple_hash("total_pgpgout");
109 total_pgfault_hash = simple_hash("total_pgfault");
110 total_pgmajfault_hash = simple_hash("total_pgmajfault");
111 total_inactive_anon_hash = simple_hash("total_inactive_anon");
112 total_active_anon_hash = simple_hash("total_active_anon");
113 total_inactive_file_hash = simple_hash("total_inactive_file");
114 total_active_file_hash = simple_hash("total_active_file");
115 total_unevictable_hash = simple_hash("total_unevictable");
117 cgroup_update_every = (int)config_get_number("plugin:cgroups", "update every", rrd_update_every);
118 if(cgroup_update_every < rrd_update_every)
119 cgroup_update_every = rrd_update_every;
121 cgroup_check_for_new_every = (int)config_get_number("plugin:cgroups", "check for new cgroups every", cgroup_check_for_new_every * cgroup_update_every);
122 if(cgroup_check_for_new_every < cgroup_update_every)
123 cgroup_check_for_new_every = cgroup_update_every;
125 cgroup_enable_cpuacct_stat = config_get_boolean_ondemand("plugin:cgroups", "enable cpuacct stat", cgroup_enable_cpuacct_stat);
126 cgroup_enable_cpuacct_usage = config_get_boolean_ondemand("plugin:cgroups", "enable cpuacct usage", cgroup_enable_cpuacct_usage);
127 cgroup_enable_memory = config_get_boolean_ondemand("plugin:cgroups", "enable memory", cgroup_enable_memory);
128 cgroup_enable_blkio = config_get_boolean_ondemand("plugin:cgroups", "enable blkio", cgroup_enable_blkio);
130 cgroup_enable_systemd_services = config_get_boolean_ondemand("plugin:cgroups", "enable systemd services", cgroup_enable_systemd_services);
132 cgroup_recheck_zero_blkio_every_iterations = (int)config_get_number("plugin:cgroups", "recheck zero blkio every iterations", cgroup_recheck_zero_blkio_every_iterations);
133 cgroup_recheck_zero_mem_failcnt_every_iterations = (int)config_get_number("plugin:cgroups", "recheck zero memory failcnt every iterations", cgroup_recheck_zero_mem_failcnt_every_iterations);
135 char filename[FILENAME_MAX + 1], *s;
136 struct mountinfo *mi, *root = mountinfo_read(0);
138 mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "cpuacct");
139 if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "cpuacct");
141 error("Cannot find cgroup cpuacct mountinfo. Assuming default: /sys/fs/cgroup/cpuacct");
142 s = "/sys/fs/cgroup/cpuacct";
144 else s = mi->mount_point;
145 snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
146 cgroup_cpuacct_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/cpuacct", filename);
148 mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "blkio");
149 if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "blkio");
151 error("Cannot find cgroup blkio mountinfo. Assuming default: /sys/fs/cgroup/blkio");
152 s = "/sys/fs/cgroup/blkio";
154 else s = mi->mount_point;
155 snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
156 cgroup_blkio_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/blkio", filename);
158 mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "memory");
159 if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "memory");
161 error("Cannot find cgroup memory mountinfo. Assuming default: /sys/fs/cgroup/memory");
162 s = "/sys/fs/cgroup/memory";
164 else s = mi->mount_point;
165 snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
166 cgroup_memory_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/memory", filename);
168 mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "devices");
169 if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "devices");
171 error("Cannot find cgroup devices mountinfo. Assuming default: /sys/fs/cgroup/devices");
172 s = "/sys/fs/cgroup/devices";
174 else s = mi->mount_point;
175 snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
176 cgroup_devices_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/devices", filename);
178 cgroup_root_max = (int)config_get_number("plugin:cgroups", "max cgroups to allow", cgroup_root_max);
179 cgroup_max_depth = (int)config_get_number("plugin:cgroups", "max cgroups depth to monitor", cgroup_max_depth);
181 cgroup_enable_new_cgroups_detected_at_runtime = config_get_boolean("plugin:cgroups", "enable new cgroups detected at run time", cgroup_enable_new_cgroups_detected_at_runtime);
183 disabled_cgroups_patterns = simple_pattern_create(
184 config_get("plugin:cgroups", "disable by default cgroups matching", " *.mount "
195 " /lxc/*/ns " // #1397
204 ), SIMPLE_PATTERN_EXACT);
206 disabled_cgroup_paths = simple_pattern_create(
207 config_get("plugin:cgroups", "do not search for cgroups in paths matching"
214 ), SIMPLE_PATTERN_EXACT);
216 cgroups_rename_script = config_get("plugin:cgroups", "script to get cgroup names", cgroups_rename_script);
218 disabled_cgroup_renames = simple_pattern_create(
219 config_get("plugin:cgroups", "do not run script to rename cgroups matching", " / "
227 ), SIMPLE_PATTERN_EXACT);
229 if(cgroup_enable_systemd_services)
230 systemd_services_cgroups = simple_pattern_create(
231 config_get("plugin:cgroups", "cgroups to match as systemd services"
232 , " !/system.slice/*/*.service /system.slice/*.service "
233 ), SIMPLE_PATTERN_EXACT);
235 mountinfo_free(root);
238 // ----------------------------------------------------------------------------
247 unsigned long long Read;
248 unsigned long long Write;
250 unsigned long long Sync;
251 unsigned long long Async;
252 unsigned long long Total;
256 // https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt
264 unsigned long long cache;
265 unsigned long long rss;
266 unsigned long long rss_huge;
267 unsigned long long mapped_file;
268 unsigned long long writeback;
269 unsigned long long dirty;
270 unsigned long long swap;
271 unsigned long long pgpgin;
272 unsigned long long pgpgout;
273 unsigned long long pgfault;
274 unsigned long long pgmajfault;
276 unsigned long long inactive_anon;
277 unsigned long long active_anon;
278 unsigned long long inactive_file;
279 unsigned long long active_file;
280 unsigned long long unevictable;
281 unsigned long long hierarchical_memory_limit;
282 unsigned long long total_cache;
283 unsigned long long total_rss;
284 unsigned long long total_rss_huge;
285 unsigned long long total_mapped_file;
286 unsigned long long total_writeback;
287 unsigned long long total_dirty;
288 unsigned long long total_swap;
289 unsigned long long total_pgpgin;
290 unsigned long long total_pgpgout;
291 unsigned long long total_pgfault;
292 unsigned long long total_pgmajfault;
293 unsigned long long total_inactive_anon;
294 unsigned long long total_active_anon;
295 unsigned long long total_inactive_file;
296 unsigned long long total_active_file;
297 unsigned long long total_unevictable;
300 int usage_in_bytes_updated;
301 char *filename_usage_in_bytes;
302 unsigned long long usage_in_bytes;
304 int msw_usage_in_bytes_updated;
305 char *filename_msw_usage_in_bytes;
306 unsigned long long msw_usage_in_bytes;
309 int failcnt_delay_counter;
310 char *filename_failcnt;
311 unsigned long long failcnt;
314 // https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt
315 struct cpuacct_stat {
320 unsigned long long user;
321 unsigned long long system;
324 // https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt
325 struct cpuacct_usage {
331 unsigned long long *cpu_percpu;
334 #define CGROUP_OPTIONS_DISABLED_DUPLICATE 0x00000001
335 #define CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE 0x00000002
340 char available; // found in the filesystem
341 char enabled; // enabled in the config
351 struct cpuacct_stat cpuacct_stat;
352 struct cpuacct_usage cpuacct_usage;
354 struct memory memory;
356 struct blkio io_service_bytes; // bytes
357 struct blkio io_serviced; // operations
359 struct blkio throttle_io_service_bytes; // bytes
360 struct blkio throttle_io_serviced; // operations
362 struct blkio io_merged; // operations
363 struct blkio io_queued; // operations
367 RRDSET *st_cpu_per_core;
369 RRDSET *st_writeback;
370 RRDSET *st_mem_activity;
372 RRDSET *st_mem_usage;
373 RRDSET *st_mem_failcnt;
375 RRDSET *st_serviced_ops;
376 RRDSET *st_throttle_io;
377 RRDSET *st_throttle_serviced_ops;
378 RRDSET *st_queued_ops;
379 RRDSET *st_merged_ops;
383 RRDDIM *rd_mem_usage;
385 RRDDIM *rd_io_service_bytes_read;
386 RRDDIM *rd_io_serviced_read;
387 RRDDIM *rd_throttle_io_read;
388 RRDDIM *rd_throttle_io_serviced_read;
389 RRDDIM *rd_io_queued_read;
390 RRDDIM *rd_io_merged_read;
392 RRDDIM *rd_io_service_bytes_write;
393 RRDDIM *rd_io_serviced_write;
394 RRDDIM *rd_throttle_io_write;
395 RRDDIM *rd_throttle_io_serviced_write;
396 RRDDIM *rd_io_queued_write;
397 RRDDIM *rd_io_merged_write;
401 } *cgroup_root = NULL;
403 // ----------------------------------------------------------------------------
404 // read values from /sys
406 static inline void cgroup_read_cpuacct_stat(struct cpuacct_stat *cp) {
407 static procfile *ff = NULL;
409 if(likely(cp->filename)) {
410 ff = procfile_reopen(ff, cp->filename, NULL, PROCFILE_FLAG_DEFAULT);
416 ff = procfile_readall(ff);
422 unsigned long i, lines = procfile_lines(ff);
424 if(unlikely(lines < 1)) {
425 error("File '%s' should have 1+ lines.", cp->filename);
430 for(i = 0; i < lines ; i++) {
431 char *s = procfile_lineword(ff, i, 0);
432 uint32_t hash = simple_hash(s);
434 if(unlikely(hash == user_hash && !strcmp(s, "user"))) {
435 cp->user = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
439 if(unlikely(hash == system_hash && !strcmp(s, "system"))) {
440 cp->system = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
449 static inline void cgroup_read_cpuacct_usage(struct cpuacct_usage *ca) {
450 static procfile *ff = NULL;
452 if(likely(ca->filename)) {
453 ff = procfile_reopen(ff, ca->filename, NULL, PROCFILE_FLAG_DEFAULT);
459 ff = procfile_readall(ff);
465 if(unlikely(procfile_lines(ff) < 1)) {
466 error("File '%s' should have 1+ lines but has %u.", ca->filename, procfile_lines(ff));
471 unsigned long i = procfile_linewords(ff, 0);
472 if(unlikely(i == 0)) {
477 // we may have 1 more CPU reported
479 char *s = procfile_lineword(ff, 0, i - 1);
484 if(unlikely(i != ca->cpus)) {
485 freez(ca->cpu_percpu);
486 ca->cpu_percpu = mallocz(sizeof(unsigned long long) * i);
487 ca->cpus = (unsigned int)i;
490 for(i = 0; i < ca->cpus ;i++)
491 ca->cpu_percpu[i] = strtoull(procfile_lineword(ff, 0, i), NULL, 10);
497 static inline void cgroup_read_blkio(struct blkio *io) {
498 static procfile *ff = NULL;
500 if(unlikely(io->delay_counter > 0)) {
505 if(likely(io->filename)) {
506 ff = procfile_reopen(ff, io->filename, NULL, PROCFILE_FLAG_DEFAULT);
512 ff = procfile_readall(ff);
518 unsigned long i, lines = procfile_lines(ff);
520 if(unlikely(lines < 1)) {
521 error("File '%s' should have 1+ lines.", io->filename);
534 for(i = 0; i < lines ; i++) {
535 char *s = procfile_lineword(ff, i, 1);
536 uint32_t hash = simple_hash(s);
538 if(unlikely(hash == Read_hash && !strcmp(s, "Read"))) {
539 io->Read += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
543 if(unlikely(hash == Write_hash && !strcmp(s, "Write"))) {
544 io->Write += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
549 if(hash == Sync_hash && !strcmp(s, "Sync")) {
550 io->Sync += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
554 if(hash == Async_hash && !strcmp(s, "Async")) {
555 io->Async += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
559 if(hash == Total_hash && !strcmp(s, "Total")) {
560 io->Total += strtoull(procfile_lineword(ff, i, 2), NULL, 10);
568 if(unlikely(!io->Read && !io->Write))
569 io->delay_counter = cgroup_recheck_zero_blkio_every_iterations;
573 static inline void cgroup_read_memory(struct memory *mem) {
574 static procfile *ff = NULL;
576 if(likely(mem->filename)) {
577 ff = procfile_reopen(ff, mem->filename, NULL, PROCFILE_FLAG_DEFAULT);
583 ff = procfile_readall(ff);
589 unsigned long i, lines = procfile_lines(ff);
591 if(unlikely(lines < 1)) {
592 error("File '%s' should have 1+ lines.", mem->filename);
597 for(i = 0; i < lines ; i++) {
598 char *s = procfile_lineword(ff, i, 0);
599 uint32_t hash = simple_hash(s);
601 if(unlikely(hash == cache_hash && !strcmp(s, "cache"))) {
602 mem->cache = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
606 if(unlikely(hash == rss_hash && !strcmp(s, "rss"))) {
607 mem->rss = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
611 if(unlikely(hash == rss_huge_hash && !strcmp(s, "rss_huge"))) {
612 mem->rss_huge = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
616 if(unlikely(hash == mapped_file_hash && !strcmp(s, "mapped_file"))) {
617 mem->mapped_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
621 if(unlikely(hash == writeback_hash && !strcmp(s, "writeback"))) {
622 mem->writeback = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
626 if(unlikely(hash == dirty_hash && !strcmp(s, "dirty"))) {
627 mem->dirty = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
628 mem->has_dirty_swap = 1;
632 if(unlikely(hash == swap_hash && !strcmp(s, "swap"))) {
633 mem->swap = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
634 mem->has_dirty_swap = 1;
638 if(unlikely(hash == pgpgin_hash && !strcmp(s, "pgpgin"))) {
639 mem->pgpgin = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
643 if(unlikely(hash == pgpgout_hash && !strcmp(s, "pgpgout"))) {
644 mem->pgpgout = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
648 if(unlikely(hash == pgfault_hash && !strcmp(s, "pgfault"))) {
649 mem->pgfault = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
653 if(unlikely(hash == pgmajfault_hash && !strcmp(s, "pgmajfault"))) {
654 mem->pgmajfault = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
659 if(unlikely(hash == inactive_anon_hash && !strcmp(s, "inactive_anon"))) {
660 mem->inactive_anon = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
664 if(unlikely(hash == active_anon_hash && !strcmp(s, "active_anon"))) {
665 mem->active_anon = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
669 if(unlikely(hash == inactive_file_hash && !strcmp(s, "inactive_file"))) {
670 mem->inactive_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
674 if(unlikely(hash == active_file_hash && !strcmp(s, "active_file"))) {
675 mem->active_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
679 if(unlikely(hash == unevictable_hash && !strcmp(s, "unevictable"))) {
680 mem->unevictable = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
684 if(unlikely(hash == hierarchical_memory_limit_hash && !strcmp(s, "hierarchical_memory_limit"))) {
685 mem->hierarchical_memory_limit = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
689 if(unlikely(hash == total_cache_hash && !strcmp(s, "total_cache"))) {
690 mem->total_cache = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
694 if(unlikely(hash == total_rss_hash && !strcmp(s, "total_rss"))) {
695 mem->total_rss = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
699 if(unlikely(hash == total_rss_huge_hash && !strcmp(s, "total_rss_huge"))) {
700 mem->total_rss_huge = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
704 if(unlikely(hash == total_mapped_file_hash && !strcmp(s, "total_mapped_file"))) {
705 mem->total_mapped_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
709 if(unlikely(hash == total_writeback_hash && !strcmp(s, "total_writeback"))) {
710 mem->total_writeback = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
714 if(unlikely(hash == total_dirty_hash && !strcmp(s, "total_dirty"))) {
715 mem->total_dirty = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
719 if(unlikely(hash == total_swap_hash && !strcmp(s, "total_swap"))) {
720 mem->total_swap = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
724 if(unlikely(hash == total_pgpgin_hash && !strcmp(s, "total_pgpgin"))) {
725 mem->total_pgpgin = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
729 if(unlikely(hash == total_pgpgout_hash && !strcmp(s, "total_pgpgout"))) {
730 mem->total_pgpgout = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
734 if(unlikely(hash == total_pgfault_hash && !strcmp(s, "total_pgfault"))) {
735 mem->total_pgfault = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
739 if(unlikely(hash == total_pgmajfault_hash && !strcmp(s, "total_pgmajfault"))) {
740 mem->total_pgmajfault = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
744 if(unlikely(hash == total_inactive_anon_hash && !strcmp(s, "total_inactive_anon"))) {
745 mem->total_inactive_anon = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
749 if(unlikely(hash == total_active_anon_hash && !strcmp(s, "total_active_anon"))) {
750 mem->total_active_anon = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
754 if(unlikely(hash == total_inactive_file_hash && !strcmp(s, "total_inactive_file"))) {
755 mem->total_inactive_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
759 if(unlikely(hash == total_active_file_hash && !strcmp(s, "total_active_file"))) {
760 mem->total_active_file = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
764 if(unlikely(hash == total_unevictable_hash && !strcmp(s, "total_unevictable"))) {
765 mem->total_unevictable = strtoull(procfile_lineword(ff, i, 1), NULL, 10);
771 // fprintf(stderr, "READ: '%s', cache: %llu, rss: %llu, rss_huge: %llu, mapped_file: %llu, writeback: %llu, dirty: %llu, swap: %llu, pgpgin: %llu, pgpgout: %llu, pgfault: %llu, pgmajfault: %llu, inactive_anon: %llu, active_anon: %llu, inactive_file: %llu, active_file: %llu, unevictable: %llu, hierarchical_memory_limit: %llu, total_cache: %llu, total_rss: %llu, total_rss_huge: %llu, total_mapped_file: %llu, total_writeback: %llu, total_dirty: %llu, total_swap: %llu, total_pgpgin: %llu, total_pgpgout: %llu, total_pgfault: %llu, total_pgmajfault: %llu, total_inactive_anon: %llu, total_active_anon: %llu, total_inactive_file: %llu, total_active_file: %llu, total_unevictable: %llu\n", mem->filename, mem->cache, mem->rss, mem->rss_huge, mem->mapped_file, mem->writeback, mem->dirty, mem->swap, mem->pgpgin, mem->pgpgout, mem->pgfault, mem->pgmajfault, mem->inactive_anon, mem->active_anon, mem->inactive_file, mem->active_file, mem->unevictable, mem->hierarchical_memory_limit, mem->total_cache, mem->total_rss, mem->total_rss_huge, mem->total_mapped_file, mem->total_writeback, mem->total_dirty, mem->total_swap, mem->total_pgpgin, mem->total_pgpgout, mem->total_pgfault, mem->total_pgmajfault, mem->total_inactive_anon, mem->total_active_anon, mem->total_inactive_file, mem->total_active_file, mem->total_unevictable);
777 if(likely(mem->filename_usage_in_bytes)) {
778 if(likely(!read_single_number_file(mem->filename_usage_in_bytes, &mem->usage_in_bytes)))
779 mem->usage_in_bytes_updated = 1;
781 mem->usage_in_bytes_updated = 0;
784 if(likely(mem->filename_msw_usage_in_bytes)) {
785 if(likely(!read_single_number_file(mem->filename_msw_usage_in_bytes, &mem->msw_usage_in_bytes)))
786 mem->msw_usage_in_bytes_updated = 1;
788 mem->msw_usage_in_bytes_updated = 0;
791 if(likely(mem->filename_failcnt)) {
792 if(unlikely(mem->failcnt_delay_counter > 0)) {
793 mem->failcnt_updated = 0;
794 mem->failcnt_delay_counter--;
796 else if(likely(!read_single_number_file(mem->filename_failcnt, &mem->failcnt))) {
797 mem->failcnt_updated = 1;
799 if(unlikely(!mem->failcnt))
800 mem->failcnt_delay_counter = cgroup_recheck_zero_mem_failcnt_every_iterations;
805 static inline void cgroup_read(struct cgroup *cg) {
806 debug(D_CGROUP, "reading metrics for cgroups '%s'", cg->id);
808 cgroup_read_cpuacct_stat(&cg->cpuacct_stat);
809 cgroup_read_cpuacct_usage(&cg->cpuacct_usage);
810 cgroup_read_memory(&cg->memory);
811 cgroup_read_blkio(&cg->io_service_bytes);
812 cgroup_read_blkio(&cg->io_serviced);
813 cgroup_read_blkio(&cg->throttle_io_service_bytes);
814 cgroup_read_blkio(&cg->throttle_io_serviced);
815 cgroup_read_blkio(&cg->io_merged);
816 cgroup_read_blkio(&cg->io_queued);
819 static inline void read_all_cgroups(struct cgroup *root) {
820 debug(D_CGROUP, "reading metrics for all cgroups");
824 for(cg = root; cg ; cg = cg->next)
825 if(cg->enabled && cg->available)
829 // ----------------------------------------------------------------------------
830 // add/remove/find cgroup objects
832 #define CGROUP_CHARTID_LINE_MAX 1024
834 static inline char *cgroup_title_strdupz(const char *s) {
835 if(!s || !*s) s = "/";
837 if(*s == '/' && s[1] != '\0') s++;
839 char *r = strdupz(s);
840 netdata_fix_chart_name(r);
845 static inline char *cgroup_chart_id_strdupz(const char *s) {
846 if(!s || !*s) s = "/";
848 if(*s == '/' && s[1] != '\0') s++;
850 char *r = strdupz(s);
851 netdata_fix_chart_id(r);
856 static inline void cgroup_get_chart_name(struct cgroup *cg) {
857 debug(D_CGROUP, "looking for the name of cgroup '%s' with chart id '%s' and title '%s'", cg->id, cg->chart_id, cg->chart_title);
860 char buffer[CGROUP_CHARTID_LINE_MAX + 1];
862 snprintfz(buffer, CGROUP_CHARTID_LINE_MAX, "exec %s '%s'", cgroups_rename_script, cg->chart_id);
864 debug(D_CGROUP, "executing command '%s' for cgroup '%s'", buffer, cg->id);
865 FILE *fp = mypopen(buffer, &cgroup_pid);
867 // debug(D_CGROUP, "reading from command '%s' for cgroup '%s'", buffer, cg->id);
868 char *s = fgets(buffer, CGROUP_CHARTID_LINE_MAX, fp);
869 // debug(D_CGROUP, "closing command for cgroup '%s'", cg->id);
870 mypclose(fp, cgroup_pid);
871 // debug(D_CGROUP, "closed command for cgroup '%s'", cg->id);
873 if(s && *s && *s != '\n') {
874 debug(D_CGROUP, "cgroup '%s' should be renamed to '%s'", cg->id, s);
878 freez(cg->chart_title);
879 cg->chart_title = cgroup_title_strdupz(s);
882 cg->chart_id = cgroup_chart_id_strdupz(s);
883 cg->hash_chart = simple_hash(cg->chart_id);
887 error("CGROUP: Cannot popen(\"%s\", \"r\").", buffer);
890 static inline struct cgroup *cgroup_add(const char *id) {
891 if(!id || !*id) id = "/";
892 debug(D_CGROUP, "adding to list, cgroup with id '%s'", id);
894 if(cgroup_root_count >= cgroup_root_max) {
895 info("Maximum number of cgroups reached (%d). Not adding cgroup '%s'", cgroup_root_count, id);
899 int def = simple_pattern_matches(disabled_cgroups_patterns, id)?0:cgroup_enable_new_cgroups_detected_at_runtime;
900 struct cgroup *cg = callocz(1, sizeof(struct cgroup));
902 cg->id = strdupz(id);
903 cg->hash = simple_hash(cg->id);
905 cg->chart_title = cgroup_title_strdupz(id);
907 cg->chart_id = cgroup_chart_id_strdupz(id);
908 cg->hash_chart = simple_hash(cg->chart_id);
915 for(e = cgroup_root; e->next ;e = e->next) ;
921 // fix the chart_id and title by calling the external script
922 if(!simple_pattern_matches(disabled_cgroup_renames, cg->id) &&
923 !simple_pattern_matches(disabled_cgroup_renames, cg->chart_id)) {
925 cgroup_get_chart_name(cg);
927 debug(D_CGROUP, "cgroup '%s' renamed to '%s' (title: '%s')", cg->id, cg->chart_id, cg->chart_title);
930 debug(D_CGROUP, "cgroup '%s' will not be renamed - it matches the list of disabled cgroup renames (will be shown as '%s')", cg->id, cg->chart_id);
932 int user_configurable = 1;
934 // check if this cgroup should be a systemd service
935 if(cgroup_enable_systemd_services) {
936 if(simple_pattern_matches(systemd_services_cgroups, cg->id) ||
937 simple_pattern_matches(systemd_services_cgroups, cg->chart_id)) {
938 debug(D_CGROUP, "cgroup '%s' with chart id '%s' (title: '%s') matches systemd services cgroups", cg->id, cg->chart_id, cg->chart_title);
940 char buffer[CGROUP_CHARTID_LINE_MAX + 1];
941 cg->options |= CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE;
943 strncpy(buffer, cg->id, CGROUP_CHARTID_LINE_MAX);
946 //freez(cg->chart_id);
947 //cg->chart_id = cgroup_chart_id_strdupz(s);
948 //cg->hash_chart = simple_hash(cg->chart_id);
950 // skip to the last slash
951 size_t len = strlen(s);
952 while(len--) if(unlikely(s[len] == '/')) break;
953 if(len) s = &s[len + 1];
957 while(len--) if(unlikely(s[len] == '.')) break;
958 if(len) s[len] = '\0';
960 freez(cg->chart_title);
961 cg->chart_title = cgroup_title_strdupz(s);
964 user_configurable = 0;
966 debug(D_CGROUP, "cgroup '%s' renamed to '%s' (title: '%s')", cg->id, cg->chart_id, cg->chart_title);
969 debug(D_CGROUP, "cgroup '%s' with chart id '%s' (title: '%s') does not match systemd services groups", cg->id, cg->chart_id, cg->chart_title);
972 if(user_configurable) {
973 // allow the user to enable/disable this individualy
974 char option[FILENAME_MAX + 1];
975 snprintfz(option, FILENAME_MAX, "enable cgroup %s", cg->chart_title);
976 cg->enabled = (char) config_get_boolean("plugin:cgroups", option, def);
979 // detect duplicate cgroups
982 for (t = cgroup_root; t; t = t->next) {
983 if (t != cg && t->enabled && t->hash_chart == cg->hash_chart && !strcmp(t->chart_id, cg->chart_id)) {
984 if (!strncmp(t->chart_id, "/system.slice/", 14) && !strncmp(cg->chart_id, "/init.scope/system.slice/", 25)) {
985 error("Control group with chart id '%s' already exists with id '%s' and is enabled. Swapping them by enabling cgroup with id '%s' and disabling cgroup with id '%s'.",
986 cg->chart_id, t->id, cg->id, t->id);
987 debug(D_CGROUP, "Control group with chart id '%s' already exists with id '%s' and is enabled. Swapping them by enabling cgroup with id '%s' and disabling cgroup with id '%s'.",
988 cg->chart_id, t->id, cg->id, t->id);
990 t->options |= CGROUP_OPTIONS_DISABLED_DUPLICATE;
993 error("Control group with chart id '%s' already exists with id '%s' and is enabled and available. Disabling cgroup with id '%s'.",
994 cg->chart_id, t->id, cg->id);
995 debug(D_CGROUP, "Control group with chart id '%s' already exists with id '%s' and is enabled and available. Disabling cgroup with id '%s'.",
996 cg->chart_id, t->id, cg->id);
998 cg->options |= CGROUP_OPTIONS_DISABLED_DUPLICATE;
1006 debug(D_CGROUP, "ADDED CGROUP: '%s' with chart id '%s' and title '%s' as %s (default was %s)", cg->id, cg->chart_id, cg->chart_title, (cg->enabled)?"enabled":"disabled", (def)?"enabled":"disabled");
1011 static inline void cgroup_free(struct cgroup *cg) {
1012 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");
1014 freez(cg->cpuacct_usage.cpu_percpu);
1016 freez(cg->cpuacct_stat.filename);
1017 freez(cg->cpuacct_usage.filename);
1019 freez(cg->memory.filename);
1020 freez(cg->memory.filename_failcnt);
1021 freez(cg->memory.filename_usage_in_bytes);
1022 freez(cg->memory.filename_msw_usage_in_bytes);
1024 freez(cg->io_service_bytes.filename);
1025 freez(cg->io_serviced.filename);
1027 freez(cg->throttle_io_service_bytes.filename);
1028 freez(cg->throttle_io_serviced.filename);
1030 freez(cg->io_merged.filename);
1031 freez(cg->io_queued.filename);
1034 freez(cg->chart_id);
1035 freez(cg->chart_title);
1039 cgroup_root_count--;
1042 // find if a given cgroup exists
1043 static inline struct cgroup *cgroup_find(const char *id) {
1044 debug(D_CGROUP, "searching for cgroup '%s'", id);
1046 uint32_t hash = simple_hash(id);
1049 for(cg = cgroup_root; cg ; cg = cg->next) {
1050 if(hash == cg->hash && strcmp(id, cg->id) == 0)
1054 debug(D_CGROUP, "cgroup '%s' %s in memory", id, (cg)?"found":"not found");
1058 // ----------------------------------------------------------------------------
1059 // detect running cgroups
1061 // callback for find_file_in_subdirs()
1062 static inline void found_subdir_in_dir(const char *dir) {
1063 debug(D_CGROUP, "examining cgroup dir '%s'", dir);
1065 struct cgroup *cg = cgroup_find(dir);
1067 if(*dir && cgroup_max_depth > 0) {
1071 for(s = dir; *s ;s++)
1072 if(unlikely(*s == '/'))
1075 if(depth > cgroup_max_depth) {
1076 info("cgroup '%s' is too deep (%d, while max is %d)", dir, depth, cgroup_max_depth);
1080 // debug(D_CGROUP, "will add dir '%s' as cgroup", dir);
1081 cg = cgroup_add(dir);
1084 if(cg) cg->available = 1;
1087 static inline int find_dir_in_subdirs(const char *base, const char *this, void (*callback)(const char *)) {
1088 if(!this) this = base;
1089 debug(D_CGROUP, "searching for directories in '%s' (base '%s')", this?this:"", base);
1091 size_t dirlen = strlen(this), baselen = strlen(base);
1096 const char *relative_path = &this[baselen];
1097 if(!*relative_path) relative_path = "/";
1099 DIR *dir = opendir(this);
1101 error("Cannot read cgroups directory '%s'", base);
1106 callback(relative_path);
1108 struct dirent *de = NULL;
1109 while((de = readdir(dir))) {
1110 if(de->d_type == DT_DIR
1112 (de->d_name[0] == '.' && de->d_name[1] == '\0')
1113 || (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
1117 if(de->d_type == DT_DIR) {
1119 const char *r = relative_path;
1120 if(*r == '\0') r = "/";
1122 // do not decent in directories we are not interested
1124 if(simple_pattern_matches(disabled_cgroup_paths, r))
1127 // we check for this option here
1128 // so that the config will not have settings
1129 // for leaf directories
1130 char option[FILENAME_MAX + 1];
1131 snprintfz(option, FILENAME_MAX, "search for cgroups under %s", r);
1132 option[FILENAME_MAX] = '\0';
1133 enabled = config_get_boolean("plugin:cgroups", option, def);
1137 char *s = mallocz(dirlen + strlen(de->d_name) + 2);
1140 strcat(s, de->d_name);
1141 int ret2 = find_dir_in_subdirs(base, s, callback);
1142 if(ret2 > 0) ret += ret2;
1152 static inline void mark_all_cgroups_as_not_available() {
1153 debug(D_CGROUP, "marking all cgroups as not available");
1157 // mark all as not available
1158 for(cg = cgroup_root; cg ; cg = cg->next) {
1163 static inline void cleanup_all_cgroups() {
1164 struct cgroup *cg = cgroup_root, *last = NULL;
1167 if(!cg->available) {
1168 // enable the first duplicate cgroup
1171 for(t = cgroup_root; t ; t = t->next) {
1172 if(t != cg && t->available && !t->enabled && t->options & CGROUP_OPTIONS_DISABLED_DUPLICATE && t->hash_chart == cg->hash_chart && !strcmp(t->chart_id, cg->chart_id)) {
1173 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);
1175 t->options &= ~CGROUP_OPTIONS_DISABLED_DUPLICATE;
1182 cgroup_root = cg->next;
1184 last->next = cg->next;
1200 static inline void find_all_cgroups() {
1201 debug(D_CGROUP, "searching for cgroups");
1203 mark_all_cgroups_as_not_available();
1205 if(cgroup_enable_cpuacct_stat || cgroup_enable_cpuacct_usage) {
1206 if (find_dir_in_subdirs(cgroup_cpuacct_base, NULL, found_subdir_in_dir) == -1) {
1207 cgroup_enable_cpuacct_stat = cgroup_enable_cpuacct_usage = 0;
1208 error("disabled cgroup cpu statistics.");
1212 if(cgroup_enable_blkio) {
1213 if (find_dir_in_subdirs(cgroup_blkio_base, NULL, found_subdir_in_dir) == -1) {
1214 cgroup_enable_blkio = 0;
1215 error("disabled cgroup blkio statistics.");
1219 if(cgroup_enable_memory) {
1220 if(find_dir_in_subdirs(cgroup_memory_base, NULL, found_subdir_in_dir) == -1) {
1221 cgroup_enable_memory = 0;
1222 error("disabled cgroup memory statistics.");
1226 if(cgroup_enable_devices) {
1227 if(find_dir_in_subdirs(cgroup_devices_base, NULL, found_subdir_in_dir) == -1) {
1228 cgroup_enable_devices = 0;
1229 error("disabled cgroup devices statistics.");
1233 // remove any non-existing cgroups
1234 cleanup_all_cgroups();
1238 for(cg = cgroup_root; cg ; cg = cg->next) {
1239 // fprintf(stderr, " >>> CGROUP '%s' (%u - %s) with name '%s'\n", cg->id, cg->hash, cg->available?"available":"stopped", cg->name);
1241 if(unlikely(!cg->available))
1244 debug(D_CGROUP, "checking paths for cgroup '%s'", cg->id);
1246 // check for newly added cgroups
1247 // and update the filenames they read
1248 char filename[FILENAME_MAX + 1];
1249 if(unlikely(cgroup_enable_cpuacct_stat && !cg->cpuacct_stat.filename)) {
1250 snprintfz(filename, FILENAME_MAX, "%s%s/cpuacct.stat", cgroup_cpuacct_base, cg->id);
1251 if(likely(stat(filename, &buf) != -1)) {
1252 cg->cpuacct_stat.filename = strdupz(filename);
1253 debug(D_CGROUP, "cpuacct.stat filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_stat.filename);
1255 else debug(D_CGROUP, "cpuacct.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1258 if(unlikely(cgroup_enable_cpuacct_usage && !cg->cpuacct_usage.filename && !(cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE))) {
1259 snprintfz(filename, FILENAME_MAX, "%s%s/cpuacct.usage_percpu", cgroup_cpuacct_base, cg->id);
1260 if(likely(stat(filename, &buf) != -1)) {
1261 cg->cpuacct_usage.filename = strdupz(filename);
1262 debug(D_CGROUP, "cpuacct.usage_percpu filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_usage.filename);
1264 else debug(D_CGROUP, "cpuacct.usage_percpu file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1267 if(unlikely(cgroup_enable_memory)) {
1268 if(unlikely(!cg->memory.filename) && !(cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE)) {
1269 snprintfz(filename, FILENAME_MAX, "%s%s/memory.stat", cgroup_memory_base, cg->id);
1270 if(likely(stat(filename, &buf) != -1)) {
1271 cg->memory.filename = strdupz(filename);
1272 debug(D_CGROUP, "memory.stat filename for cgroup '%s': '%s'", cg->id, cg->memory.filename);
1275 debug(D_CGROUP, "memory.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1277 if(unlikely(!cg->memory.filename_usage_in_bytes)) {
1278 snprintfz(filename, FILENAME_MAX, "%s%s/memory.usage_in_bytes", cgroup_memory_base, cg->id);
1279 if(likely(stat(filename, &buf) != -1)) {
1280 cg->memory.filename_usage_in_bytes = strdupz(filename);
1281 debug(D_CGROUP, "memory.usage_in_bytes filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_usage_in_bytes);
1284 debug(D_CGROUP, "memory.usage_in_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1286 if(unlikely(!cg->memory.filename_msw_usage_in_bytes)) {
1287 snprintfz(filename, FILENAME_MAX, "%s%s/memory.msw_usage_in_bytes", cgroup_memory_base, cg->id);
1288 if(likely(stat(filename, &buf) != -1)) {
1289 cg->memory.filename_msw_usage_in_bytes = strdupz(filename);
1290 debug(D_CGROUP, "memory.msw_usage_in_bytes filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_msw_usage_in_bytes);
1293 debug(D_CGROUP, "memory.msw_usage_in_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1295 if(unlikely(!cg->memory.filename_failcnt)) {
1296 snprintfz(filename, FILENAME_MAX, "%s%s/memory.failcnt", cgroup_memory_base, cg->id);
1297 if(likely(stat(filename, &buf) != -1)) {
1298 cg->memory.filename_failcnt = strdupz(filename);
1299 debug(D_CGROUP, "memory.failcnt filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_failcnt);
1302 debug(D_CGROUP, "memory.failcnt file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1306 if(unlikely(cgroup_enable_blkio)) {
1307 if(unlikely(!cg->io_service_bytes.filename)) {
1308 snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_service_bytes", cgroup_blkio_base, cg->id);
1309 if(likely(stat(filename, &buf) != -1)) {
1310 cg->io_service_bytes.filename = strdupz(filename);
1311 debug(D_CGROUP, "io_service_bytes filename for cgroup '%s': '%s'", cg->id, cg->io_service_bytes.filename);
1314 debug(D_CGROUP, "io_service_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1317 if(unlikely(!cg->io_serviced.filename)) {
1318 snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_serviced", cgroup_blkio_base, cg->id);
1319 if(likely(stat(filename, &buf) != -1)) {
1320 cg->io_serviced.filename = strdupz(filename);
1321 debug(D_CGROUP, "io_serviced filename for cgroup '%s': '%s'", cg->id, cg->io_serviced.filename);
1324 debug(D_CGROUP, "io_serviced file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1327 if(unlikely(!cg->throttle_io_service_bytes.filename)) {
1328 snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_service_bytes", cgroup_blkio_base, cg->id);
1329 if(likely(stat(filename, &buf) != -1)) {
1330 cg->throttle_io_service_bytes.filename = strdupz(filename);
1331 debug(D_CGROUP, "throttle_io_service_bytes filename for cgroup '%s': '%s'", cg->id, cg->throttle_io_service_bytes.filename);
1334 debug(D_CGROUP, "throttle_io_service_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1337 if(unlikely(!cg->throttle_io_serviced.filename)) {
1338 snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_serviced", cgroup_blkio_base, cg->id);
1339 if(likely(stat(filename, &buf) != -1)) {
1340 cg->throttle_io_serviced.filename = strdupz(filename);
1341 debug(D_CGROUP, "throttle_io_serviced filename for cgroup '%s': '%s'", cg->id, cg->throttle_io_serviced.filename);
1344 debug(D_CGROUP, "throttle_io_serviced file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1347 if(unlikely(!cg->io_merged.filename)) {
1348 snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_merged", cgroup_blkio_base, cg->id);
1349 if(likely(stat(filename, &buf) != -1)) {
1350 cg->io_merged.filename = strdupz(filename);
1351 debug(D_CGROUP, "io_merged filename for cgroup '%s': '%s'", cg->id, cg->io_merged.filename);
1354 debug(D_CGROUP, "io_merged file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1357 if(unlikely(!cg->io_queued.filename)) {
1358 snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_queued", cgroup_blkio_base, cg->id);
1359 if(likely(stat(filename, &buf) != -1)) {
1360 cg->io_queued.filename = strdupz(filename);
1361 debug(D_CGROUP, "io_queued filename for cgroup '%s': '%s'", cg->id, cg->io_queued.filename);
1364 debug(D_CGROUP, "io_queued file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1369 debug(D_CGROUP, "done searching for cgroups");
1373 // ----------------------------------------------------------------------------
1376 #define CHART_TITLE_MAX 300
1378 void update_services_charts(int update_every,
1384 int do_throttle_ops /*,
1386 int do_merged_ops */
1390 *st_mem_usage = NULL,
1393 *st_io_serviced_read = NULL,
1394 *st_throttle_io_read = NULL,
1395 *st_throttle_ops_read = NULL,
1397 *st_queued_ops_read = NULL,
1398 *st_merged_ops_read = NULL,
1401 *st_io_write = NULL,
1402 *st_io_serviced_write = NULL,
1403 *st_throttle_io_write = NULL,
1404 *st_throttle_ops_write = NULL/*,
1405 *st_queued_ops_write = NULL,
1406 *st_merged_ops_write = NULL*/;
1408 // create the charts
1410 if(likely(do_cpu)) {
1411 if(unlikely(!st_cpu)) {
1412 char title[CHART_TITLE_MAX + 1];
1414 st_cpu = rrdset_find_bytype("services", "cpu");
1415 if(likely(!st_cpu)) {
1416 snprintfz(title, CHART_TITLE_MAX, "Systemd Services CPU utilization (%d%% = %d core%s)", (processors * 100), processors, (processors > 1) ? "s" : "");
1417 st_cpu = rrdset_create("services", "cpu", NULL, "cpu", "services.cpu", title, "%", 30000, update_every, RRDSET_TYPE_STACKED);
1421 rrdset_next(st_cpu);
1424 if(likely(do_mem_usage)) {
1425 if(unlikely(!st_mem_usage)) {
1426 st_mem_usage = rrdset_find_bytype("services", "mem_usage");
1427 if(likely(!st_mem_usage))
1428 st_mem_usage = rrdset_create("services", "mem_usage", NULL, "mem", "services.mem_usage", "Systemd Services RAM Usage", "MB", 30001, update_every, RRDSET_TYPE_STACKED);
1431 rrdset_next(st_mem_usage);
1435 if(unlikely(!st_io_read)) {
1436 st_io_read = rrdset_find_bytype("services", "io_read");
1437 if(likely(!st_io_read))
1438 st_io_read = rrdset_create("services", "io_read", NULL, "disk", "services.io_read", "Systemd Services Disk Read Bandwidth", "KB/s", 30012, update_every, RRDSET_TYPE_STACKED);
1441 rrdset_next(st_io_read);
1443 if(unlikely(!st_io_write)) {
1444 st_io_write = rrdset_find_bytype("services", "io_write");
1445 if(likely(!st_io_write))
1446 st_io_write = rrdset_create("services", "io_write", NULL, "disk", "services.io_write", "Systemd Services Disk Write Bandwidth", "KB/s", 30013, update_every, RRDSET_TYPE_STACKED);
1449 rrdset_next(st_io_write);
1452 if(likely(do_io_ops)) {
1453 if(unlikely(!st_io_serviced_read)) {
1454 st_io_serviced_read = rrdset_find_bytype("services", "io_ops_read");
1455 if(likely(!st_io_serviced_read))
1456 st_io_serviced_read = rrdset_create("services", "io_ops_read", NULL, "disk", "services.io_ops_read", "Systemd Services Disk Read Operations", "operations/s", 30014, update_every, RRDSET_TYPE_STACKED);
1459 rrdset_next(st_io_serviced_read);
1461 if(unlikely(!st_io_serviced_write)) {
1462 st_io_serviced_write = rrdset_find_bytype("services", "io_ops_write");
1463 if(likely(!st_io_serviced_write))
1464 st_io_serviced_write = rrdset_create("services", "io_ops_write", NULL, "disk", "services.io_ops_write", "Systemd Services Disk Write Operations", "operations/s", 30015, update_every, RRDSET_TYPE_STACKED);
1467 rrdset_next(st_io_serviced_write);
1470 if(likely(do_throttle_io)) {
1471 if(unlikely(!st_throttle_io_read)) {
1472 st_throttle_io_read = rrdset_find_bytype("services", "throttle_io_read");
1473 if(likely(!st_throttle_io_read))
1474 st_throttle_io_read = rrdset_create("services", "throttle_io_read", NULL, "disk", "services.throttle_io_read", "Systemd Services Throttle Disk Read Bandwidth", "KB/s", 30016, update_every, RRDSET_TYPE_STACKED);
1477 rrdset_next(st_throttle_io_read);
1479 if(unlikely(!st_throttle_io_write)) {
1480 st_throttle_io_write = rrdset_find_bytype("services", "throttle_io_write");
1481 if(likely(!st_throttle_io_write))
1482 st_throttle_io_write = rrdset_create("services", "throttle_io_write", NULL, "disk", "services.throttle_io_write", "Systemd Services Throttle Disk Write Bandwidth", "KB/s", 30017, update_every, RRDSET_TYPE_STACKED);
1485 rrdset_next(st_throttle_io_write);
1488 if(likely(do_throttle_ops)) {
1489 if(unlikely(!st_throttle_ops_read)) {
1490 st_throttle_ops_read = rrdset_find_bytype("services", "throttle_io_ops_read");
1491 if(likely(!st_throttle_ops_read))
1492 st_throttle_ops_read = rrdset_create("services", "throttle_io_ops_read", NULL, "disk", "services.throttle_io_ops_read", "Systemd Services Throttle Disk Read Operations", "operations/s", 30018, update_every, RRDSET_TYPE_STACKED);
1495 rrdset_next(st_throttle_ops_read);
1497 if(unlikely(!st_throttle_ops_write)) {
1498 st_throttle_ops_write = rrdset_find_bytype("services", "throttle_io_ops_write");
1499 if(likely(!st_throttle_ops_write))
1500 st_throttle_ops_write = rrdset_create("services", "throttle_io_ops_write", NULL, "disk", "services.throttle_io_ops_write", "Systemd Services Throttle Disk Write Operations", "operations/s", 30019, update_every, RRDSET_TYPE_STACKED);
1503 rrdset_next(st_throttle_ops_write);
1506 // update the values
1508 for(cg = cgroup_root; cg ; cg = cg->next) {
1509 if(unlikely(!cg->available || !cg->enabled || !(cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE)))
1512 if(likely(do_cpu && cg->cpuacct_stat.updated)) {
1513 if(unlikely(!cg->rd_cpu))
1514 cg->rd_cpu = rrddim_add(st_cpu, cg->chart_id, cg->chart_title, 100, hz, RRDDIM_INCREMENTAL);
1516 rrddim_set_by_pointer(st_cpu, cg->rd_cpu, cg->cpuacct_stat.user + cg->cpuacct_stat.system);
1519 if(likely(do_mem_usage && cg->memory.usage_in_bytes_updated)) {
1520 if(unlikely(!cg->rd_mem_usage))
1521 cg->rd_mem_usage = rrddim_add(st_mem_usage, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1523 rrddim_set_by_pointer(st_mem_usage, cg->rd_mem_usage, cg->memory.usage_in_bytes);
1526 if(likely(do_io && cg->io_service_bytes.updated)) {
1527 if(unlikely(!cg->rd_io_service_bytes_read))
1528 cg->rd_io_service_bytes_read = rrddim_add(st_io_read, cg->chart_id, cg->chart_title, 1, 1024, RRDDIM_INCREMENTAL);
1530 rrddim_set_by_pointer(st_io_read, cg->rd_io_service_bytes_read, cg->io_service_bytes.Read);
1532 if(unlikely(!cg->rd_io_service_bytes_write))
1533 cg->rd_io_service_bytes_write = rrddim_add(st_io_write, cg->chart_id, cg->chart_title, 1, 1024, RRDDIM_INCREMENTAL);
1535 rrddim_set_by_pointer(st_io_write, cg->rd_io_service_bytes_write, cg->io_service_bytes.Write);
1538 if(likely(do_io_ops && cg->io_serviced.updated)) {
1539 if(unlikely(!cg->rd_io_serviced_read))
1540 cg->rd_io_serviced_read = rrddim_add(st_io_serviced_read, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
1542 rrddim_set_by_pointer(st_io_serviced_read, cg->rd_io_serviced_read, cg->io_serviced.Read);
1544 if(unlikely(!cg->rd_io_serviced_write))
1545 cg->rd_io_serviced_write = rrddim_add(st_io_serviced_write, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
1547 rrddim_set_by_pointer(st_io_serviced_write, cg->rd_io_serviced_write, cg->io_serviced.Write);
1550 if(likely(do_throttle_io && cg->throttle_io_service_bytes.updated)) {
1551 if(unlikely(!cg->rd_throttle_io_read))
1552 cg->rd_throttle_io_read = rrddim_add(st_throttle_io_read, cg->chart_id, cg->chart_title, 1, 1024, RRDDIM_INCREMENTAL);
1554 rrddim_set_by_pointer(st_throttle_io_read, cg->rd_throttle_io_read, cg->throttle_io_service_bytes.Read);
1556 if(unlikely(!cg->rd_throttle_io_write))
1557 cg->rd_throttle_io_write = rrddim_add(st_throttle_io_write, cg->chart_id, cg->chart_title, 1, 1024, RRDDIM_INCREMENTAL);
1559 rrddim_set_by_pointer(st_throttle_io_write, cg->rd_throttle_io_write, cg->throttle_io_service_bytes.Write);
1562 if(likely(do_throttle_ops && cg->throttle_io_serviced.updated)) {
1563 if(unlikely(!cg->rd_throttle_io_serviced_read))
1564 cg->rd_throttle_io_serviced_read = rrddim_add(st_throttle_ops_read, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
1566 rrddim_set_by_pointer(st_throttle_ops_read, cg->rd_throttle_io_serviced_read, cg->throttle_io_serviced.Read);
1568 if(unlikely(!cg->rd_throttle_io_serviced_write))
1569 cg->rd_throttle_io_serviced_write = rrddim_add(st_throttle_ops_write, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
1571 rrddim_set_by_pointer(st_throttle_ops_write, cg->rd_throttle_io_serviced_write, cg->throttle_io_serviced.Write);
1575 // complete the iteration
1577 rrdset_done(st_cpu);
1579 if(likely(do_mem_usage))
1580 rrdset_done(st_mem_usage);
1583 rrdset_done(st_io_read);
1584 rrdset_done(st_io_write);
1587 if(likely(do_io_ops)) {
1588 rrdset_done(st_io_serviced_read);
1589 rrdset_done(st_io_serviced_write);
1592 if(likely(do_throttle_io)) {
1593 rrdset_done(st_throttle_io_read);
1594 rrdset_done(st_throttle_io_write);
1597 if(likely(do_throttle_ops)) {
1598 rrdset_done(st_throttle_ops_read);
1599 rrdset_done(st_throttle_ops_write);
1603 static inline char *cgroup_chart_type(char *buffer, const char *id, size_t len) {
1604 if(buffer[0]) return buffer;
1606 if(id[0] == '\0' || (id[0] == '/' && id[1] == '\0'))
1607 strncpy(buffer, "cgroup_root", len);
1609 snprintfz(buffer, len, "cgroup_%s", id);
1611 netdata_fix_chart_id(buffer);
1615 void update_cgroup_charts(int update_every) {
1616 debug(D_CGROUP, "updating cgroups charts");
1618 char type[RRD_ID_LENGTH_MAX + 1];
1619 char title[CHART_TITLE_MAX + 1];
1621 int services_do_cpu = 0,
1622 services_do_mem_usage = 0,
1624 services_do_io_ops = 0,
1625 services_do_throttle_io = 0,
1626 services_do_throttle_ops = 0,
1627 services_do_queued_ops = 0,
1628 services_do_merged_ops = 0;
1631 for(cg = cgroup_root; cg ; cg = cg->next) {
1632 if(unlikely(!cg->available || !cg->enabled))
1635 if(likely(cgroup_enable_systemd_services && cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE)) {
1636 if(cg->cpuacct_stat.updated && (cg->cpuacct_stat.user || cg->cpuacct_stat.system)) services_do_cpu++;
1637 if(cg->memory.usage_in_bytes_updated && (cg->memory.usage_in_bytes)) services_do_mem_usage++;
1638 if(cg->io_service_bytes.updated && (cg->io_service_bytes.Read || cg->io_service_bytes.Write)) services_do_io++;
1639 if(cg->io_serviced.updated && (cg->io_serviced.Read || cg->io_serviced.Write)) services_do_io_ops++;
1640 if(cg->throttle_io_service_bytes.updated && (cg->throttle_io_service_bytes.Read || cg->throttle_io_service_bytes.Write)) services_do_throttle_io++;
1641 if(cg->throttle_io_serviced.updated && (cg->throttle_io_serviced.Read || cg->throttle_io_serviced.Write)) services_do_throttle_ops++;
1642 if(cg->io_queued.updated && (cg->io_queued.Read || cg->io_queued.Write)) services_do_queued_ops++;
1643 if(cg->io_merged.updated && (cg->io_merged.Read || cg->io_merged.Write)) services_do_merged_ops++;
1649 if(likely(cg->cpuacct_stat.updated)) {
1650 if(unlikely(!cg->st_cpu)) {
1651 cg->st_cpu = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "cpu");
1652 if(likely(!cg->st_cpu)) {
1653 snprintfz(title, CHART_TITLE_MAX, "CPU Usage (%d%% = %d core%s) for cgroup %s", (processors * 100), processors, (processors > 1) ? "s" : "", cg->chart_title);
1654 cg->st_cpu = rrdset_create(type, "cpu", NULL, "cpu", "cgroup.cpu", title, "%", 40000, update_every, RRDSET_TYPE_STACKED);
1656 rrddim_add(cg->st_cpu, "user", NULL, 100, hz, RRDDIM_INCREMENTAL);
1657 rrddim_add(cg->st_cpu, "system", NULL, 100, hz, RRDDIM_INCREMENTAL);
1660 rrdset_next(cg->st_cpu);
1662 rrddim_set(cg->st_cpu, "user", cg->cpuacct_stat.user);
1663 rrddim_set(cg->st_cpu, "system", cg->cpuacct_stat.system);
1664 rrdset_done(cg->st_cpu);
1667 if(likely(cg->cpuacct_usage.updated)) {
1668 char id[RRD_ID_LENGTH_MAX + 1];
1671 if(unlikely(!cg->st_cpu_per_core)) {
1672 cg->st_cpu_per_core = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "cpu_per_core");
1673 if(likely(!cg->st_cpu_per_core)) {
1674 snprintfz(title, CHART_TITLE_MAX, "CPU Usage (%d%% = %d core%s) Per Core for cgroup %s", (processors * 100), processors, (processors > 1) ? "s" : "", cg->chart_title);
1675 cg->st_cpu_per_core = rrdset_create(type, "cpu_per_core", NULL, "cpu", "cgroup.cpu_per_core", title, "%", 40100, update_every, RRDSET_TYPE_STACKED);
1677 for(i = 0; i < cg->cpuacct_usage.cpus; i++) {
1678 snprintfz(id, CHART_TITLE_MAX, "cpu%u", i);
1679 rrddim_add(cg->st_cpu_per_core, id, NULL, 100, 1000000000, RRDDIM_INCREMENTAL);
1683 rrdset_next(cg->st_cpu_per_core);
1685 for(i = 0; i < cg->cpuacct_usage.cpus ;i++) {
1686 snprintfz(id, CHART_TITLE_MAX, "cpu%u", i);
1687 rrddim_set(cg->st_cpu_per_core, id, cg->cpuacct_usage.cpu_percpu[i]);
1689 rrdset_done(cg->st_cpu_per_core);
1692 if(likely(cg->memory.updated)) {
1693 if(likely(cg->memory.cache || cg->memory.rss || cg->memory.rss_huge || cg->memory.mapped_file)) {
1694 if(unlikely(!cg->st_mem)) {
1695 cg->st_mem = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "mem");
1696 if(likely(!cg->st_mem)) {
1697 snprintfz(title, CHART_TITLE_MAX, "Memory Usage for cgroup %s", cg->chart_title);
1698 cg->st_mem = rrdset_create(type, "mem", NULL, "mem", "cgroup.mem", title, "MB", 40210, update_every, RRDSET_TYPE_STACKED);
1701 rrddim_add(cg->st_mem, "cache", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1702 rrddim_add(cg->st_mem, "rss", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1703 if(cg->memory.has_dirty_swap)
1704 rrddim_add(cg->st_mem, "swap", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1705 rrddim_add(cg->st_mem, "rss_huge", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1706 rrddim_add(cg->st_mem, "mapped_file", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1709 rrdset_next(cg->st_mem);
1711 rrddim_set(cg->st_mem, "cache", cg->memory.cache);
1712 rrddim_set(cg->st_mem, "rss", cg->memory.rss);
1713 if(cg->memory.has_dirty_swap)
1714 rrddim_set(cg->st_mem, "swap", cg->memory.swap);
1715 rrddim_set(cg->st_mem, "rss_huge", cg->memory.rss_huge);
1716 rrddim_set(cg->st_mem, "mapped_file", cg->memory.mapped_file);
1717 rrdset_done(cg->st_mem);
1720 if(unlikely(!cg->st_writeback)) {
1721 cg->st_writeback = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "writeback");
1722 if(likely(!cg->st_writeback)) {
1723 snprintfz(title, CHART_TITLE_MAX, "Writeback Memory for cgroup %s", cg->chart_title);
1724 cg->st_writeback = rrdset_create(type, "writeback", NULL, "mem", "cgroup.writeback", title, "MB", 40300, update_every, RRDSET_TYPE_AREA);
1727 if(cg->memory.has_dirty_swap)
1728 rrddim_add(cg->st_writeback, "dirty", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1729 rrddim_add(cg->st_writeback, "writeback", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1732 rrdset_next(cg->st_writeback);
1734 if(cg->memory.has_dirty_swap)
1735 rrddim_set(cg->st_writeback, "dirty", cg->memory.dirty);
1736 rrddim_set(cg->st_writeback, "writeback", cg->memory.writeback);
1737 rrdset_done(cg->st_writeback);
1739 if(likely(cg->memory.pgpgin || cg->memory.pgpgout)) {
1740 if(unlikely(!cg->st_mem_activity)) {
1741 cg->st_mem_activity = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "mem_activity");
1742 if(likely(!cg->st_mem_activity)) {
1743 snprintfz(title, CHART_TITLE_MAX, "Memory Activity for cgroup %s", cg->chart_title);
1744 cg->st_mem_activity = rrdset_create(type, "mem_activity", NULL, "mem", "cgroup.mem_activity", title, "MB/s", 40400, update_every, RRDSET_TYPE_LINE);
1746 rrddim_add(cg->st_mem_activity, "pgpgin", "in", sysconf(_SC_PAGESIZE), 1024 * 1024, RRDDIM_INCREMENTAL);
1747 rrddim_add(cg->st_mem_activity, "pgpgout", "out", -sysconf(_SC_PAGESIZE), 1024 * 1024, RRDDIM_INCREMENTAL);
1750 rrdset_next(cg->st_mem_activity);
1752 rrddim_set(cg->st_mem_activity, "pgpgin", cg->memory.pgpgin);
1753 rrddim_set(cg->st_mem_activity, "pgpgout", cg->memory.pgpgout);
1754 rrdset_done(cg->st_mem_activity);
1757 if(likely(cg->memory.pgfault || cg->memory.pgmajfault)) {
1758 if(unlikely(!cg->st_pgfaults)) {
1759 cg->st_pgfaults = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "pgfaults");
1760 if(likely(!cg->st_pgfaults)) {
1761 snprintfz(title, CHART_TITLE_MAX, "Memory Page Faults for cgroup %s", cg->chart_title);
1762 cg->st_pgfaults = rrdset_create(type, "pgfaults", NULL, "mem", "cgroup.pgfaults", title, "MB/s", 40500, update_every, RRDSET_TYPE_LINE);
1764 rrddim_add(cg->st_pgfaults, "pgfault", NULL, sysconf(_SC_PAGESIZE), 1024 * 1024, RRDDIM_INCREMENTAL);
1765 rrddim_add(cg->st_pgfaults, "pgmajfault", "swap", -sysconf(_SC_PAGESIZE), 1024 * 1024, RRDDIM_INCREMENTAL);
1768 rrdset_next(cg->st_pgfaults);
1770 rrddim_set(cg->st_pgfaults, "pgfault", cg->memory.pgfault);
1771 rrddim_set(cg->st_pgfaults, "pgmajfault", cg->memory.pgmajfault);
1772 rrdset_done(cg->st_pgfaults);
1776 if(likely(cg->memory.usage_in_bytes_updated)) {
1777 if(unlikely(!cg->st_mem_usage)) {
1778 cg->st_mem_usage = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "mem_usage");
1779 if(likely(!cg->st_mem_usage)) {
1780 snprintfz(title, CHART_TITLE_MAX, "Total Memory for cgroup %s", cg->chart_title);
1781 cg->st_mem_usage = rrdset_create(type, "mem_usage", NULL, "mem", "cgroup.mem_usage", title, "MB", 40200, update_every, RRDSET_TYPE_STACKED);
1783 rrddim_add(cg->st_mem_usage, "ram", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1784 rrddim_add(cg->st_mem_usage, "swap", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1787 rrdset_next(cg->st_mem_usage);
1789 rrddim_set(cg->st_mem_usage, "ram", cg->memory.usage_in_bytes);
1790 rrddim_set(cg->st_mem_usage, "swap", (cg->memory.msw_usage_in_bytes > cg->memory.usage_in_bytes)?cg->memory.msw_usage_in_bytes - cg->memory.usage_in_bytes:0);
1791 rrdset_done(cg->st_mem_usage);
1794 if(likely(cg->memory.failcnt_updated && cg->memory.failcnt)) {
1795 if(unlikely(!cg->st_mem_failcnt)) {
1796 cg->st_mem_failcnt = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "mem_failcnt");
1797 if(likely(!cg->st_mem_failcnt)) {
1798 snprintfz(title, CHART_TITLE_MAX, "Memory Limit Failures for cgroup %s", cg->chart_title);
1799 cg->st_mem_failcnt = rrdset_create(type, "mem_failcnt", NULL, "mem", "cgroup.mem_failcnt", title, "MB", 40250, update_every, RRDSET_TYPE_LINE);
1801 rrddim_add(cg->st_mem_failcnt, "failures", NULL, 1, 1, RRDDIM_INCREMENTAL);
1804 rrdset_next(cg->st_mem_failcnt);
1806 rrddim_set(cg->st_mem_failcnt, "failures", cg->memory.failcnt);
1807 rrdset_done(cg->st_mem_failcnt);
1810 if(likely(cg->io_service_bytes.updated && (cg->io_service_bytes.Read || cg->io_service_bytes.Write))) {
1811 if(unlikely(!cg->st_io)) {
1812 cg->st_io = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "io");
1813 if(likely(!cg->st_io)) {
1814 snprintfz(title, CHART_TITLE_MAX, "I/O Bandwidth (all disks) for cgroup %s", cg->chart_title);
1815 cg->st_io = rrdset_create(type, "io", NULL, "disk", "cgroup.io", title, "KB/s", 41200, update_every, RRDSET_TYPE_AREA);
1817 rrddim_add(cg->st_io, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
1818 rrddim_add(cg->st_io, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
1821 rrdset_next(cg->st_io);
1823 rrddim_set(cg->st_io, "read", cg->io_service_bytes.Read);
1824 rrddim_set(cg->st_io, "write", cg->io_service_bytes.Write);
1825 rrdset_done(cg->st_io);
1828 if(likely(cg->io_serviced.updated && (cg->io_serviced.Read || cg->io_serviced.Write))) {
1829 if(unlikely(!cg->st_serviced_ops)) {
1830 cg->st_serviced_ops = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "serviced_ops");
1831 if(likely(!cg->st_serviced_ops)) {
1832 snprintfz(title, CHART_TITLE_MAX, "Serviced I/O Operations (all disks) for cgroup %s", cg->chart_title);
1833 cg->st_serviced_ops = rrdset_create(type, "serviced_ops", NULL, "disk", "cgroup.serviced_ops", title, "operations/s", 41200, update_every, RRDSET_TYPE_LINE);
1835 rrddim_add(cg->st_serviced_ops, "read", NULL, 1, 1, RRDDIM_INCREMENTAL);
1836 rrddim_add(cg->st_serviced_ops, "write", NULL, -1, 1, RRDDIM_INCREMENTAL);
1839 rrdset_next(cg->st_serviced_ops);
1841 rrddim_set(cg->st_serviced_ops, "read", cg->io_serviced.Read);
1842 rrddim_set(cg->st_serviced_ops, "write", cg->io_serviced.Write);
1843 rrdset_done(cg->st_serviced_ops);
1846 if(likely(cg->throttle_io_service_bytes.updated && (cg->throttle_io_service_bytes.Read || cg->throttle_io_service_bytes.Write))) {
1847 if(unlikely(!cg->st_throttle_io)) {
1848 cg->st_throttle_io = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "throttle_io");
1849 if(likely(!cg->st_throttle_io)) {
1850 snprintfz(title, CHART_TITLE_MAX, "Throttle I/O Bandwidth (all disks) for cgroup %s", cg->chart_title);
1851 cg->st_throttle_io = rrdset_create(type, "throttle_io", NULL, "disk", "cgroup.throttle_io", title, "KB/s", 41200, update_every, RRDSET_TYPE_AREA);
1853 rrddim_add(cg->st_throttle_io, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
1854 rrddim_add(cg->st_throttle_io, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
1857 rrdset_next(cg->st_throttle_io);
1859 rrddim_set(cg->st_throttle_io, "read", cg->throttle_io_service_bytes.Read);
1860 rrddim_set(cg->st_throttle_io, "write", cg->throttle_io_service_bytes.Write);
1861 rrdset_done(cg->st_throttle_io);
1864 if(likely(cg->throttle_io_serviced.updated && (cg->throttle_io_serviced.Read || cg->throttle_io_serviced.Write))) {
1865 if(unlikely(!cg->st_throttle_serviced_ops)) {
1866 cg->st_throttle_serviced_ops = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "throttle_serviced_ops");
1867 if(likely(!cg->st_throttle_serviced_ops)) {
1868 snprintfz(title, CHART_TITLE_MAX, "Throttle Serviced I/O Operations (all disks) for cgroup %s", cg->chart_title);
1869 cg->st_throttle_serviced_ops = rrdset_create(type, "throttle_serviced_ops", NULL, "disk", "cgroup.throttle_serviced_ops", title, "operations/s", 41200, update_every, RRDSET_TYPE_LINE);
1871 rrddim_add(cg->st_throttle_serviced_ops, "read", NULL, 1, 1, RRDDIM_INCREMENTAL);
1872 rrddim_add(cg->st_throttle_serviced_ops, "write", NULL, -1, 1, RRDDIM_INCREMENTAL);
1875 rrdset_next(cg->st_throttle_serviced_ops);
1877 rrddim_set(cg->st_throttle_serviced_ops, "read", cg->throttle_io_serviced.Read);
1878 rrddim_set(cg->st_throttle_serviced_ops, "write", cg->throttle_io_serviced.Write);
1879 rrdset_done(cg->st_throttle_serviced_ops);
1882 if(likely(cg->io_queued.updated)) {
1883 if(unlikely(!cg->st_queued_ops)) {
1884 cg->st_queued_ops = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "queued_ops");
1885 if(likely(!cg->st_queued_ops)) {
1886 snprintfz(title, CHART_TITLE_MAX, "Queued I/O Operations (all disks) for cgroup %s", cg->chart_title);
1887 cg->st_queued_ops = rrdset_create(type, "queued_ops", NULL, "disk", "cgroup.queued_ops", title, "operations", 42000, update_every, RRDSET_TYPE_LINE);
1889 rrddim_add(cg->st_queued_ops, "read", NULL, 1, 1, RRDDIM_ABSOLUTE);
1890 rrddim_add(cg->st_queued_ops, "write", NULL, -1, 1, RRDDIM_ABSOLUTE);
1893 rrdset_next(cg->st_queued_ops);
1895 rrddim_set(cg->st_queued_ops, "read", cg->io_queued.Read);
1896 rrddim_set(cg->st_queued_ops, "write", cg->io_queued.Write);
1897 rrdset_done(cg->st_queued_ops);
1900 if(likely(cg->io_merged.updated && (cg->io_merged.Read || cg->io_merged.Write))) {
1901 if(unlikely(!cg->st_merged_ops)) {
1902 cg->st_merged_ops = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "merged_ops");
1903 if(likely(!cg->st_merged_ops)) {
1904 snprintfz(title, CHART_TITLE_MAX, "Merged I/O Operations (all disks) for cgroup %s", cg->chart_title);
1905 cg->st_merged_ops = rrdset_create(type, "merged_ops", NULL, "disk", "cgroup.merged_ops", title, "operations/s", 42100, update_every, RRDSET_TYPE_LINE);
1907 rrddim_add(cg->st_merged_ops, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
1908 rrddim_add(cg->st_merged_ops, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
1911 rrdset_next(cg->st_merged_ops);
1913 rrddim_set(cg->st_merged_ops, "read", cg->io_merged.Read);
1914 rrddim_set(cg->st_merged_ops, "write", cg->io_merged.Write);
1915 rrdset_done(cg->st_merged_ops);
1919 if(likely(cgroup_enable_systemd_services))
1920 update_services_charts(update_every,
1922 services_do_mem_usage,
1925 services_do_throttle_io,
1926 services_do_throttle_ops/*,
1927 services_do_queued_ops,
1928 services_do_merged_ops*/
1931 debug(D_CGROUP, "done updating cgroups charts");
1934 // ----------------------------------------------------------------------------
1937 void *cgroups_main(void *ptr) {
1938 struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
1940 info("CGROUP Plugin thread created with task id %d", gettid());
1942 if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
1943 error("Cannot set pthread cancel type to DEFERRED.");
1945 if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
1946 error("Cannot set pthread cancel state to ENABLE.");
1948 struct rusage thread;
1950 // when ZERO, attempt to do it
1951 int vdo_cpu_netdata = config_get_boolean("plugin:cgroups", "cgroups plugin resource charts", 1);
1953 read_cgroup_plugin_configuration();
1955 RRDSET *stcpu_thread = NULL;
1957 usec_t step = cgroup_update_every * USEC_PER_SEC;
1958 usec_t find_every = cgroup_check_for_new_every * USEC_PER_SEC, find_next = 0;
1960 usec_t now = now_monotonic_usec();
1961 usec_t next = now - (now % step) + step;
1964 sleep_usec(next - now);
1965 now = now_monotonic_usec();
1968 if(unlikely(netdata_exit)) break;
1970 // BEGIN -- the job to be done
1972 if(unlikely(now >= find_next)) {
1974 find_next = now + find_every;
1977 read_all_cgroups(cgroup_root);
1978 update_cgroup_charts(cgroup_update_every);
1980 // END -- the job is done
1982 // --------------------------------------------------------------------
1984 if(vdo_cpu_netdata) {
1985 getrusage(RUSAGE_THREAD, &thread);
1987 if(unlikely(!stcpu_thread)) {
1988 stcpu_thread = rrdset_find("netdata.plugin_cgroups_cpu");
1989 if(unlikely(!stcpu_thread))
1990 stcpu_thread = rrdset_create("netdata", "plugin_cgroups_cpu", NULL, "cgroups", NULL, "NetData CGroups Plugin CPU usage", "milliseconds/s", 132000, cgroup_update_every, RRDSET_TYPE_STACKED);
1992 rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRDDIM_INCREMENTAL);
1993 rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
1996 rrdset_next(stcpu_thread);
1998 rrddim_set(stcpu_thread, "user" , thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec);
1999 rrddim_set(stcpu_thread, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec);
2000 rrdset_done(stcpu_thread);
2004 info("CGROUP thread exiting");
2006 static_thread->enabled = 0;