]> arthur.barton.de Git - netdata.git/blob - src/sys_fs_cgroup.c
Merge pull request #1627 from l2isbad/tomcat_bugfix
[netdata.git] / src / sys_fs_cgroup.c
1 #include "common.h"
2
3 // ----------------------------------------------------------------------------
4 // cgroup globals
5
6 #define CHART_PRIORITY_SYSTEMD_SERVICES 19000
7 #define CHART_PRIORITY_CONTAINERS       40000
8
9 static long system_page_size = 4096; // system will be queried via sysconf() in configuration()
10
11 static int cgroup_enable_cpuacct_stat = CONFIG_ONDEMAND_ONDEMAND;
12 static int cgroup_enable_cpuacct_usage = CONFIG_ONDEMAND_ONDEMAND;
13 static int cgroup_enable_memory = CONFIG_ONDEMAND_ONDEMAND;
14 static int cgroup_enable_detailed_memory = CONFIG_ONDEMAND_ONDEMAND;
15 static int cgroup_enable_memory_failcnt = CONFIG_ONDEMAND_ONDEMAND;
16 static int cgroup_enable_swap = CONFIG_ONDEMAND_ONDEMAND;
17 static int cgroup_enable_blkio_io = CONFIG_ONDEMAND_ONDEMAND;
18 static int cgroup_enable_blkio_ops = CONFIG_ONDEMAND_ONDEMAND;
19 static int cgroup_enable_blkio_throttle_io = CONFIG_ONDEMAND_ONDEMAND;
20 static int cgroup_enable_blkio_throttle_ops = CONFIG_ONDEMAND_ONDEMAND;
21 static int cgroup_enable_blkio_merged_ops = CONFIG_ONDEMAND_ONDEMAND;
22 static int cgroup_enable_blkio_queued_ops = CONFIG_ONDEMAND_ONDEMAND;
23
24 static int cgroup_enable_systemd_services = CONFIG_ONDEMAND_YES;
25 static int cgroup_enable_systemd_services_detailed_memory = CONFIG_ONDEMAND_NO;
26 static int cgroup_used_memory_without_cache = CONFIG_ONDEMAND_YES;
27
28 static int cgroup_search_in_devices = 1;
29
30 static int cgroup_enable_new_cgroups_detected_at_runtime = 1;
31 static int cgroup_check_for_new_every = 10;
32 static int cgroup_update_every = 1;
33
34 static int cgroup_recheck_zero_blkio_every_iterations = 10;
35 static int cgroup_recheck_zero_mem_failcnt_every_iterations = 10;
36 static int cgroup_recheck_zero_mem_detailed_every_iterations = 10;
37
38 static char *cgroup_cpuacct_base = NULL;
39 static char *cgroup_blkio_base = NULL;
40 static char *cgroup_memory_base = NULL;
41 static char *cgroup_devices_base = NULL;
42
43 static int cgroup_root_count = 0;
44 static int cgroup_root_max = 500;
45 static int cgroup_max_depth = 0;
46
47 static SIMPLE_PATTERN *enabled_cgroup_patterns = NULL;
48 static SIMPLE_PATTERN *enabled_cgroup_paths = NULL;
49 static SIMPLE_PATTERN *enabled_cgroup_renames = NULL;
50 static SIMPLE_PATTERN *systemd_services_cgroups = NULL;
51
52 static char *cgroups_rename_script = PLUGINS_DIR "/cgroup-name.sh";
53
54 static uint32_t Read_hash = 0;
55 static uint32_t Write_hash = 0;
56 static uint32_t user_hash = 0;
57 static uint32_t system_hash = 0;
58
59 void read_cgroup_plugin_configuration() {
60     system_page_size = sysconf(_SC_PAGESIZE);
61
62     Read_hash = simple_hash("Read");
63     Write_hash = simple_hash("Write");
64     user_hash = simple_hash("user");
65     system_hash = simple_hash("system");
66
67     cgroup_update_every = (int)config_get_number("plugin:cgroups", "update every", rrd_update_every);
68     if(cgroup_update_every < rrd_update_every)
69         cgroup_update_every = rrd_update_every;
70
71     cgroup_check_for_new_every = (int)config_get_number("plugin:cgroups", "check for new cgroups every", cgroup_check_for_new_every * cgroup_update_every);
72     if(cgroup_check_for_new_every < cgroup_update_every)
73         cgroup_check_for_new_every = cgroup_update_every;
74
75     cgroup_enable_cpuacct_stat = config_get_boolean_ondemand("plugin:cgroups", "enable cpuacct stat (total CPU)", cgroup_enable_cpuacct_stat);
76     cgroup_enable_cpuacct_usage = config_get_boolean_ondemand("plugin:cgroups", "enable cpuacct usage (per core CPU)", cgroup_enable_cpuacct_usage);
77
78     cgroup_enable_memory = config_get_boolean_ondemand("plugin:cgroups", "enable memory (used mem including cache)", cgroup_enable_memory);
79     cgroup_enable_detailed_memory = config_get_boolean_ondemand("plugin:cgroups", "enable detailed memory", cgroup_enable_detailed_memory);
80     cgroup_enable_memory_failcnt = config_get_boolean_ondemand("plugin:cgroups", "enable memory limits fail count", cgroup_enable_memory_failcnt);
81     cgroup_enable_swap = config_get_boolean_ondemand("plugin:cgroups", "enable swap memory", cgroup_enable_swap);
82
83     cgroup_enable_blkio_io = config_get_boolean_ondemand("plugin:cgroups", "enable blkio bandwidth", cgroup_enable_blkio_io);
84     cgroup_enable_blkio_ops = config_get_boolean_ondemand("plugin:cgroups", "enable blkio operations", cgroup_enable_blkio_ops);
85     cgroup_enable_blkio_throttle_io = config_get_boolean_ondemand("plugin:cgroups", "enable blkio throttle bandwidth", cgroup_enable_blkio_throttle_io);
86     cgroup_enable_blkio_throttle_ops = config_get_boolean_ondemand("plugin:cgroups", "enable blkio throttle operations", cgroup_enable_blkio_throttle_ops);
87     cgroup_enable_blkio_queued_ops = config_get_boolean_ondemand("plugin:cgroups", "enable blkio queued operations", cgroup_enable_blkio_queued_ops);
88     cgroup_enable_blkio_merged_ops = config_get_boolean_ondemand("plugin:cgroups", "enable blkio merged operations", cgroup_enable_blkio_merged_ops);
89
90     cgroup_recheck_zero_blkio_every_iterations = (int)config_get_number("plugin:cgroups", "recheck zero blkio every iterations", cgroup_recheck_zero_blkio_every_iterations);
91     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);
92     cgroup_recheck_zero_mem_detailed_every_iterations = (int)config_get_number("plugin:cgroups", "recheck zero detailed memory every iterations", cgroup_recheck_zero_mem_detailed_every_iterations);
93
94     cgroup_enable_systemd_services = config_get_boolean("plugin:cgroups", "enable systemd services", cgroup_enable_systemd_services);
95     cgroup_enable_systemd_services_detailed_memory = config_get_boolean("plugin:cgroups", "enable systemd services detailed memory", cgroup_enable_systemd_services_detailed_memory);
96     cgroup_used_memory_without_cache = config_get_boolean("plugin:cgroups", "report used memory without cache", cgroup_used_memory_without_cache);
97
98     char filename[FILENAME_MAX + 1], *s;
99     struct mountinfo *mi, *root = mountinfo_read(0);
100
101     mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "cpuacct");
102     if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "cpuacct");
103     if(!mi) {
104         error("Cannot find cgroup cpuacct mountinfo. Assuming default: /sys/fs/cgroup/cpuacct");
105         s = "/sys/fs/cgroup/cpuacct";
106     }
107     else s = mi->mount_point;
108     snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
109     cgroup_cpuacct_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/cpuacct", filename);
110
111     mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "blkio");
112     if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "blkio");
113     if(!mi) {
114         error("Cannot find cgroup blkio mountinfo. Assuming default: /sys/fs/cgroup/blkio");
115         s = "/sys/fs/cgroup/blkio";
116     }
117     else s = mi->mount_point;
118     snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
119     cgroup_blkio_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/blkio", filename);
120
121     mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "memory");
122     if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "memory");
123     if(!mi) {
124         error("Cannot find cgroup memory mountinfo. Assuming default: /sys/fs/cgroup/memory");
125         s = "/sys/fs/cgroup/memory";
126     }
127     else s = mi->mount_point;
128     snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
129     cgroup_memory_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/memory", filename);
130
131     mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "devices");
132     if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "devices");
133     if(!mi) {
134         error("Cannot find cgroup devices mountinfo. Assuming default: /sys/fs/cgroup/devices");
135         s = "/sys/fs/cgroup/devices";
136     }
137     else s = mi->mount_point;
138     snprintfz(filename, FILENAME_MAX, "%s%s", global_host_prefix, s);
139     cgroup_devices_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/devices", filename);
140
141     cgroup_root_max = (int)config_get_number("plugin:cgroups", "max cgroups to allow", cgroup_root_max);
142     cgroup_max_depth = (int)config_get_number("plugin:cgroups", "max cgroups depth to monitor", cgroup_max_depth);
143
144     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);
145
146     enabled_cgroup_patterns = simple_pattern_create(
147             config_get("plugin:cgroups", "enable by default cgroups matching",
148                     " /system.slice/docker-*.scope "
149                     " !*.mount "
150                     " !*.partition "
151                     " !*.scope "
152                     " !*.service "
153                     " !*.slice "
154                     " !*.swap "
155                     " !*.user "
156                     " !/ "
157                     " !/docker "
158                     " !/libvirt "
159                     " !/lxc "
160                     " !/lxc/*/ns "         //  #1397
161                     " !/machine "
162                     " !/qemu "
163                     " !/system "
164                     " !/systemd "
165                     " !/user "
166                     " * "                  // enable anything else
167             ), SIMPLE_PATTERN_EXACT);
168
169     enabled_cgroup_paths = simple_pattern_create(
170             config_get("plugin:cgroups", "search for cgroups in subpaths matching",
171                     " !*-qemu "            //  #345
172                     " !/init.scope "
173                     " !/system "
174                     " !/systemd "
175                     " !/user "
176                     " !/user.slice "
177                     " * "
178             ), SIMPLE_PATTERN_EXACT);
179
180     cgroups_rename_script = config_get("plugin:cgroups", "script to get cgroup names", cgroups_rename_script);
181
182     enabled_cgroup_renames = simple_pattern_create(
183             config_get("plugin:cgroups", "run script to rename cgroups matching",
184                     " *docker* "
185                     " *lxc* "
186                     " !/ "
187                     " !*.mount "
188                     " !*.partition "
189                     " !*.scope "
190                     " !*.service "
191                     " !*.slice "
192                     " !*.swap "
193                     " !*.user "
194                     " * "
195             ), SIMPLE_PATTERN_EXACT);
196
197     if(cgroup_enable_systemd_services) {
198         systemd_services_cgroups = simple_pattern_create(
199                 config_get("plugin:cgroups", "cgroups to match as systemd services",
200                         " !/system.slice/*/*.service "
201                         " /system.slice/*.service "
202                 ), SIMPLE_PATTERN_EXACT);
203     }
204
205     mountinfo_free(root);
206 }
207
208 // ----------------------------------------------------------------------------
209 // cgroup objects
210
211 struct blkio {
212     int updated;
213     int enabled; // CONFIG_ONDEMAND_YES or CONFIG_ONDEMAND_ONDEMAND
214     int delay_counter;
215
216     char *filename;
217
218     unsigned long long Read;
219     unsigned long long Write;
220 /*
221     unsigned long long Sync;
222     unsigned long long Async;
223     unsigned long long Total;
224 */
225 };
226
227 // https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt
228 struct memory {
229     ARL_BASE *arl_base;
230     ARL_ENTRY *arl_dirty;
231     ARL_ENTRY *arl_swap;
232
233     int updated_detailed;
234     int updated_usage_in_bytes;
235     int updated_msw_usage_in_bytes;
236     int updated_failcnt;
237
238     int enabled_detailed;           // CONFIG_ONDEMAND_YES or CONFIG_ONDEMAND_ONDEMAND
239     int enabled_usage_in_bytes;     // CONFIG_ONDEMAND_YES or CONFIG_ONDEMAND_ONDEMAND
240     int enabled_msw_usage_in_bytes; // CONFIG_ONDEMAND_YES or CONFIG_ONDEMAND_ONDEMAND
241     int enabled_failcnt;            // CONFIG_ONDEMAND_YES or CONFIG_ONDEMAND_ONDEMAND
242
243     int delay_counter_detailed;
244     int delay_counter_failcnt;
245
246     char *filename_detailed;
247     char *filename_usage_in_bytes;
248     char *filename_msw_usage_in_bytes;
249     char *filename_failcnt;
250
251     int detailed_has_dirty;
252     int detailed_has_swap;
253
254     // detailed metrics
255     unsigned long long cache;
256     unsigned long long rss;
257     unsigned long long rss_huge;
258     unsigned long long mapped_file;
259     unsigned long long writeback;
260     unsigned long long dirty;
261     unsigned long long swap;
262     unsigned long long pgpgin;
263     unsigned long long pgpgout;
264     unsigned long long pgfault;
265     unsigned long long pgmajfault;
266 /*
267     unsigned long long inactive_anon;
268     unsigned long long active_anon;
269     unsigned long long inactive_file;
270     unsigned long long active_file;
271     unsigned long long unevictable;
272     unsigned long long hierarchical_memory_limit;
273     unsigned long long total_cache;
274     unsigned long long total_rss;
275     unsigned long long total_rss_huge;
276     unsigned long long total_mapped_file;
277     unsigned long long total_writeback;
278     unsigned long long total_dirty;
279     unsigned long long total_swap;
280     unsigned long long total_pgpgin;
281     unsigned long long total_pgpgout;
282     unsigned long long total_pgfault;
283     unsigned long long total_pgmajfault;
284     unsigned long long total_inactive_anon;
285     unsigned long long total_active_anon;
286     unsigned long long total_inactive_file;
287     unsigned long long total_active_file;
288     unsigned long long total_unevictable;
289 */
290
291     // single file metrics
292     unsigned long long usage_in_bytes;
293     unsigned long long msw_usage_in_bytes;
294     unsigned long long failcnt;
295 };
296
297 // https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt
298 struct cpuacct_stat {
299     int updated;
300     int enabled; // CONFIG_ONDEMAND_YES or CONFIG_ONDEMAND_ONDEMAND
301
302     char *filename;
303
304     unsigned long long user;
305     unsigned long long system;
306 };
307
308 // https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt
309 struct cpuacct_usage {
310     int updated;
311     int enabled; // CONFIG_ONDEMAND_YES or CONFIG_ONDEMAND_ONDEMAND
312
313     char *filename;
314
315     unsigned int cpus;
316     unsigned long long *cpu_percpu;
317 };
318
319 #define CGROUP_OPTIONS_DISABLED_DUPLICATE   0x00000001
320 #define CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE 0x00000002
321
322 struct cgroup {
323     uint32_t options;
324
325     char available;      // found in the filesystem
326     char enabled;        // enabled in the config
327
328     char *id;
329     uint32_t hash;
330
331     char *chart_id;
332     uint32_t hash_chart;
333
334     char *chart_title;
335
336     struct cpuacct_stat cpuacct_stat;
337     struct cpuacct_usage cpuacct_usage;
338
339     struct memory memory;
340
341     struct blkio io_service_bytes;              // bytes
342     struct blkio io_serviced;                   // operations
343
344     struct blkio throttle_io_service_bytes;     // bytes
345     struct blkio throttle_io_serviced;          // operations
346
347     struct blkio io_merged;                     // operations
348     struct blkio io_queued;                     // operations
349
350     // per cgroup charts
351     RRDSET *st_cpu;
352     RRDSET *st_cpu_per_core;
353     RRDSET *st_mem;
354     RRDSET *st_writeback;
355     RRDSET *st_mem_activity;
356     RRDSET *st_pgfaults;
357     RRDSET *st_mem_usage;
358     RRDSET *st_mem_failcnt;
359     RRDSET *st_io;
360     RRDSET *st_serviced_ops;
361     RRDSET *st_throttle_io;
362     RRDSET *st_throttle_serviced_ops;
363     RRDSET *st_queued_ops;
364     RRDSET *st_merged_ops;
365
366     // services
367     RRDDIM *rd_cpu;
368     RRDDIM *rd_mem_usage;
369     RRDDIM *rd_mem_failcnt;
370     RRDDIM *rd_swap_usage;
371
372     RRDDIM *rd_mem_detailed_cache;
373     RRDDIM *rd_mem_detailed_rss;
374     RRDDIM *rd_mem_detailed_mapped;
375     RRDDIM *rd_mem_detailed_writeback;
376     RRDDIM *rd_mem_detailed_pgpgin;
377     RRDDIM *rd_mem_detailed_pgpgout;
378     RRDDIM *rd_mem_detailed_pgfault;
379     RRDDIM *rd_mem_detailed_pgmajfault;
380
381     RRDDIM *rd_io_service_bytes_read;
382     RRDDIM *rd_io_serviced_read;
383     RRDDIM *rd_throttle_io_read;
384     RRDDIM *rd_throttle_io_serviced_read;
385     RRDDIM *rd_io_queued_read;
386     RRDDIM *rd_io_merged_read;
387
388     RRDDIM *rd_io_service_bytes_write;
389     RRDDIM *rd_io_serviced_write;
390     RRDDIM *rd_throttle_io_write;
391     RRDDIM *rd_throttle_io_serviced_write;
392     RRDDIM *rd_io_queued_write;
393     RRDDIM *rd_io_merged_write;
394
395     struct cgroup *next;
396
397 } *cgroup_root = NULL;
398
399 // ----------------------------------------------------------------------------
400 // read values from /sys
401
402 static inline void cgroup_read_cpuacct_stat(struct cpuacct_stat *cp) {
403     static procfile *ff = NULL;
404
405     if(likely(cp->filename)) {
406         ff = procfile_reopen(ff, cp->filename, NULL, PROCFILE_FLAG_DEFAULT);
407         if(unlikely(!ff)) {
408             cp->updated = 0;
409             return;
410         }
411
412         ff = procfile_readall(ff);
413         if(unlikely(!ff)) {
414             cp->updated = 0;
415             return;
416         }
417
418         unsigned long i, lines = procfile_lines(ff);
419
420         if(unlikely(lines < 1)) {
421             error("File '%s' should have 1+ lines.", cp->filename);
422             cp->updated = 0;
423             return;
424         }
425
426         for(i = 0; i < lines ; i++) {
427             char *s = procfile_lineword(ff, i, 0);
428             uint32_t hash = simple_hash(s);
429
430             if(unlikely(hash == user_hash && !strcmp(s, "user")))
431                 cp->user = str2ull(procfile_lineword(ff, i, 1));
432
433             else if(unlikely(hash == system_hash && !strcmp(s, "system")))
434                 cp->system = str2ull(procfile_lineword(ff, i, 1));
435         }
436
437         cp->updated = 1;
438
439         if(unlikely(cp->enabled == CONFIG_ONDEMAND_ONDEMAND && (cp->user || cp->system)))
440             cp->enabled = CONFIG_ONDEMAND_YES;
441     }
442 }
443
444 static inline void cgroup_read_cpuacct_usage(struct cpuacct_usage *ca) {
445     static procfile *ff = NULL;
446
447     if(likely(ca->filename)) {
448         ff = procfile_reopen(ff, ca->filename, NULL, PROCFILE_FLAG_DEFAULT);
449         if(unlikely(!ff)) {
450             ca->updated = 0;
451             return;
452         }
453
454         ff = procfile_readall(ff);
455         if(unlikely(!ff)) {
456             ca->updated = 0;
457             return;
458         }
459
460         if(unlikely(procfile_lines(ff) < 1)) {
461             error("File '%s' should have 1+ lines but has %zu.", ca->filename, procfile_lines(ff));
462             ca->updated = 0;
463             return;
464         }
465
466         unsigned long i = procfile_linewords(ff, 0);
467         if(unlikely(i == 0)) {
468             return;
469             ca->updated = 0;
470         }
471
472         // we may have 1 more CPU reported
473         while(i > 0) {
474             char *s = procfile_lineword(ff, 0, i - 1);
475             if(!*s) i--;
476             else break;
477         }
478
479         if(unlikely(i != ca->cpus)) {
480             freez(ca->cpu_percpu);
481             ca->cpu_percpu = mallocz(sizeof(unsigned long long) * i);
482             ca->cpus = (unsigned int)i;
483         }
484
485         unsigned long long total = 0;
486         for(i = 0; i < ca->cpus ;i++) {
487             unsigned long long n = str2ull(procfile_lineword(ff, 0, i));
488             ca->cpu_percpu[i] = n;
489             total += n;
490         }
491
492         ca->updated = 1;
493
494         if(unlikely(ca->enabled == CONFIG_ONDEMAND_ONDEMAND && total))
495             ca->enabled = CONFIG_ONDEMAND_YES;
496     }
497 }
498
499 static inline void cgroup_read_blkio(struct blkio *io) {
500     static procfile *ff = NULL;
501
502     if(unlikely(io->enabled == CONFIG_ONDEMAND_ONDEMAND && io->delay_counter > 0)) {
503         io->delay_counter--;
504         return;
505     }
506
507     if(likely(io->filename)) {
508         ff = procfile_reopen(ff, io->filename, NULL, PROCFILE_FLAG_DEFAULT);
509         if(unlikely(!ff)) {
510             io->updated = 0;
511             return;
512         }
513
514         ff = procfile_readall(ff);
515         if(unlikely(!ff)) {
516             io->updated = 0;
517             return;
518         }
519
520         unsigned long i, lines = procfile_lines(ff);
521
522         if(unlikely(lines < 1)) {
523             error("File '%s' should have 1+ lines.", io->filename);
524             io->updated = 0;
525             return;
526         }
527
528         io->Read = 0;
529         io->Write = 0;
530 /*
531         io->Sync = 0;
532         io->Async = 0;
533         io->Total = 0;
534 */
535
536         for(i = 0; i < lines ; i++) {
537             char *s = procfile_lineword(ff, i, 1);
538             uint32_t hash = simple_hash(s);
539
540             if(unlikely(hash == Read_hash && !strcmp(s, "Read")))
541                 io->Read += str2ull(procfile_lineword(ff, i, 2));
542
543             else if(unlikely(hash == Write_hash && !strcmp(s, "Write")))
544                 io->Write += str2ull(procfile_lineword(ff, i, 2));
545
546 /*
547             else if(unlikely(hash == Sync_hash && !strcmp(s, "Sync")))
548                 io->Sync += str2ull(procfile_lineword(ff, i, 2));
549
550             else if(unlikely(hash == Async_hash && !strcmp(s, "Async")))
551                 io->Async += str2ull(procfile_lineword(ff, i, 2));
552
553             else if(unlikely(hash == Total_hash && !strcmp(s, "Total")))
554                 io->Total += str2ull(procfile_lineword(ff, i, 2));
555 */
556         }
557
558         io->updated = 1;
559
560         if(unlikely(io->enabled == CONFIG_ONDEMAND_ONDEMAND)) {
561             if(unlikely(io->Read || io->Write))
562                 io->enabled = CONFIG_ONDEMAND_YES;
563             else
564                 io->delay_counter = cgroup_recheck_zero_blkio_every_iterations;
565         }
566     }
567 }
568
569 static inline void cgroup_read_memory(struct memory *mem) {
570     static procfile *ff = NULL;
571
572     // read detailed ram usage
573     if(likely(mem->filename_detailed)) {
574         if(unlikely(mem->enabled_detailed == CONFIG_ONDEMAND_ONDEMAND && mem->delay_counter_detailed > 0)) {
575             mem->delay_counter_detailed--;
576             goto memory_next;
577         }
578
579         ff = procfile_reopen(ff, mem->filename_detailed, NULL, PROCFILE_FLAG_DEFAULT);
580         if(unlikely(!ff)) {
581             mem->updated_detailed = 0;
582             goto memory_next;
583         }
584
585         ff = procfile_readall(ff);
586         if(unlikely(!ff)) {
587             mem->updated_detailed = 0;
588             goto memory_next;
589         }
590
591         unsigned long i, lines = procfile_lines(ff);
592
593         if(unlikely(lines < 1)) {
594             error("File '%s' should have 1+ lines.", mem->filename_detailed);
595             mem->updated_detailed = 0;
596             goto memory_next;
597         }
598
599         if(unlikely(!mem->arl_base)) {
600             mem->arl_base = arl_create("cgroup/memory", NULL, 60);
601
602             arl_expect(mem->arl_base, "cache", &mem->cache);
603             arl_expect(mem->arl_base, "rss", &mem->rss);
604             arl_expect(mem->arl_base, "rss_huge", &mem->rss_huge);
605             arl_expect(mem->arl_base, "mapped_file", &mem->mapped_file);
606             arl_expect(mem->arl_base, "writeback", &mem->writeback);
607             mem->arl_dirty = arl_expect(mem->arl_base, "dirty", &mem->dirty);
608             mem->arl_swap  = arl_expect(mem->arl_base, "swap", &mem->swap);
609             arl_expect(mem->arl_base, "pgpgin", &mem->pgpgin);
610             arl_expect(mem->arl_base, "pgpgout", &mem->pgpgout);
611             arl_expect(mem->arl_base, "pgfault", &mem->pgfault);
612             arl_expect(mem->arl_base, "pgmajfault", &mem->pgmajfault);
613         }
614
615         arl_begin(mem->arl_base);
616
617         for(i = 0; i < lines ; i++) {
618             if(arl_check(mem->arl_base,
619                     procfile_lineword(ff, i, 0),
620                     procfile_lineword(ff, i, 1))) break;
621         }
622
623         if(unlikely(mem->arl_dirty->flags & ARL_ENTRY_FLAG_FOUND))
624             mem->detailed_has_dirty = 1;
625
626         if(unlikely(mem->arl_swap->flags & ARL_ENTRY_FLAG_FOUND))
627             mem->detailed_has_swap = 1;
628
629         // 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);
630
631         mem->updated_detailed = 1;
632
633         if(unlikely(mem->enabled_detailed == CONFIG_ONDEMAND_ONDEMAND)) {
634             if(mem->cache || mem->dirty || mem->rss || mem->rss_huge || mem->mapped_file || mem->writeback || mem->swap || mem->pgpgin || mem->pgpgout || mem->pgfault || mem->pgmajfault)
635                 mem->enabled_detailed = CONFIG_ONDEMAND_YES;
636             else
637                 mem->delay_counter_detailed = cgroup_recheck_zero_mem_detailed_every_iterations;
638         }
639     }
640
641 memory_next:
642
643     // read usage_in_bytes
644     if(likely(mem->filename_usage_in_bytes)) {
645         mem->updated_usage_in_bytes = !read_single_number_file(mem->filename_usage_in_bytes, &mem->usage_in_bytes);
646         if(unlikely(mem->updated_usage_in_bytes && mem->enabled_usage_in_bytes == CONFIG_ONDEMAND_ONDEMAND && mem->usage_in_bytes))
647             mem->enabled_usage_in_bytes = CONFIG_ONDEMAND_YES;
648     }
649
650     // read msw_usage_in_bytes
651     if(likely(mem->filename_msw_usage_in_bytes)) {
652         mem->updated_msw_usage_in_bytes = !read_single_number_file(mem->filename_msw_usage_in_bytes, &mem->msw_usage_in_bytes);
653         if(unlikely(mem->updated_msw_usage_in_bytes && mem->enabled_msw_usage_in_bytes == CONFIG_ONDEMAND_ONDEMAND && mem->msw_usage_in_bytes))
654             mem->enabled_msw_usage_in_bytes = CONFIG_ONDEMAND_YES;
655     }
656
657     // read failcnt
658     if(likely(mem->filename_failcnt)) {
659         if(unlikely(mem->enabled_failcnt == CONFIG_ONDEMAND_ONDEMAND && mem->delay_counter_failcnt > 0)) {
660             mem->updated_failcnt = 0;
661             mem->delay_counter_failcnt--;
662         }
663         else {
664             mem->updated_failcnt = !read_single_number_file(mem->filename_failcnt, &mem->failcnt);
665             if(unlikely(mem->updated_failcnt && mem->enabled_failcnt == CONFIG_ONDEMAND_ONDEMAND)) {
666                 if(unlikely(!mem->failcnt))
667                     mem->delay_counter_failcnt = cgroup_recheck_zero_mem_failcnt_every_iterations;
668                 else
669                     mem->enabled_failcnt = CONFIG_ONDEMAND_YES;
670             }
671         }
672     }
673 }
674
675 static inline void cgroup_read(struct cgroup *cg) {
676     debug(D_CGROUP, "reading metrics for cgroups '%s'", cg->id);
677
678     cgroup_read_cpuacct_stat(&cg->cpuacct_stat);
679     cgroup_read_cpuacct_usage(&cg->cpuacct_usage);
680     cgroup_read_memory(&cg->memory);
681     cgroup_read_blkio(&cg->io_service_bytes);
682     cgroup_read_blkio(&cg->io_serviced);
683     cgroup_read_blkio(&cg->throttle_io_service_bytes);
684     cgroup_read_blkio(&cg->throttle_io_serviced);
685     cgroup_read_blkio(&cg->io_merged);
686     cgroup_read_blkio(&cg->io_queued);
687 }
688
689 static inline void read_all_cgroups(struct cgroup *root) {
690     debug(D_CGROUP, "reading metrics for all cgroups");
691
692     struct cgroup *cg;
693
694     for(cg = root; cg ; cg = cg->next)
695         if(cg->enabled && cg->available)
696             cgroup_read(cg);
697 }
698
699 // ----------------------------------------------------------------------------
700 // add/remove/find cgroup objects
701
702 #define CGROUP_CHARTID_LINE_MAX 1024
703
704 static inline char *cgroup_title_strdupz(const char *s) {
705     if(!s || !*s) s = "/";
706
707     if(*s == '/' && s[1] != '\0') s++;
708
709     char *r = strdupz(s);
710     netdata_fix_chart_name(r);
711
712     return r;
713 }
714
715 static inline char *cgroup_chart_id_strdupz(const char *s) {
716     if(!s || !*s) s = "/";
717
718     if(*s == '/' && s[1] != '\0') s++;
719
720     char *r = strdupz(s);
721     netdata_fix_chart_id(r);
722
723     return r;
724 }
725
726 static inline void cgroup_get_chart_name(struct cgroup *cg) {
727     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);
728
729     pid_t cgroup_pid;
730     char buffer[CGROUP_CHARTID_LINE_MAX + 1];
731
732     snprintfz(buffer, CGROUP_CHARTID_LINE_MAX, "exec %s '%s'", cgroups_rename_script, cg->chart_id);
733
734     debug(D_CGROUP, "executing command '%s' for cgroup '%s'", buffer, cg->id);
735     FILE *fp = mypopen(buffer, &cgroup_pid);
736     if(fp) {
737         // debug(D_CGROUP, "reading from command '%s' for cgroup '%s'", buffer, cg->id);
738         char *s = fgets(buffer, CGROUP_CHARTID_LINE_MAX, fp);
739         // debug(D_CGROUP, "closing command for cgroup '%s'", cg->id);
740         mypclose(fp, cgroup_pid);
741         // debug(D_CGROUP, "closed command for cgroup '%s'", cg->id);
742
743         if(s && *s && *s != '\n') {
744             debug(D_CGROUP, "cgroup '%s' should be renamed to '%s'", cg->id, s);
745
746             trim(s);
747
748             freez(cg->chart_title);
749             cg->chart_title = cgroup_title_strdupz(s);
750
751             freez(cg->chart_id);
752             cg->chart_id = cgroup_chart_id_strdupz(s);
753             cg->hash_chart = simple_hash(cg->chart_id);
754         }
755     }
756     else
757         error("CGROUP: Cannot popen(\"%s\", \"r\").", buffer);
758 }
759
760 static inline struct cgroup *cgroup_add(const char *id) {
761     if(!id || !*id) id = "/";
762     debug(D_CGROUP, "adding to list, cgroup with id '%s'", id);
763
764     if(cgroup_root_count >= cgroup_root_max) {
765         info("Maximum number of cgroups reached (%d). Not adding cgroup '%s'", cgroup_root_count, id);
766         return NULL;
767     }
768
769     int def = simple_pattern_matches(enabled_cgroup_patterns, id)?cgroup_enable_new_cgroups_detected_at_runtime:0;
770     struct cgroup *cg = callocz(1, sizeof(struct cgroup));
771
772     cg->id = strdupz(id);
773     cg->hash = simple_hash(cg->id);
774
775     cg->chart_title = cgroup_title_strdupz(id);
776
777     cg->chart_id = cgroup_chart_id_strdupz(id);
778     cg->hash_chart = simple_hash(cg->chart_id);
779
780     if(!cgroup_root)
781         cgroup_root = cg;
782     else {
783         // append it
784         struct cgroup *e;
785         for(e = cgroup_root; e->next ;e = e->next) ;
786         e->next = cg;
787     }
788
789     cgroup_root_count++;
790
791     // fix the chart_id and title by calling the external script
792     if(simple_pattern_matches(enabled_cgroup_renames, cg->id)) {
793
794         cgroup_get_chart_name(cg);
795
796         debug(D_CGROUP, "cgroup '%s' renamed to '%s' (title: '%s')", cg->id, cg->chart_id, cg->chart_title);
797     }
798     else
799         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);
800
801     int user_configurable = 1;
802
803     // check if this cgroup should be a systemd service
804     if(cgroup_enable_systemd_services) {
805         if(simple_pattern_matches(systemd_services_cgroups, cg->id) ||
806                 simple_pattern_matches(systemd_services_cgroups, cg->chart_id)) {
807             debug(D_CGROUP, "cgroup '%s' with chart id '%s' (title: '%s') matches systemd services cgroups", cg->id, cg->chart_id, cg->chart_title);
808
809             char buffer[CGROUP_CHARTID_LINE_MAX + 1];
810             cg->options |= CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE;
811
812             strncpy(buffer, cg->id, CGROUP_CHARTID_LINE_MAX);
813             char *s = buffer;
814
815             //freez(cg->chart_id);
816             //cg->chart_id = cgroup_chart_id_strdupz(s);
817             //cg->hash_chart = simple_hash(cg->chart_id);
818
819             // skip to the last slash
820             size_t len = strlen(s);
821             while(len--) if(unlikely(s[len] == '/')) break;
822             if(len) s = &s[len + 1];
823
824             // remove extension
825             len = strlen(s);
826             while(len--) if(unlikely(s[len] == '.')) break;
827             if(len) s[len] = '\0';
828
829             freez(cg->chart_title);
830             cg->chart_title = cgroup_title_strdupz(s);
831
832             cg->enabled = 1;
833             user_configurable = 0;
834
835             debug(D_CGROUP, "cgroup '%s' renamed to '%s' (title: '%s')", cg->id, cg->chart_id, cg->chart_title);
836         }
837         else
838             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);
839     }
840
841     if(user_configurable) {
842         // allow the user to enable/disable this individualy
843         char option[FILENAME_MAX + 1];
844         snprintfz(option, FILENAME_MAX, "enable cgroup %s", cg->chart_title);
845         cg->enabled = (char) config_get_boolean("plugin:cgroups", option, def);
846     }
847
848     // detect duplicate cgroups
849     if(cg->enabled) {
850         struct cgroup *t;
851         for (t = cgroup_root; t; t = t->next) {
852             if (t != cg && t->enabled && t->hash_chart == cg->hash_chart && !strcmp(t->chart_id, cg->chart_id)) {
853                 if (!strncmp(t->chart_id, "/system.slice/", 14) && !strncmp(cg->chart_id, "/init.scope/system.slice/", 25)) {
854                     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'.",
855                           cg->chart_id, t->id, cg->id, t->id);
856                     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'.",
857                           cg->chart_id, t->id, cg->id, t->id);
858                     t->enabled = 0;
859                     t->options |= CGROUP_OPTIONS_DISABLED_DUPLICATE;
860                 }
861                 else {
862                     error("Control group with chart id '%s' already exists with id '%s' and is enabled and available. Disabling cgroup with id '%s'.",
863                           cg->chart_id, t->id, cg->id);
864                     debug(D_CGROUP, "Control group with chart id '%s' already exists with id '%s' and is enabled and available. Disabling cgroup with id '%s'.",
865                           cg->chart_id, t->id, cg->id);
866                     cg->enabled = 0;
867                     cg->options |= CGROUP_OPTIONS_DISABLED_DUPLICATE;
868                 }
869
870                 break;
871             }
872         }
873     }
874
875     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");
876
877     return cg;
878 }
879
880 static inline void cgroup_free(struct cgroup *cg) {
881     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");
882
883     freez(cg->cpuacct_usage.cpu_percpu);
884
885     freez(cg->cpuacct_stat.filename);
886     freez(cg->cpuacct_usage.filename);
887
888     arl_free(cg->memory.arl_base);
889     freez(cg->memory.filename_detailed);
890     freez(cg->memory.filename_failcnt);
891     freez(cg->memory.filename_usage_in_bytes);
892     freez(cg->memory.filename_msw_usage_in_bytes);
893
894     freez(cg->io_service_bytes.filename);
895     freez(cg->io_serviced.filename);
896
897     freez(cg->throttle_io_service_bytes.filename);
898     freez(cg->throttle_io_serviced.filename);
899
900     freez(cg->io_merged.filename);
901     freez(cg->io_queued.filename);
902
903     freez(cg->id);
904     freez(cg->chart_id);
905     freez(cg->chart_title);
906
907     freez(cg);
908
909     cgroup_root_count--;
910 }
911
912 // find if a given cgroup exists
913 static inline struct cgroup *cgroup_find(const char *id) {
914     debug(D_CGROUP, "searching for cgroup '%s'", id);
915
916     uint32_t hash = simple_hash(id);
917
918     struct cgroup *cg;
919     for(cg = cgroup_root; cg ; cg = cg->next) {
920         if(hash == cg->hash && strcmp(id, cg->id) == 0)
921             break;
922     }
923
924     debug(D_CGROUP, "cgroup '%s' %s in memory", id, (cg)?"found":"not found");
925     return cg;
926 }
927
928 // ----------------------------------------------------------------------------
929 // detect running cgroups
930
931 // callback for find_file_in_subdirs()
932 static inline void found_subdir_in_dir(const char *dir) {
933     debug(D_CGROUP, "examining cgroup dir '%s'", dir);
934
935     struct cgroup *cg = cgroup_find(dir);
936     if(!cg) {
937         if(*dir && cgroup_max_depth > 0) {
938             int depth = 0;
939             const char *s;
940
941             for(s = dir; *s ;s++)
942                 if(unlikely(*s == '/'))
943                     depth++;
944
945             if(depth > cgroup_max_depth) {
946                 info("cgroup '%s' is too deep (%d, while max is %d)", dir, depth, cgroup_max_depth);
947                 return;
948             }
949         }
950         // debug(D_CGROUP, "will add dir '%s' as cgroup", dir);
951         cg = cgroup_add(dir);
952     }
953
954     if(cg) cg->available = 1;
955 }
956
957 static inline int find_dir_in_subdirs(const char *base, const char *this, void (*callback)(const char *)) {
958     if(!this) this = base;
959     debug(D_CGROUP, "searching for directories in '%s' (base '%s')", this?this:"", base);
960
961     size_t dirlen = strlen(this), baselen = strlen(base);
962
963     int ret = -1;
964     int enabled = -1;
965
966     const char *relative_path = &this[baselen];
967     if(!*relative_path) relative_path = "/";
968
969     DIR *dir = opendir(this);
970     if(!dir) {
971         error("Cannot read cgroups directory '%s'", base);
972         return ret;
973     }
974     ret = 1;
975
976     callback(relative_path);
977
978     struct dirent *de = NULL;
979     while((de = readdir(dir))) {
980         if(de->d_type == DT_DIR
981             && (
982                 (de->d_name[0] == '.' && de->d_name[1] == '\0')
983                 || (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
984                 ))
985             continue;
986
987         if(de->d_type == DT_DIR) {
988             if(enabled == -1) {
989                 const char *r = relative_path;
990                 if(*r == '\0') r = "/";
991
992                 // do not decent in directories we are not interested
993                 int def = simple_pattern_matches(enabled_cgroup_paths, r);
994
995                 // we check for this option here
996                 // so that the config will not have settings
997                 // for leaf directories
998                 char option[FILENAME_MAX + 1];
999                 snprintfz(option, FILENAME_MAX, "search for cgroups under %s", r);
1000                 option[FILENAME_MAX] = '\0';
1001                 enabled = config_get_boolean("plugin:cgroups", option, def);
1002             }
1003
1004             if(enabled) {
1005                 char *s = mallocz(dirlen + strlen(de->d_name) + 2);
1006                 strcpy(s, this);
1007                 strcat(s, "/");
1008                 strcat(s, de->d_name);
1009                 int ret2 = find_dir_in_subdirs(base, s, callback);
1010                 if(ret2 > 0) ret += ret2;
1011                 freez(s);
1012             }
1013         }
1014     }
1015
1016     closedir(dir);
1017     return ret;
1018 }
1019
1020 static inline void mark_all_cgroups_as_not_available() {
1021     debug(D_CGROUP, "marking all cgroups as not available");
1022
1023     struct cgroup *cg;
1024
1025     // mark all as not available
1026     for(cg = cgroup_root; cg ; cg = cg->next) {
1027         cg->available = 0;
1028     }
1029 }
1030
1031 static inline void cleanup_all_cgroups() {
1032     struct cgroup *cg = cgroup_root, *last = NULL;
1033
1034     for(; cg ;) {
1035         if(!cg->available) {
1036             // enable the first duplicate cgroup
1037             {
1038                 struct cgroup *t;
1039                 for(t = cgroup_root; t ; t = t->next) {
1040                     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)) {
1041                         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);
1042                         t->enabled = 1;
1043                         t->options &= ~CGROUP_OPTIONS_DISABLED_DUPLICATE;
1044                         break;
1045                     }
1046                 }
1047             }
1048
1049             if(!last)
1050                 cgroup_root = cg->next;
1051             else
1052                 last->next = cg->next;
1053
1054             cgroup_free(cg);
1055
1056             if(!last)
1057                 cg = cgroup_root;
1058             else
1059                 cg = last->next;
1060         }
1061         else {
1062             last = cg;
1063             cg = cg->next;
1064         }
1065     }
1066 }
1067
1068 static inline void find_all_cgroups() {
1069     debug(D_CGROUP, "searching for cgroups");
1070
1071     mark_all_cgroups_as_not_available();
1072
1073     if(cgroup_enable_cpuacct_stat || cgroup_enable_cpuacct_usage) {
1074         if(find_dir_in_subdirs(cgroup_cpuacct_base, NULL, found_subdir_in_dir) == -1) {
1075             cgroup_enable_cpuacct_stat =
1076             cgroup_enable_cpuacct_usage = CONFIG_ONDEMAND_NO;
1077             error("disabled CGROUP cpu statistics.");
1078         }
1079     }
1080
1081     if(cgroup_enable_blkio_io || cgroup_enable_blkio_ops || cgroup_enable_blkio_throttle_io || cgroup_enable_blkio_throttle_ops || cgroup_enable_blkio_merged_ops || cgroup_enable_blkio_queued_ops) {
1082         if(find_dir_in_subdirs(cgroup_blkio_base, NULL, found_subdir_in_dir) == -1) {
1083             cgroup_enable_blkio_io =
1084             cgroup_enable_blkio_ops =
1085             cgroup_enable_blkio_throttle_io =
1086             cgroup_enable_blkio_throttle_ops =
1087             cgroup_enable_blkio_merged_ops =
1088             cgroup_enable_blkio_queued_ops = CONFIG_ONDEMAND_NO;
1089             error("disabled CGROUP blkio statistics.");
1090         }
1091     }
1092
1093     if(cgroup_enable_memory || cgroup_enable_detailed_memory || cgroup_enable_swap || cgroup_enable_memory_failcnt) {
1094         if(find_dir_in_subdirs(cgroup_memory_base, NULL, found_subdir_in_dir) == -1) {
1095             cgroup_enable_memory =
1096             cgroup_enable_detailed_memory =
1097             cgroup_enable_swap =
1098             cgroup_enable_memory_failcnt = CONFIG_ONDEMAND_NO;
1099             error("disabled CGROUP memory statistics.");
1100         }
1101     }
1102
1103     if(cgroup_search_in_devices) {
1104         if(find_dir_in_subdirs(cgroup_devices_base, NULL, found_subdir_in_dir) == -1) {
1105             cgroup_search_in_devices = 0;
1106             error("disabled CGROUP devices statistics.");
1107         }
1108     }
1109
1110     // remove any non-existing cgroups
1111     cleanup_all_cgroups();
1112
1113     struct cgroup *cg;
1114     struct stat buf;
1115     for(cg = cgroup_root; cg ; cg = cg->next) {
1116         // fprintf(stderr, " >>> CGROUP '%s' (%u - %s) with name '%s'\n", cg->id, cg->hash, cg->available?"available":"stopped", cg->name);
1117
1118         if(unlikely(!cg->available))
1119             continue;
1120
1121         debug(D_CGROUP, "checking paths for cgroup '%s'", cg->id);
1122
1123         // check for newly added cgroups
1124         // and update the filenames they read
1125         char filename[FILENAME_MAX + 1];
1126         if(unlikely(cgroup_enable_cpuacct_stat && !cg->cpuacct_stat.filename)) {
1127             snprintfz(filename, FILENAME_MAX, "%s%s/cpuacct.stat", cgroup_cpuacct_base, cg->id);
1128             if(likely(stat(filename, &buf) != -1)) {
1129                 cg->cpuacct_stat.filename = strdupz(filename);
1130                 cg->cpuacct_stat.enabled = cgroup_enable_cpuacct_stat;
1131                 debug(D_CGROUP, "cpuacct.stat filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_stat.filename);
1132             }
1133             else
1134                 debug(D_CGROUP, "cpuacct.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1135         }
1136
1137         if(unlikely(cgroup_enable_cpuacct_usage && !cg->cpuacct_usage.filename && !(cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE))) {
1138             snprintfz(filename, FILENAME_MAX, "%s%s/cpuacct.usage_percpu", cgroup_cpuacct_base, cg->id);
1139             if(likely(stat(filename, &buf) != -1)) {
1140                 cg->cpuacct_usage.filename = strdupz(filename);
1141                 cg->cpuacct_usage.enabled = cgroup_enable_cpuacct_usage;
1142                 debug(D_CGROUP, "cpuacct.usage_percpu filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_usage.filename);
1143             }
1144             else
1145                 debug(D_CGROUP, "cpuacct.usage_percpu file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1146         }
1147
1148         if(unlikely((cgroup_enable_detailed_memory || cgroup_used_memory_without_cache) && !cg->memory.filename_detailed && (cgroup_used_memory_without_cache || cgroup_enable_systemd_services_detailed_memory || !(cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE)))) {
1149             snprintfz(filename, FILENAME_MAX, "%s%s/memory.stat", cgroup_memory_base, cg->id);
1150             if(likely(stat(filename, &buf) != -1)) {
1151                 cg->memory.filename_detailed = strdupz(filename);
1152                 cg->memory.enabled_detailed = (cgroup_enable_detailed_memory == CONFIG_ONDEMAND_YES)?CONFIG_ONDEMAND_YES:CONFIG_ONDEMAND_ONDEMAND;
1153                 debug(D_CGROUP, "memory.stat filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_detailed);
1154             }
1155             else
1156                 debug(D_CGROUP, "memory.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1157         }
1158
1159         if(unlikely(cgroup_enable_memory && !cg->memory.filename_usage_in_bytes)) {
1160             snprintfz(filename, FILENAME_MAX, "%s%s/memory.usage_in_bytes", cgroup_memory_base, cg->id);
1161             if(likely(stat(filename, &buf) != -1)) {
1162                 cg->memory.filename_usage_in_bytes = strdupz(filename);
1163                 cg->memory.enabled_usage_in_bytes = cgroup_enable_memory;
1164                 debug(D_CGROUP, "memory.usage_in_bytes filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_usage_in_bytes);
1165             }
1166             else
1167                 debug(D_CGROUP, "memory.usage_in_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1168         }
1169
1170         if(unlikely(cgroup_enable_swap && !cg->memory.filename_msw_usage_in_bytes)) {
1171             snprintfz(filename, FILENAME_MAX, "%s%s/memory.msw_usage_in_bytes", cgroup_memory_base, cg->id);
1172             if(likely(stat(filename, &buf) != -1)) {
1173                 cg->memory.filename_msw_usage_in_bytes = strdupz(filename);
1174                 cg->memory.enabled_msw_usage_in_bytes = cgroup_enable_swap;
1175                 debug(D_CGROUP, "memory.msw_usage_in_bytes filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_msw_usage_in_bytes);
1176             }
1177             else
1178                 debug(D_CGROUP, "memory.msw_usage_in_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1179         }
1180
1181         if(unlikely(cgroup_enable_memory_failcnt && !cg->memory.filename_failcnt)) {
1182             snprintfz(filename, FILENAME_MAX, "%s%s/memory.failcnt", cgroup_memory_base, cg->id);
1183             if(likely(stat(filename, &buf) != -1)) {
1184                 cg->memory.filename_failcnt = strdupz(filename);
1185                 cg->memory.enabled_failcnt = cgroup_enable_memory_failcnt;
1186                 debug(D_CGROUP, "memory.failcnt filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_failcnt);
1187             }
1188             else
1189                 debug(D_CGROUP, "memory.failcnt file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1190         }
1191
1192         if(unlikely(cgroup_enable_blkio_io && !cg->io_service_bytes.filename)) {
1193             snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_service_bytes", cgroup_blkio_base, cg->id);
1194             if(likely(stat(filename, &buf) != -1)) {
1195                 cg->io_service_bytes.filename = strdupz(filename);
1196                 cg->io_service_bytes.enabled = cgroup_enable_blkio_io;
1197                 debug(D_CGROUP, "io_service_bytes filename for cgroup '%s': '%s'", cg->id, cg->io_service_bytes.filename);
1198             }
1199             else
1200                 debug(D_CGROUP, "io_service_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1201         }
1202
1203         if(unlikely(cgroup_enable_blkio_ops && !cg->io_serviced.filename)) {
1204             snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_serviced", cgroup_blkio_base, cg->id);
1205             if(likely(stat(filename, &buf) != -1)) {
1206                 cg->io_serviced.filename = strdupz(filename);
1207                 cg->io_serviced.enabled = cgroup_enable_blkio_ops;
1208                 debug(D_CGROUP, "io_serviced filename for cgroup '%s': '%s'", cg->id, cg->io_serviced.filename);
1209             }
1210             else
1211                 debug(D_CGROUP, "io_serviced file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1212         }
1213
1214         if(unlikely(cgroup_enable_blkio_throttle_io && !cg->throttle_io_service_bytes.filename)) {
1215             snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_service_bytes", cgroup_blkio_base, cg->id);
1216             if(likely(stat(filename, &buf) != -1)) {
1217                 cg->throttle_io_service_bytes.filename = strdupz(filename);
1218                 cg->throttle_io_service_bytes.enabled = cgroup_enable_blkio_throttle_io;
1219                 debug(D_CGROUP, "throttle_io_service_bytes filename for cgroup '%s': '%s'", cg->id, cg->throttle_io_service_bytes.filename);
1220             }
1221             else
1222                 debug(D_CGROUP, "throttle_io_service_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1223         }
1224
1225         if(unlikely(cgroup_enable_blkio_throttle_ops && !cg->throttle_io_serviced.filename)) {
1226             snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_serviced", cgroup_blkio_base, cg->id);
1227             if(likely(stat(filename, &buf) != -1)) {
1228                 cg->throttle_io_serviced.filename = strdupz(filename);
1229                 cg->throttle_io_serviced.enabled = cgroup_enable_blkio_throttle_ops;
1230                 debug(D_CGROUP, "throttle_io_serviced filename for cgroup '%s': '%s'", cg->id, cg->throttle_io_serviced.filename);
1231             }
1232             else
1233                 debug(D_CGROUP, "throttle_io_serviced file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1234         }
1235
1236         if(unlikely(cgroup_enable_blkio_merged_ops && !cg->io_merged.filename)) {
1237             snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_merged", cgroup_blkio_base, cg->id);
1238             if(likely(stat(filename, &buf) != -1)) {
1239                 cg->io_merged.filename = strdupz(filename);
1240                 cg->io_merged.enabled = cgroup_enable_blkio_merged_ops;
1241                 debug(D_CGROUP, "io_merged filename for cgroup '%s': '%s'", cg->id, cg->io_merged.filename);
1242             }
1243             else
1244                 debug(D_CGROUP, "io_merged file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1245         }
1246
1247         if(unlikely(cgroup_enable_blkio_queued_ops && !cg->io_queued.filename)) {
1248             snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_queued", cgroup_blkio_base, cg->id);
1249             if(likely(stat(filename, &buf) != -1)) {
1250                 cg->io_queued.filename = strdupz(filename);
1251                 cg->io_queued.enabled = cgroup_enable_blkio_queued_ops;
1252                 debug(D_CGROUP, "io_queued filename for cgroup '%s': '%s'", cg->id, cg->io_queued.filename);
1253             }
1254             else
1255                 debug(D_CGROUP, "io_queued file for cgroup '%s': '%s' does not exist.", cg->id, filename);
1256         }
1257     }
1258
1259     debug(D_CGROUP, "done searching for cgroups");
1260     return;
1261 }
1262
1263 // ----------------------------------------------------------------------------
1264 // generate charts
1265
1266 #define CHART_TITLE_MAX 300
1267
1268 void update_services_charts(int update_every,
1269         int do_cpu,
1270         int do_mem_usage,
1271         int do_mem_detailed,
1272         int do_mem_failcnt,
1273         int do_swap_usage,
1274         int do_io,
1275         int do_io_ops,
1276         int do_throttle_io,
1277         int do_throttle_ops,
1278         int do_queued_ops,
1279         int do_merged_ops
1280 ) {
1281     static RRDSET
1282         *st_cpu = NULL,
1283         *st_mem_usage = NULL,
1284         *st_mem_failcnt = NULL,
1285         *st_swap_usage = NULL,
1286
1287         *st_mem_detailed_cache = NULL,
1288         *st_mem_detailed_rss = NULL,
1289         *st_mem_detailed_mapped = NULL,
1290         *st_mem_detailed_writeback = NULL,
1291         *st_mem_detailed_pgfault = NULL,
1292         *st_mem_detailed_pgmajfault = NULL,
1293         *st_mem_detailed_pgpgin = NULL,
1294         *st_mem_detailed_pgpgout = NULL,
1295
1296         *st_io_read = NULL,
1297         *st_io_serviced_read = NULL,
1298         *st_throttle_io_read = NULL,
1299         *st_throttle_ops_read = NULL,
1300         *st_queued_ops_read = NULL,
1301         *st_merged_ops_read = NULL,
1302
1303         *st_io_write = NULL,
1304         *st_io_serviced_write = NULL,
1305         *st_throttle_io_write = NULL,
1306         *st_throttle_ops_write = NULL,
1307         *st_queued_ops_write = NULL,
1308         *st_merged_ops_write = NULL;
1309
1310     // create the charts
1311
1312     if(likely(do_cpu)) {
1313         if(unlikely(!st_cpu)) {
1314             char title[CHART_TITLE_MAX + 1];
1315
1316             st_cpu = rrdset_find_bytype("services", "cpu");
1317             if(likely(!st_cpu)) {
1318                 snprintfz(title, CHART_TITLE_MAX, "Systemd Services CPU utilization (%d%% = %d core%s)", (processors * 100), processors, (processors > 1) ? "s" : "");
1319                 st_cpu = rrdset_create("services", "cpu", NULL, "cpu", "services.cpu", title, "%", CHART_PRIORITY_SYSTEMD_SERVICES, update_every, RRDSET_TYPE_STACKED);
1320             }
1321         }
1322         else
1323             rrdset_next(st_cpu);
1324     }
1325
1326     if(likely(do_mem_usage)) {
1327         if(unlikely(!st_mem_usage)) {
1328             st_mem_usage = rrdset_find_bytype("services", "mem_usage");
1329             if(likely(!st_mem_usage))
1330                 st_mem_usage = rrdset_create("services", "mem_usage", NULL, "mem", "services.mem_usage", (cgroup_used_memory_without_cache)?"Systemd Services Used Memory without Cache":"Systemd Services Used Memory", "MB", CHART_PRIORITY_SYSTEMD_SERVICES + 10, update_every, RRDSET_TYPE_STACKED);
1331         }
1332         else
1333             rrdset_next(st_mem_usage);
1334     }
1335
1336     if(likely(do_mem_detailed)) {
1337         if(unlikely(!st_mem_detailed_rss)) {
1338             st_mem_detailed_rss = rrdset_find_bytype("services", "mem_rss");
1339             if(likely(!st_mem_detailed_rss))
1340                 st_mem_detailed_rss = rrdset_create("services", "mem_rss", NULL, "mem", "services.mem_rss", "Systemd Services RSS Memory", "MB", CHART_PRIORITY_SYSTEMD_SERVICES + 20, update_every, RRDSET_TYPE_STACKED);
1341         }
1342         else
1343             rrdset_next(st_mem_detailed_rss);
1344
1345         if(unlikely(!st_mem_detailed_mapped)) {
1346             st_mem_detailed_mapped = rrdset_find_bytype("services", "mem_mapped");
1347             if(likely(!st_mem_detailed_mapped))
1348                 st_mem_detailed_mapped = rrdset_create("services", "mem_mapped", NULL, "mem", "services.mem_mapped", "Systemd Services Mapped Memory", "MB", CHART_PRIORITY_SYSTEMD_SERVICES + 30, update_every, RRDSET_TYPE_STACKED);
1349         }
1350         else
1351             rrdset_next(st_mem_detailed_mapped);
1352
1353         if(unlikely(!st_mem_detailed_cache)) {
1354             st_mem_detailed_cache = rrdset_find_bytype("services", "mem_cache");
1355             if(likely(!st_mem_detailed_cache))
1356                 st_mem_detailed_cache = rrdset_create("services", "mem_cache", NULL, "mem", "services.mem_cache", "Systemd Services Cache Memory", "MB", CHART_PRIORITY_SYSTEMD_SERVICES + 40, update_every, RRDSET_TYPE_STACKED);
1357         }
1358         else
1359             rrdset_next(st_mem_detailed_cache);
1360
1361         if(unlikely(!st_mem_detailed_writeback)) {
1362             st_mem_detailed_writeback = rrdset_find_bytype("services", "mem_writeback");
1363             if(likely(!st_mem_detailed_writeback))
1364                 st_mem_detailed_writeback = rrdset_create("services", "mem_writeback", NULL, "mem", "services.mem_writeback", "Systemd Services Writeback Memory", "MB", CHART_PRIORITY_SYSTEMD_SERVICES + 50, update_every, RRDSET_TYPE_STACKED);
1365         }
1366         else
1367             rrdset_next(st_mem_detailed_writeback);
1368
1369         if(unlikely(!st_mem_detailed_pgfault)) {
1370             st_mem_detailed_pgfault = rrdset_find_bytype("services", "mem_pgfault");
1371             if(likely(!st_mem_detailed_pgfault))
1372                 st_mem_detailed_pgfault = rrdset_create("services", "mem_pgfault", NULL, "mem", "services.mem_pgfault", "Systemd Services Memory Minor Page Faults", "MB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 60, update_every, RRDSET_TYPE_STACKED);
1373         }
1374         else
1375             rrdset_next(st_mem_detailed_pgfault);
1376
1377         if(unlikely(!st_mem_detailed_pgmajfault)) {
1378             st_mem_detailed_pgmajfault = rrdset_find_bytype("services", "mem_pgmajfault");
1379             if(likely(!st_mem_detailed_pgmajfault))
1380                 st_mem_detailed_pgmajfault = rrdset_create("services", "mem_pgmajfault", NULL, "mem", "services.mem_pgmajfault", "Systemd Services Memory Major Page Faults", "MB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 70, update_every, RRDSET_TYPE_STACKED);
1381         }
1382         else
1383             rrdset_next(st_mem_detailed_pgmajfault);
1384
1385         if(unlikely(!st_mem_detailed_pgpgin)) {
1386             st_mem_detailed_pgpgin = rrdset_find_bytype("services", "mem_pgpgin");
1387             if(likely(!st_mem_detailed_pgpgin))
1388                 st_mem_detailed_pgpgin = rrdset_create("services", "mem_pgpgin", NULL, "mem", "services.mem_pgpgin", "Systemd Services Memory Charging Activity", "MB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 80, update_every, RRDSET_TYPE_STACKED);
1389         }
1390         else
1391             rrdset_next(st_mem_detailed_pgpgin);
1392
1393         if(unlikely(!st_mem_detailed_pgpgout)) {
1394             st_mem_detailed_pgpgout = rrdset_find_bytype("services", "mem_pgpgout");
1395             if(likely(!st_mem_detailed_pgpgout))
1396                 st_mem_detailed_pgpgout = rrdset_create("services", "mem_pgpgout", NULL, "mem", "services.mem_pgpgout", "Systemd Services Memory Uncharging Activity", "MB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 90, update_every, RRDSET_TYPE_STACKED);
1397         }
1398         else
1399             rrdset_next(st_mem_detailed_pgpgout);
1400     }
1401
1402     if(likely(do_mem_failcnt)) {
1403         if(unlikely(!st_mem_failcnt)) {
1404             st_mem_failcnt = rrdset_find_bytype("services", "mem_failcnt");
1405             if(likely(!st_mem_failcnt))
1406                 st_mem_failcnt = rrdset_create("services", "mem_failcnt", NULL, "mem", "services.mem_failcnt", "Systemd Services Memory Limit Failures", "MB", CHART_PRIORITY_SYSTEMD_SERVICES + 110, update_every, RRDSET_TYPE_STACKED);
1407         }
1408         else
1409             rrdset_next(st_mem_failcnt);
1410     }
1411
1412     if(likely(do_swap_usage)) {
1413         if(unlikely(!st_swap_usage)) {
1414             st_swap_usage = rrdset_find_bytype("services", "swap_usage");
1415             if(likely(!st_swap_usage))
1416                 st_swap_usage = rrdset_create("services", "swap_usage", NULL, "swap", "services.swap_usage", "Systemd Services Swap Memory Used", "MB", CHART_PRIORITY_SYSTEMD_SERVICES + 100, update_every, RRDSET_TYPE_STACKED);
1417         }
1418         else
1419             rrdset_next(st_swap_usage);
1420     }
1421
1422     if(likely(do_io)) {
1423         if(unlikely(!st_io_read)) {
1424             st_io_read = rrdset_find_bytype("services", "io_read");
1425             if(likely(!st_io_read))
1426                 st_io_read = rrdset_create("services", "io_read", NULL, "disk", "services.io_read", "Systemd Services Disk Read Bandwidth", "KB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 120, update_every, RRDSET_TYPE_STACKED);
1427         }
1428         else
1429             rrdset_next(st_io_read);
1430
1431         if(unlikely(!st_io_write)) {
1432             st_io_write = rrdset_find_bytype("services", "io_write");
1433             if(likely(!st_io_write))
1434                 st_io_write = rrdset_create("services", "io_write", NULL, "disk", "services.io_write", "Systemd Services Disk Write Bandwidth", "KB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 130, update_every, RRDSET_TYPE_STACKED);
1435         }
1436         else
1437             rrdset_next(st_io_write);
1438     }
1439
1440     if(likely(do_io_ops)) {
1441         if(unlikely(!st_io_serviced_read)) {
1442             st_io_serviced_read = rrdset_find_bytype("services", "io_ops_read");
1443             if(likely(!st_io_serviced_read))
1444                 st_io_serviced_read = rrdset_create("services", "io_ops_read", NULL, "disk", "services.io_ops_read", "Systemd Services Disk Read Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 140, update_every, RRDSET_TYPE_STACKED);
1445         }
1446         else
1447             rrdset_next(st_io_serviced_read);
1448
1449         if(unlikely(!st_io_serviced_write)) {
1450             st_io_serviced_write = rrdset_find_bytype("services", "io_ops_write");
1451             if(likely(!st_io_serviced_write))
1452                 st_io_serviced_write = rrdset_create("services", "io_ops_write", NULL, "disk", "services.io_ops_write", "Systemd Services Disk Write Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 150, update_every, RRDSET_TYPE_STACKED);
1453         }
1454         else
1455             rrdset_next(st_io_serviced_write);
1456     }
1457
1458     if(likely(do_throttle_io)) {
1459         if(unlikely(!st_throttle_io_read)) {
1460             st_throttle_io_read = rrdset_find_bytype("services", "throttle_io_read");
1461             if(likely(!st_throttle_io_read))
1462                 st_throttle_io_read = rrdset_create("services", "throttle_io_read", NULL, "disk", "services.throttle_io_read", "Systemd Services Throttle Disk Read Bandwidth", "KB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 160, update_every, RRDSET_TYPE_STACKED);
1463         }
1464         else
1465             rrdset_next(st_throttle_io_read);
1466
1467         if(unlikely(!st_throttle_io_write)) {
1468             st_throttle_io_write = rrdset_find_bytype("services", "throttle_io_write");
1469             if(likely(!st_throttle_io_write))
1470                 st_throttle_io_write = rrdset_create("services", "throttle_io_write", NULL, "disk", "services.throttle_io_write", "Systemd Services Throttle Disk Write Bandwidth", "KB/s", CHART_PRIORITY_SYSTEMD_SERVICES + 170, update_every, RRDSET_TYPE_STACKED);
1471         }
1472         else
1473             rrdset_next(st_throttle_io_write);
1474     }
1475
1476     if(likely(do_throttle_ops)) {
1477         if(unlikely(!st_throttle_ops_read)) {
1478             st_throttle_ops_read = rrdset_find_bytype("services", "throttle_io_ops_read");
1479             if(likely(!st_throttle_ops_read))
1480                 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", CHART_PRIORITY_SYSTEMD_SERVICES + 180, update_every, RRDSET_TYPE_STACKED);
1481         }
1482         else
1483             rrdset_next(st_throttle_ops_read);
1484
1485         if(unlikely(!st_throttle_ops_write)) {
1486             st_throttle_ops_write = rrdset_find_bytype("services", "throttle_io_ops_write");
1487             if(likely(!st_throttle_ops_write))
1488                 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", CHART_PRIORITY_SYSTEMD_SERVICES + 190, update_every, RRDSET_TYPE_STACKED);
1489         }
1490         else
1491             rrdset_next(st_throttle_ops_write);
1492     }
1493
1494     if(likely(do_queued_ops)) {
1495         if(unlikely(!st_queued_ops_read)) {
1496             st_queued_ops_read = rrdset_find_bytype("services", "queued_io_ops_read");
1497             if(likely(!st_queued_ops_read))
1498                 st_queued_ops_read = rrdset_create("services", "queued_io_ops_read", NULL, "disk", "services.queued_io_ops_read", "Systemd Services Queued Disk Read Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 200, update_every, RRDSET_TYPE_STACKED);
1499         }
1500         else
1501             rrdset_next(st_queued_ops_read);
1502
1503         if(unlikely(!st_queued_ops_write)) {
1504             st_queued_ops_write = rrdset_find_bytype("services", "queued_io_ops_write");
1505             if(likely(!st_queued_ops_write))
1506                 st_queued_ops_write = rrdset_create("services", "queued_io_ops_write", NULL, "disk", "services.queued_io_ops_write", "Systemd Services Queued Disk Write Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 210, update_every, RRDSET_TYPE_STACKED);
1507         }
1508         else
1509             rrdset_next(st_queued_ops_write);
1510     }
1511
1512     if(likely(do_merged_ops)) {
1513         if(unlikely(!st_merged_ops_read)) {
1514             st_merged_ops_read = rrdset_find_bytype("services", "merged_io_ops_read");
1515             if(likely(!st_merged_ops_read))
1516                 st_merged_ops_read = rrdset_create("services", "merged_io_ops_read", NULL, "disk", "services.merged_io_ops_read", "Systemd Services Merged Disk Read Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 220, update_every, RRDSET_TYPE_STACKED);
1517         }
1518         else
1519             rrdset_next(st_merged_ops_read);
1520
1521         if(unlikely(!st_merged_ops_write)) {
1522             st_merged_ops_write = rrdset_find_bytype("services", "merged_io_ops_write");
1523             if(likely(!st_merged_ops_write))
1524                 st_merged_ops_write = rrdset_create("services", "merged_io_ops_write", NULL, "disk", "services.merged_io_ops_write", "Systemd Services Merged Disk Write Operations", "operations/s", CHART_PRIORITY_SYSTEMD_SERVICES + 230, update_every, RRDSET_TYPE_STACKED);
1525         }
1526         else
1527             rrdset_next(st_merged_ops_write);
1528     }
1529
1530     // update the values
1531     struct cgroup *cg;
1532     for(cg = cgroup_root; cg ; cg = cg->next) {
1533         if(unlikely(!cg->available || !cg->enabled || !(cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE)))
1534             continue;
1535
1536         if(likely(do_cpu && cg->cpuacct_stat.updated)) {
1537             if(unlikely(!cg->rd_cpu))
1538                 cg->rd_cpu = rrddim_add(st_cpu, cg->chart_id, cg->chart_title, 100, hz, RRDDIM_INCREMENTAL);
1539
1540             rrddim_set_by_pointer(st_cpu, cg->rd_cpu, cg->cpuacct_stat.user + cg->cpuacct_stat.system);
1541         }
1542
1543         if(likely(do_mem_usage && cg->memory.updated_usage_in_bytes)) {
1544             if(unlikely(!cg->rd_mem_usage))
1545                 cg->rd_mem_usage = rrddim_add(st_mem_usage, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1546
1547             rrddim_set_by_pointer(st_mem_usage, cg->rd_mem_usage, cg->memory.usage_in_bytes - ((cgroup_used_memory_without_cache)?cg->memory.cache:0));
1548         }
1549
1550         if(likely(do_mem_detailed && cg->memory.updated_detailed)) {
1551             if(unlikely(!cg->rd_mem_detailed_rss))
1552                 cg->rd_mem_detailed_rss = rrddim_add(st_mem_detailed_rss, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1553             rrddim_set_by_pointer(st_mem_detailed_rss, cg->rd_mem_detailed_rss, cg->memory.rss + cg->memory.rss_huge);
1554
1555             if(unlikely(!cg->rd_mem_detailed_mapped))
1556                 cg->rd_mem_detailed_mapped = rrddim_add(st_mem_detailed_mapped, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1557             rrddim_set_by_pointer(st_mem_detailed_mapped, cg->rd_mem_detailed_mapped, cg->memory.mapped_file);
1558
1559             if(unlikely(!cg->rd_mem_detailed_cache))
1560                 cg->rd_mem_detailed_cache = rrddim_add(st_mem_detailed_cache, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1561             rrddim_set_by_pointer(st_mem_detailed_cache, cg->rd_mem_detailed_cache, cg->memory.cache);
1562
1563             if(unlikely(!cg->rd_mem_detailed_writeback))
1564                 cg->rd_mem_detailed_writeback = rrddim_add(st_mem_detailed_writeback, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1565             rrddim_set_by_pointer(st_mem_detailed_writeback, cg->rd_mem_detailed_writeback, cg->memory.writeback);
1566
1567             if(unlikely(!cg->rd_mem_detailed_pgfault))
1568                 cg->rd_mem_detailed_pgfault = rrddim_add(st_mem_detailed_pgfault, cg->chart_id, cg->chart_title, system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
1569             rrddim_set_by_pointer(st_mem_detailed_pgfault, cg->rd_mem_detailed_pgfault, cg->memory.pgfault);
1570
1571             if(unlikely(!cg->rd_mem_detailed_pgmajfault))
1572                 cg->rd_mem_detailed_pgmajfault = rrddim_add(st_mem_detailed_pgmajfault, cg->chart_id, cg->chart_title, system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
1573             rrddim_set_by_pointer(st_mem_detailed_pgmajfault, cg->rd_mem_detailed_pgmajfault, cg->memory.pgmajfault);
1574
1575             if(unlikely(!cg->rd_mem_detailed_pgpgin))
1576                 cg->rd_mem_detailed_pgpgin = rrddim_add(st_mem_detailed_pgpgin, cg->chart_id, cg->chart_title, system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
1577             rrddim_set_by_pointer(st_mem_detailed_pgpgin, cg->rd_mem_detailed_pgpgin, cg->memory.pgpgin);
1578
1579             if(unlikely(!cg->rd_mem_detailed_pgpgout))
1580                 cg->rd_mem_detailed_pgpgout = rrddim_add(st_mem_detailed_pgpgout, cg->chart_id, cg->chart_title, system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
1581             rrddim_set_by_pointer(st_mem_detailed_pgpgout, cg->rd_mem_detailed_pgpgout, cg->memory.pgpgout);
1582         }
1583
1584         if(likely(do_mem_failcnt && cg->memory.updated_failcnt)) {
1585             if(unlikely(!cg->rd_mem_failcnt))
1586                 cg->rd_mem_failcnt = rrddim_add(st_mem_failcnt, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
1587
1588             rrddim_set_by_pointer(st_mem_failcnt, cg->rd_mem_failcnt, cg->memory.failcnt);
1589         }
1590
1591         if(likely(do_swap_usage && cg->memory.updated_msw_usage_in_bytes)) {
1592             if(unlikely(!cg->rd_swap_usage))
1593                 cg->rd_swap_usage = rrddim_add(st_swap_usage, cg->chart_id, cg->chart_title, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1594
1595             rrddim_set_by_pointer(st_swap_usage, cg->rd_swap_usage, cg->memory.msw_usage_in_bytes);
1596         }
1597
1598         if(likely(do_io && cg->io_service_bytes.updated)) {
1599             if(unlikely(!cg->rd_io_service_bytes_read))
1600                 cg->rd_io_service_bytes_read = rrddim_add(st_io_read, cg->chart_id, cg->chart_title, 1, 1024, RRDDIM_INCREMENTAL);
1601
1602             rrddim_set_by_pointer(st_io_read, cg->rd_io_service_bytes_read, cg->io_service_bytes.Read);
1603
1604             if(unlikely(!cg->rd_io_service_bytes_write))
1605                 cg->rd_io_service_bytes_write = rrddim_add(st_io_write, cg->chart_id, cg->chart_title, 1, 1024, RRDDIM_INCREMENTAL);
1606
1607             rrddim_set_by_pointer(st_io_write, cg->rd_io_service_bytes_write, cg->io_service_bytes.Write);
1608         }
1609
1610         if(likely(do_io_ops && cg->io_serviced.updated)) {
1611             if(unlikely(!cg->rd_io_serviced_read))
1612                 cg->rd_io_serviced_read = rrddim_add(st_io_serviced_read, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
1613
1614             rrddim_set_by_pointer(st_io_serviced_read, cg->rd_io_serviced_read, cg->io_serviced.Read);
1615
1616             if(unlikely(!cg->rd_io_serviced_write))
1617                 cg->rd_io_serviced_write = rrddim_add(st_io_serviced_write, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
1618
1619             rrddim_set_by_pointer(st_io_serviced_write, cg->rd_io_serviced_write, cg->io_serviced.Write);
1620         }
1621
1622         if(likely(do_throttle_io && cg->throttle_io_service_bytes.updated)) {
1623             if(unlikely(!cg->rd_throttle_io_read))
1624                 cg->rd_throttle_io_read = rrddim_add(st_throttle_io_read, cg->chart_id, cg->chart_title, 1, 1024, RRDDIM_INCREMENTAL);
1625
1626             rrddim_set_by_pointer(st_throttle_io_read, cg->rd_throttle_io_read, cg->throttle_io_service_bytes.Read);
1627
1628             if(unlikely(!cg->rd_throttle_io_write))
1629                 cg->rd_throttle_io_write = rrddim_add(st_throttle_io_write, cg->chart_id, cg->chart_title, 1, 1024, RRDDIM_INCREMENTAL);
1630
1631             rrddim_set_by_pointer(st_throttle_io_write, cg->rd_throttle_io_write, cg->throttle_io_service_bytes.Write);
1632         }
1633
1634         if(likely(do_throttle_ops && cg->throttle_io_serviced.updated)) {
1635             if(unlikely(!cg->rd_throttle_io_serviced_read))
1636                 cg->rd_throttle_io_serviced_read = rrddim_add(st_throttle_ops_read, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
1637
1638             rrddim_set_by_pointer(st_throttle_ops_read, cg->rd_throttle_io_serviced_read, cg->throttle_io_serviced.Read);
1639
1640             if(unlikely(!cg->rd_throttle_io_serviced_write))
1641                 cg->rd_throttle_io_serviced_write = rrddim_add(st_throttle_ops_write, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
1642
1643             rrddim_set_by_pointer(st_throttle_ops_write, cg->rd_throttle_io_serviced_write, cg->throttle_io_serviced.Write);
1644         }
1645
1646         if(likely(do_queued_ops && cg->io_queued.updated)) {
1647             if(unlikely(!cg->rd_io_queued_read))
1648                 cg->rd_io_queued_read = rrddim_add(st_queued_ops_read, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
1649
1650             rrddim_set_by_pointer(st_queued_ops_read, cg->rd_io_queued_read, cg->io_queued.Read);
1651
1652             if(unlikely(!cg->rd_io_queued_write))
1653                 cg->rd_io_queued_write = rrddim_add(st_queued_ops_write, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
1654
1655             rrddim_set_by_pointer(st_queued_ops_write, cg->rd_io_queued_write, cg->io_queued.Write);
1656         }
1657
1658         if(likely(do_merged_ops && cg->io_merged.updated)) {
1659             if(unlikely(!cg->rd_io_merged_read))
1660                 cg->rd_io_merged_read = rrddim_add(st_merged_ops_read, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
1661
1662             rrddim_set_by_pointer(st_merged_ops_read, cg->rd_io_merged_read, cg->io_merged.Read);
1663
1664             if(unlikely(!cg->rd_io_merged_write))
1665                 cg->rd_io_merged_write = rrddim_add(st_merged_ops_write, cg->chart_id, cg->chart_title, 1, 1, RRDDIM_INCREMENTAL);
1666
1667             rrddim_set_by_pointer(st_merged_ops_write, cg->rd_io_merged_write, cg->io_merged.Write);
1668         }
1669     }
1670
1671     // complete the iteration
1672     if(likely(do_cpu))
1673         rrdset_done(st_cpu);
1674
1675     if(likely(do_mem_usage))
1676         rrdset_done(st_mem_usage);
1677
1678     if(unlikely(do_mem_detailed)) {
1679         rrdset_done(st_mem_detailed_cache);
1680         rrdset_done(st_mem_detailed_rss);
1681         rrdset_done(st_mem_detailed_mapped);
1682         rrdset_done(st_mem_detailed_writeback);
1683         rrdset_done(st_mem_detailed_pgfault);
1684         rrdset_done(st_mem_detailed_pgmajfault);
1685         rrdset_done(st_mem_detailed_pgpgin);
1686         rrdset_done(st_mem_detailed_pgpgout);
1687     }
1688
1689     if(likely(do_mem_failcnt))
1690         rrdset_done(st_mem_failcnt);
1691
1692     if(likely(do_swap_usage))
1693         rrdset_done(st_swap_usage);
1694
1695     if(likely(do_io)) {
1696         rrdset_done(st_io_read);
1697         rrdset_done(st_io_write);
1698     }
1699
1700     if(likely(do_io_ops)) {
1701         rrdset_done(st_io_serviced_read);
1702         rrdset_done(st_io_serviced_write);
1703     }
1704
1705     if(likely(do_throttle_io)) {
1706         rrdset_done(st_throttle_io_read);
1707         rrdset_done(st_throttle_io_write);
1708     }
1709
1710     if(likely(do_throttle_ops)) {
1711         rrdset_done(st_throttle_ops_read);
1712         rrdset_done(st_throttle_ops_write);
1713     }
1714
1715     if(likely(do_queued_ops)) {
1716         rrdset_done(st_queued_ops_read);
1717         rrdset_done(st_queued_ops_write);
1718     }
1719
1720     if(likely(do_merged_ops)) {
1721         rrdset_done(st_merged_ops_read);
1722         rrdset_done(st_merged_ops_write);
1723     }
1724 }
1725
1726 static inline char *cgroup_chart_type(char *buffer, const char *id, size_t len) {
1727     if(buffer[0]) return buffer;
1728
1729     if(id[0] == '\0' || (id[0] == '/' && id[1] == '\0'))
1730         strncpy(buffer, "cgroup_root", len);
1731     else
1732         snprintfz(buffer, len, "cgroup_%s", id);
1733
1734     netdata_fix_chart_id(buffer);
1735     return buffer;
1736 }
1737
1738 void update_cgroup_charts(int update_every) {
1739     debug(D_CGROUP, "updating cgroups charts");
1740
1741     char type[RRD_ID_LENGTH_MAX + 1];
1742     char title[CHART_TITLE_MAX + 1];
1743
1744     int services_do_cpu = 0,
1745             services_do_mem_usage = 0,
1746             services_do_mem_detailed = 0,
1747             services_do_mem_failcnt = 0,
1748             services_do_swap_usage = 0,
1749             services_do_io = 0,
1750             services_do_io_ops = 0,
1751             services_do_throttle_io = 0,
1752             services_do_throttle_ops = 0,
1753             services_do_queued_ops = 0,
1754             services_do_merged_ops = 0;
1755
1756     struct cgroup *cg;
1757     for(cg = cgroup_root; cg ; cg = cg->next) {
1758         if(unlikely(!cg->available || !cg->enabled))
1759             continue;
1760
1761         if(likely(cgroup_enable_systemd_services && cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE)) {
1762             if(cg->cpuacct_stat.updated && cg->cpuacct_stat.enabled == CONFIG_ONDEMAND_YES) services_do_cpu++;
1763
1764             if(cgroup_enable_systemd_services_detailed_memory && cg->memory.updated_detailed && cg->memory.enabled_detailed) services_do_mem_detailed++;
1765             if(cg->memory.updated_usage_in_bytes && cg->memory.enabled_usage_in_bytes == CONFIG_ONDEMAND_YES) services_do_mem_usage++;
1766             if(cg->memory.updated_failcnt && cg->memory.enabled_failcnt == CONFIG_ONDEMAND_YES) services_do_mem_failcnt++;
1767             if(cg->memory.updated_msw_usage_in_bytes && cg->memory.enabled_msw_usage_in_bytes == CONFIG_ONDEMAND_YES) services_do_swap_usage++;
1768
1769             if(cg->io_service_bytes.updated && cg->io_service_bytes.enabled == CONFIG_ONDEMAND_YES) services_do_io++;
1770             if(cg->io_serviced.updated && cg->io_serviced.enabled == CONFIG_ONDEMAND_YES) services_do_io_ops++;
1771             if(cg->throttle_io_service_bytes.updated && cg->throttle_io_service_bytes.enabled == CONFIG_ONDEMAND_YES) services_do_throttle_io++;
1772             if(cg->throttle_io_serviced.updated && cg->throttle_io_serviced.enabled == CONFIG_ONDEMAND_YES) services_do_throttle_ops++;
1773             if(cg->io_queued.updated && cg->io_queued.enabled == CONFIG_ONDEMAND_YES) services_do_queued_ops++;
1774             if(cg->io_merged.updated && cg->io_merged.enabled == CONFIG_ONDEMAND_YES) services_do_merged_ops++;
1775             continue;
1776         }
1777
1778         type[0] = '\0';
1779
1780         if(likely(cg->cpuacct_stat.updated && cg->cpuacct_stat.enabled == CONFIG_ONDEMAND_YES)) {
1781             if(unlikely(!cg->st_cpu)) {
1782                 cg->st_cpu = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "cpu");
1783                 if(likely(!cg->st_cpu)) {
1784                     snprintfz(title, CHART_TITLE_MAX, "CPU Usage (%d%% = %d core%s) for cgroup %s", (processors * 100), processors, (processors > 1) ? "s" : "", cg->chart_title);
1785                     cg->st_cpu = rrdset_create(type, "cpu", NULL, "cpu", "cgroup.cpu", title, "%", CHART_PRIORITY_CONTAINERS, update_every, RRDSET_TYPE_STACKED);
1786                 }
1787                 rrddim_add(cg->st_cpu, "user", NULL, 100, hz, RRDDIM_INCREMENTAL);
1788                 rrddim_add(cg->st_cpu, "system", NULL, 100, hz, RRDDIM_INCREMENTAL);
1789             }
1790             else
1791                 rrdset_next(cg->st_cpu);
1792
1793             rrddim_set(cg->st_cpu, "user", cg->cpuacct_stat.user);
1794             rrddim_set(cg->st_cpu, "system", cg->cpuacct_stat.system);
1795             rrdset_done(cg->st_cpu);
1796         }
1797
1798         if(likely(cg->cpuacct_usage.updated && cg->cpuacct_usage.enabled == CONFIG_ONDEMAND_YES)) {
1799             char id[RRD_ID_LENGTH_MAX + 1];
1800             unsigned int i;
1801
1802             if(unlikely(!cg->st_cpu_per_core)) {
1803                 cg->st_cpu_per_core = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "cpu_per_core");
1804                 if(likely(!cg->st_cpu_per_core)) {
1805                     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);
1806                     cg->st_cpu_per_core = rrdset_create(type, "cpu_per_core", NULL, "cpu", "cgroup.cpu_per_core", title, "%", CHART_PRIORITY_CONTAINERS + 100, update_every, RRDSET_TYPE_STACKED);
1807                 }
1808                 for(i = 0; i < cg->cpuacct_usage.cpus; i++) {
1809                     snprintfz(id, CHART_TITLE_MAX, "cpu%u", i);
1810                     rrddim_add(cg->st_cpu_per_core, id, NULL, 100, 1000000000, RRDDIM_INCREMENTAL);
1811                 }
1812             }
1813             else
1814                 rrdset_next(cg->st_cpu_per_core);
1815
1816             for(i = 0; i < cg->cpuacct_usage.cpus ;i++) {
1817                 snprintfz(id, CHART_TITLE_MAX, "cpu%u", i);
1818                 rrddim_set(cg->st_cpu_per_core, id, cg->cpuacct_usage.cpu_percpu[i]);
1819             }
1820             rrdset_done(cg->st_cpu_per_core);
1821         }
1822
1823         if(likely(cg->memory.updated_detailed && cg->memory.enabled_detailed == CONFIG_ONDEMAND_YES)) {
1824             if(unlikely(!cg->st_mem)) {
1825                 cg->st_mem = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "mem");
1826                 if(likely(!cg->st_mem)) {
1827                     snprintfz(title, CHART_TITLE_MAX, "Memory Usage for cgroup %s", cg->chart_title);
1828                     cg->st_mem = rrdset_create(type, "mem", NULL, "mem", "cgroup.mem", title, "MB", CHART_PRIORITY_CONTAINERS + 210, update_every, RRDSET_TYPE_STACKED);
1829                 }
1830
1831                 rrddim_add(cg->st_mem, "cache", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1832                 rrddim_add(cg->st_mem, "rss", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1833                 if(cg->memory.detailed_has_swap)
1834                     rrddim_add(cg->st_mem, "swap", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1835                 rrddim_add(cg->st_mem, "rss_huge", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1836                 rrddim_add(cg->st_mem, "mapped_file", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1837             }
1838             else
1839                 rrdset_next(cg->st_mem);
1840
1841             rrddim_set(cg->st_mem, "cache", cg->memory.cache);
1842             rrddim_set(cg->st_mem, "rss", cg->memory.rss);
1843             if(cg->memory.detailed_has_swap)
1844                 rrddim_set(cg->st_mem, "swap", cg->memory.swap);
1845             rrddim_set(cg->st_mem, "rss_huge", cg->memory.rss_huge);
1846             rrddim_set(cg->st_mem, "mapped_file", cg->memory.mapped_file);
1847             rrdset_done(cg->st_mem);
1848
1849             if(unlikely(!cg->st_writeback)) {
1850                 cg->st_writeback = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "writeback");
1851                 if(likely(!cg->st_writeback)) {
1852                     snprintfz(title, CHART_TITLE_MAX, "Writeback Memory for cgroup %s", cg->chart_title);
1853                     cg->st_writeback = rrdset_create(type, "writeback", NULL, "mem", "cgroup.writeback", title, "MB", CHART_PRIORITY_CONTAINERS + 300, update_every, RRDSET_TYPE_AREA);
1854                 }
1855
1856                 if(cg->memory.detailed_has_dirty)
1857                     rrddim_add(cg->st_writeback, "dirty", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1858                 rrddim_add(cg->st_writeback, "writeback", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1859             }
1860             else
1861                 rrdset_next(cg->st_writeback);
1862
1863             if(cg->memory.detailed_has_dirty)
1864                 rrddim_set(cg->st_writeback, "dirty", cg->memory.dirty);
1865             rrddim_set(cg->st_writeback, "writeback", cg->memory.writeback);
1866             rrdset_done(cg->st_writeback);
1867
1868             if(unlikely(!cg->st_mem_activity)) {
1869                 cg->st_mem_activity = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "mem_activity");
1870                 if(likely(!cg->st_mem_activity)) {
1871                     snprintfz(title, CHART_TITLE_MAX, "Memory Activity for cgroup %s", cg->chart_title);
1872                     cg->st_mem_activity = rrdset_create(type, "mem_activity", NULL, "mem", "cgroup.mem_activity", title, "MB/s", CHART_PRIORITY_CONTAINERS + 400, update_every, RRDSET_TYPE_LINE);
1873                 }
1874                 rrddim_add(cg->st_mem_activity, "pgpgin", "in", system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
1875                 rrddim_add(cg->st_mem_activity, "pgpgout", "out", -system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
1876             }
1877             else
1878                 rrdset_next(cg->st_mem_activity);
1879
1880             rrddim_set(cg->st_mem_activity, "pgpgin", cg->memory.pgpgin);
1881             rrddim_set(cg->st_mem_activity, "pgpgout", cg->memory.pgpgout);
1882             rrdset_done(cg->st_mem_activity);
1883
1884             if(unlikely(!cg->st_pgfaults)) {
1885                 cg->st_pgfaults = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "pgfaults");
1886                 if(likely(!cg->st_pgfaults)) {
1887                     snprintfz(title, CHART_TITLE_MAX, "Memory Page Faults for cgroup %s", cg->chart_title);
1888                     cg->st_pgfaults = rrdset_create(type, "pgfaults", NULL, "mem", "cgroup.pgfaults", title, "MB/s", CHART_PRIORITY_CONTAINERS + 500, update_every, RRDSET_TYPE_LINE);
1889                 }
1890                 rrddim_add(cg->st_pgfaults, "pgfault", NULL, system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
1891                 rrddim_add(cg->st_pgfaults, "pgmajfault", "swap", -system_page_size, 1024 * 1024, RRDDIM_INCREMENTAL);
1892             }
1893             else
1894                 rrdset_next(cg->st_pgfaults);
1895
1896             rrddim_set(cg->st_pgfaults, "pgfault", cg->memory.pgfault);
1897             rrddim_set(cg->st_pgfaults, "pgmajfault", cg->memory.pgmajfault);
1898             rrdset_done(cg->st_pgfaults);
1899         }
1900
1901         if(likely(cg->memory.updated_usage_in_bytes && cg->memory.enabled_usage_in_bytes == CONFIG_ONDEMAND_YES)) {
1902             if(unlikely(!cg->st_mem_usage)) {
1903                 cg->st_mem_usage = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "mem_usage");
1904                 if(likely(!cg->st_mem_usage)) {
1905                     snprintfz(title, CHART_TITLE_MAX, "Used Memory %sfor cgroup %s", (cgroup_used_memory_without_cache && cg->memory.updated_detailed)?"without Cache ":"", cg->chart_title);
1906                     cg->st_mem_usage = rrdset_create(type, "mem_usage", NULL, "mem", "cgroup.mem_usage", title, "MB", CHART_PRIORITY_CONTAINERS + 200, update_every, RRDSET_TYPE_STACKED);
1907                 }
1908                 rrddim_add(cg->st_mem_usage, "ram", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1909                 rrddim_add(cg->st_mem_usage, "swap", NULL, 1, 1024 * 1024, RRDDIM_ABSOLUTE);
1910             }
1911             else
1912                 rrdset_next(cg->st_mem_usage);
1913
1914             rrddim_set(cg->st_mem_usage, "ram", cg->memory.usage_in_bytes - ((cgroup_used_memory_without_cache)?cg->memory.cache:0));
1915             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);
1916             rrdset_done(cg->st_mem_usage);
1917         }
1918
1919         if(likely(cg->memory.updated_failcnt && cg->memory.enabled_failcnt == CONFIG_ONDEMAND_YES)) {
1920             if(unlikely(!cg->st_mem_failcnt)) {
1921                 cg->st_mem_failcnt = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "mem_failcnt");
1922                 if(likely(!cg->st_mem_failcnt)) {
1923                     snprintfz(title, CHART_TITLE_MAX, "Memory Limit Failures for cgroup %s", cg->chart_title);
1924                     cg->st_mem_failcnt = rrdset_create(type, "mem_failcnt", NULL, "mem", "cgroup.mem_failcnt", title, "count", CHART_PRIORITY_CONTAINERS + 250, update_every, RRDSET_TYPE_LINE);
1925                 }
1926                 rrddim_add(cg->st_mem_failcnt, "failures", NULL, 1, 1, RRDDIM_INCREMENTAL);
1927             }
1928             else
1929                 rrdset_next(cg->st_mem_failcnt);
1930
1931             rrddim_set(cg->st_mem_failcnt, "failures", cg->memory.failcnt);
1932             rrdset_done(cg->st_mem_failcnt);
1933         }
1934
1935         if(likely(cg->io_service_bytes.updated && cg->io_service_bytes.enabled == CONFIG_ONDEMAND_YES)) {
1936             if(unlikely(!cg->st_io)) {
1937                 cg->st_io = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "io");
1938                 if(likely(!cg->st_io)) {
1939                     snprintfz(title, CHART_TITLE_MAX, "I/O Bandwidth (all disks) for cgroup %s", cg->chart_title);
1940                     cg->st_io = rrdset_create(type, "io", NULL, "disk", "cgroup.io", title, "KB/s", CHART_PRIORITY_CONTAINERS + 1200, update_every, RRDSET_TYPE_AREA);
1941                 }
1942                 rrddim_add(cg->st_io, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
1943                 rrddim_add(cg->st_io, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
1944             }
1945             else
1946                 rrdset_next(cg->st_io);
1947
1948             rrddim_set(cg->st_io, "read", cg->io_service_bytes.Read);
1949             rrddim_set(cg->st_io, "write", cg->io_service_bytes.Write);
1950             rrdset_done(cg->st_io);
1951         }
1952
1953         if(likely(cg->io_serviced.updated && cg->io_serviced.enabled == CONFIG_ONDEMAND_YES)) {
1954             if(unlikely(!cg->st_serviced_ops)) {
1955                 cg->st_serviced_ops = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "serviced_ops");
1956                 if(likely(!cg->st_serviced_ops)) {
1957                     snprintfz(title, CHART_TITLE_MAX, "Serviced I/O Operations (all disks) for cgroup %s", cg->chart_title);
1958                     cg->st_serviced_ops = rrdset_create(type, "serviced_ops", NULL, "disk", "cgroup.serviced_ops", title, "operations/s", CHART_PRIORITY_CONTAINERS + 1200, update_every, RRDSET_TYPE_LINE);
1959                 }
1960                 rrddim_add(cg->st_serviced_ops, "read", NULL, 1, 1, RRDDIM_INCREMENTAL);
1961                 rrddim_add(cg->st_serviced_ops, "write", NULL, -1, 1, RRDDIM_INCREMENTAL);
1962             }
1963             else
1964                 rrdset_next(cg->st_serviced_ops);
1965
1966             rrddim_set(cg->st_serviced_ops, "read", cg->io_serviced.Read);
1967             rrddim_set(cg->st_serviced_ops, "write", cg->io_serviced.Write);
1968             rrdset_done(cg->st_serviced_ops);
1969         }
1970
1971         if(likely(cg->throttle_io_service_bytes.updated && cg->throttle_io_service_bytes.enabled == CONFIG_ONDEMAND_YES)) {
1972             if(unlikely(!cg->st_throttle_io)) {
1973                 cg->st_throttle_io = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "throttle_io");
1974                 if(likely(!cg->st_throttle_io)) {
1975                     snprintfz(title, CHART_TITLE_MAX, "Throttle I/O Bandwidth (all disks) for cgroup %s", cg->chart_title);
1976                     cg->st_throttle_io = rrdset_create(type, "throttle_io", NULL, "disk", "cgroup.throttle_io", title, "KB/s", CHART_PRIORITY_CONTAINERS + 1200, update_every, RRDSET_TYPE_AREA);
1977                 }
1978                 rrddim_add(cg->st_throttle_io, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
1979                 rrddim_add(cg->st_throttle_io, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
1980             }
1981             else
1982                 rrdset_next(cg->st_throttle_io);
1983
1984             rrddim_set(cg->st_throttle_io, "read", cg->throttle_io_service_bytes.Read);
1985             rrddim_set(cg->st_throttle_io, "write", cg->throttle_io_service_bytes.Write);
1986             rrdset_done(cg->st_throttle_io);
1987         }
1988
1989         if(likely(cg->throttle_io_serviced.updated && cg->throttle_io_serviced.enabled == CONFIG_ONDEMAND_YES)) {
1990             if(unlikely(!cg->st_throttle_serviced_ops)) {
1991                 cg->st_throttle_serviced_ops = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "throttle_serviced_ops");
1992                 if(likely(!cg->st_throttle_serviced_ops)) {
1993                     snprintfz(title, CHART_TITLE_MAX, "Throttle Serviced I/O Operations (all disks) for cgroup %s", cg->chart_title);
1994                     cg->st_throttle_serviced_ops = rrdset_create(type, "throttle_serviced_ops", NULL, "disk", "cgroup.throttle_serviced_ops", title, "operations/s", CHART_PRIORITY_CONTAINERS + 1200, update_every, RRDSET_TYPE_LINE);
1995                 }
1996                 rrddim_add(cg->st_throttle_serviced_ops, "read", NULL, 1, 1, RRDDIM_INCREMENTAL);
1997                 rrddim_add(cg->st_throttle_serviced_ops, "write", NULL, -1, 1, RRDDIM_INCREMENTAL);
1998             }
1999             else
2000                 rrdset_next(cg->st_throttle_serviced_ops);
2001
2002             rrddim_set(cg->st_throttle_serviced_ops, "read", cg->throttle_io_serviced.Read);
2003             rrddim_set(cg->st_throttle_serviced_ops, "write", cg->throttle_io_serviced.Write);
2004             rrdset_done(cg->st_throttle_serviced_ops);
2005         }
2006
2007         if(likely(cg->io_queued.updated && cg->io_queued.enabled == CONFIG_ONDEMAND_YES)) {
2008             if(unlikely(!cg->st_queued_ops)) {
2009                 cg->st_queued_ops = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "queued_ops");
2010                 if(likely(!cg->st_queued_ops)) {
2011                     snprintfz(title, CHART_TITLE_MAX, "Queued I/O Operations (all disks) for cgroup %s", cg->chart_title);
2012                     cg->st_queued_ops = rrdset_create(type, "queued_ops", NULL, "disk", "cgroup.queued_ops", title, "operations", CHART_PRIORITY_CONTAINERS + 2000, update_every, RRDSET_TYPE_LINE);
2013                 }
2014                 rrddim_add(cg->st_queued_ops, "read", NULL, 1, 1, RRDDIM_ABSOLUTE);
2015                 rrddim_add(cg->st_queued_ops, "write", NULL, -1, 1, RRDDIM_ABSOLUTE);
2016             }
2017             else
2018                 rrdset_next(cg->st_queued_ops);
2019
2020             rrddim_set(cg->st_queued_ops, "read", cg->io_queued.Read);
2021             rrddim_set(cg->st_queued_ops, "write", cg->io_queued.Write);
2022             rrdset_done(cg->st_queued_ops);
2023         }
2024
2025         if(likely(cg->io_merged.updated && cg->io_merged.enabled == CONFIG_ONDEMAND_YES)) {
2026             if(unlikely(!cg->st_merged_ops)) {
2027                 cg->st_merged_ops = rrdset_find_bytype(cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX), "merged_ops");
2028                 if(likely(!cg->st_merged_ops)) {
2029                     snprintfz(title, CHART_TITLE_MAX, "Merged I/O Operations (all disks) for cgroup %s", cg->chart_title);
2030                     cg->st_merged_ops = rrdset_create(type, "merged_ops", NULL, "disk", "cgroup.merged_ops", title, "operations/s", CHART_PRIORITY_CONTAINERS + 2100, update_every, RRDSET_TYPE_LINE);
2031                 }
2032                 rrddim_add(cg->st_merged_ops, "read", NULL, 1, 1024, RRDDIM_INCREMENTAL);
2033                 rrddim_add(cg->st_merged_ops, "write", NULL, -1, 1024, RRDDIM_INCREMENTAL);
2034             }
2035             else
2036                 rrdset_next(cg->st_merged_ops);
2037
2038             rrddim_set(cg->st_merged_ops, "read", cg->io_merged.Read);
2039             rrddim_set(cg->st_merged_ops, "write", cg->io_merged.Write);
2040             rrdset_done(cg->st_merged_ops);
2041         }
2042     }
2043
2044     if(likely(cgroup_enable_systemd_services))
2045         update_services_charts(update_every,
2046                 services_do_cpu,
2047                 services_do_mem_usage,
2048                 services_do_mem_detailed,
2049                 services_do_mem_failcnt,
2050                 services_do_swap_usage,
2051                 services_do_io,
2052                 services_do_io_ops,
2053                 services_do_throttle_io,
2054                 services_do_throttle_ops,
2055                 services_do_queued_ops,
2056                 services_do_merged_ops
2057         );
2058
2059     debug(D_CGROUP, "done updating cgroups charts");
2060 }
2061
2062 // ----------------------------------------------------------------------------
2063 // cgroups main
2064
2065 void *cgroups_main(void *ptr) {
2066     struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
2067
2068     info("CGROUP Plugin thread created with task id %d", gettid());
2069
2070     if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
2071         error("Cannot set pthread cancel type to DEFERRED.");
2072
2073     if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
2074         error("Cannot set pthread cancel state to ENABLE.");
2075
2076     struct rusage thread;
2077
2078     // when ZERO, attempt to do it
2079     int vdo_cpu_netdata = config_get_boolean("plugin:cgroups", "cgroups plugin resource charts", 1);
2080
2081     read_cgroup_plugin_configuration();
2082
2083     RRDSET *stcpu_thread = NULL;
2084
2085     usec_t step = cgroup_update_every * USEC_PER_SEC;
2086     usec_t find_every = cgroup_check_for_new_every * USEC_PER_SEC, find_next = 0;
2087     for(;;) {
2088         usec_t now = now_monotonic_usec();
2089         usec_t next = now - (now % step) + step;
2090
2091         while(now < next) {
2092             sleep_usec(next - now);
2093             now = now_monotonic_usec();
2094         }
2095
2096         if(unlikely(netdata_exit)) break;
2097
2098         // BEGIN -- the job to be done
2099
2100         if(unlikely(now >= find_next)) {
2101             find_all_cgroups();
2102             find_next = now + find_every;
2103         }
2104
2105         read_all_cgroups(cgroup_root);
2106         update_cgroup_charts(cgroup_update_every);
2107
2108         // END -- the job is done
2109
2110         // --------------------------------------------------------------------
2111
2112         if(vdo_cpu_netdata) {
2113             getrusage(RUSAGE_THREAD, &thread);
2114
2115             if(unlikely(!stcpu_thread)) {
2116                 stcpu_thread = rrdset_find("netdata.plugin_cgroups_cpu");
2117                 if(unlikely(!stcpu_thread))
2118                     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);
2119
2120                 rrddim_add(stcpu_thread, "user",  NULL,  1, 1000, RRDDIM_INCREMENTAL);
2121                 rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRDDIM_INCREMENTAL);
2122             }
2123             else
2124                 rrdset_next(stcpu_thread);
2125
2126             rrddim_set(stcpu_thread, "user"  , thread.ru_utime.tv_sec * 1000000ULL + thread.ru_utime.tv_usec);
2127             rrddim_set(stcpu_thread, "system", thread.ru_stime.tv_sec * 1000000ULL + thread.ru_stime.tv_usec);
2128             rrdset_done(stcpu_thread);
2129         }
2130     }
2131
2132     info("CGROUP thread exiting");
2133
2134     static_thread->enabled = 0;
2135     pthread_exit(NULL);
2136     return NULL;
2137 }