summaryrefslogtreecommitdiffstats
path: root/src/plugins/linux-cgroups.plugin/sys_fs_cgroup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/linux-cgroups.plugin/sys_fs_cgroup.c')
-rw-r--r--src/plugins/linux-cgroups.plugin/sys_fs_cgroup.c2771
1 files changed, 0 insertions, 2771 deletions
diff --git a/src/plugins/linux-cgroups.plugin/sys_fs_cgroup.c b/src/plugins/linux-cgroups.plugin/sys_fs_cgroup.c
deleted file mode 100644
index 9c0fd7f43f..0000000000
--- a/src/plugins/linux-cgroups.plugin/sys_fs_cgroup.c
+++ /dev/null
@@ -1,2771 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "sys_fs_cgroup.h"
-
-#define PLUGIN_CGROUPS_NAME "cgroups.plugin"
-#define PLUGIN_CGROUPS_MODULE_SYSTEMD_NAME "systemd"
-#define PLUGIN_CGROUPS_MODULE_CGROUPS_NAME "/sys/fs/cgroup"
-
-// ----------------------------------------------------------------------------
-// cgroup globals
-
-static long system_page_size = 4096; // system will be queried via sysconf() in configuration()
-
-static int cgroup_enable_cpuacct_stat = CONFIG_BOOLEAN_AUTO;
-static int cgroup_enable_cpuacct_usage = CONFIG_BOOLEAN_AUTO;
-static int cgroup_enable_memory = CONFIG_BOOLEAN_AUTO;
-static int cgroup_enable_detailed_memory = CONFIG_BOOLEAN_AUTO;
-static int cgroup_enable_memory_failcnt = CONFIG_BOOLEAN_AUTO;
-static int cgroup_enable_swap = CONFIG_BOOLEAN_AUTO;
-static int cgroup_enable_blkio_io = CONFIG_BOOLEAN_AUTO;
-static int cgroup_enable_blkio_ops = CONFIG_BOOLEAN_AUTO;
-static int cgroup_enable_blkio_throttle_io = CONFIG_BOOLEAN_AUTO;
-static int cgroup_enable_blkio_throttle_ops = CONFIG_BOOLEAN_AUTO;
-static int cgroup_enable_blkio_merged_ops = CONFIG_BOOLEAN_AUTO;
-static int cgroup_enable_blkio_queued_ops = CONFIG_BOOLEAN_AUTO;
-
-static int cgroup_enable_systemd_services = CONFIG_BOOLEAN_YES;
-static int cgroup_enable_systemd_services_detailed_memory = CONFIG_BOOLEAN_NO;
-static int cgroup_used_memory_without_cache = CONFIG_BOOLEAN_YES;
-
-static int cgroup_search_in_devices = 1;
-
-static int cgroup_enable_new_cgroups_detected_at_runtime = 1;
-static int cgroup_check_for_new_every = 10;
-static int cgroup_update_every = 1;
-
-static int cgroup_recheck_zero_blkio_every_iterations = 10;
-static int cgroup_recheck_zero_mem_failcnt_every_iterations = 10;
-static int cgroup_recheck_zero_mem_detailed_every_iterations = 10;
-
-static char *cgroup_cpuacct_base = NULL;
-static char *cgroup_blkio_base = NULL;
-static char *cgroup_memory_base = NULL;
-static char *cgroup_devices_base = NULL;
-
-static int cgroup_root_count = 0;
-static int cgroup_root_max = 1000;
-static int cgroup_max_depth = 0;
-
-static SIMPLE_PATTERN *enabled_cgroup_patterns = NULL;
-static SIMPLE_PATTERN *enabled_cgroup_paths = NULL;
-static SIMPLE_PATTERN *enabled_cgroup_renames = NULL;
-static SIMPLE_PATTERN *systemd_services_cgroups = NULL;
-
-static char *cgroups_rename_script = NULL;
-static char *cgroups_network_interface_script = NULL;
-
-static int cgroups_check = 0;
-
-static uint32_t Read_hash = 0;
-static uint32_t Write_hash = 0;
-static uint32_t user_hash = 0;
-static uint32_t system_hash = 0;
-
-void read_cgroup_plugin_configuration() {
- system_page_size = sysconf(_SC_PAGESIZE);
-
- Read_hash = simple_hash("Read");
- Write_hash = simple_hash("Write");
- user_hash = simple_hash("user");
- system_hash = simple_hash("system");
-
- cgroup_update_every = (int)config_get_number("plugin:cgroups", "update every", localhost->rrd_update_every);
- if(cgroup_update_every < localhost->rrd_update_every)
- cgroup_update_every = localhost->rrd_update_every;
-
- cgroup_check_for_new_every = (int)config_get_number("plugin:cgroups", "check for new cgroups every", (long long)cgroup_check_for_new_every * (long long)cgroup_update_every);
- if(cgroup_check_for_new_every < cgroup_update_every)
- cgroup_check_for_new_every = cgroup_update_every;
-
- cgroup_enable_cpuacct_stat = config_get_boolean_ondemand("plugin:cgroups", "enable cpuacct stat (total CPU)", cgroup_enable_cpuacct_stat);
- cgroup_enable_cpuacct_usage = config_get_boolean_ondemand("plugin:cgroups", "enable cpuacct usage (per core CPU)", cgroup_enable_cpuacct_usage);
-
- cgroup_enable_memory = config_get_boolean_ondemand("plugin:cgroups", "enable memory (used mem including cache)", cgroup_enable_memory);
- cgroup_enable_detailed_memory = config_get_boolean_ondemand("plugin:cgroups", "enable detailed memory", cgroup_enable_detailed_memory);
- cgroup_enable_memory_failcnt = config_get_boolean_ondemand("plugin:cgroups", "enable memory limits fail count", cgroup_enable_memory_failcnt);
- cgroup_enable_swap = config_get_boolean_ondemand("plugin:cgroups", "enable swap memory", cgroup_enable_swap);
-
- cgroup_enable_blkio_io = config_get_boolean_ondemand("plugin:cgroups", "enable blkio bandwidth", cgroup_enable_blkio_io);
- cgroup_enable_blkio_ops = config_get_boolean_ondemand("plugin:cgroups", "enable blkio operations", cgroup_enable_blkio_ops);
- cgroup_enable_blkio_throttle_io = config_get_boolean_ondemand("plugin:cgroups", "enable blkio throttle bandwidth", cgroup_enable_blkio_throttle_io);
- cgroup_enable_blkio_throttle_ops = config_get_boolean_ondemand("plugin:cgroups", "enable blkio throttle operations", cgroup_enable_blkio_throttle_ops);
- cgroup_enable_blkio_queued_ops = config_get_boolean_ondemand("plugin:cgroups", "enable blkio queued operations", cgroup_enable_blkio_queued_ops);
- cgroup_enable_blkio_merged_ops = config_get_boolean_ondemand("plugin:cgroups", "enable blkio merged operations", cgroup_enable_blkio_merged_ops);
-
- cgroup_recheck_zero_blkio_every_iterations = (int)config_get_number("plugin:cgroups", "recheck zero blkio every iterations", cgroup_recheck_zero_blkio_every_iterations);
- 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);
- 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);
-
- cgroup_enable_systemd_services = config_get_boolean("plugin:cgroups", "enable systemd services", cgroup_enable_systemd_services);
- cgroup_enable_systemd_services_detailed_memory = config_get_boolean("plugin:cgroups", "enable systemd services detailed memory", cgroup_enable_systemd_services_detailed_memory);
- cgroup_used_memory_without_cache = config_get_boolean("plugin:cgroups", "report used memory without cache", cgroup_used_memory_without_cache);
-
- char filename[FILENAME_MAX + 1], *s;
- struct mountinfo *mi, *root = mountinfo_read(0);
-
- mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "cpuacct");
- if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "cpuacct");
- if(!mi) {
- error("CGROUP: cannot find cpuacct mountinfo. Assuming default: /sys/fs/cgroup/cpuacct");
- s = "/sys/fs/cgroup/cpuacct";
- }
- else s = mi->mount_point;
- snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, s);
- cgroup_cpuacct_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/cpuacct", filename);
-
- mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "blkio");
- if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "blkio");
- if(!mi) {
- error("CGROUP: cannot find blkio mountinfo. Assuming default: /sys/fs/cgroup/blkio");
- s = "/sys/fs/cgroup/blkio";
- }
- else s = mi->mount_point;
- snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, s);
- cgroup_blkio_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/blkio", filename);
-
- mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "memory");
- if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "memory");
- if(!mi) {
- error("CGROUP: cannot find memory mountinfo. Assuming default: /sys/fs/cgroup/memory");
- s = "/sys/fs/cgroup/memory";
- }
- else s = mi->mount_point;
- snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, s);
- cgroup_memory_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/memory", filename);
-
- mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "devices");
- if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "devices");
- if(!mi) {
- error("CGROUP: cannot find devices mountinfo. Assuming default: /sys/fs/cgroup/devices");
- s = "/sys/fs/cgroup/devices";
- }
- else s = mi->mount_point;
- snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, s);
- cgroup_devices_base = config_get("plugin:cgroups", "path to /sys/fs/cgroup/devices", filename);
-
- cgroup_root_max = (int)config_get_number("plugin:cgroups", "max cgroups to allow", cgroup_root_max);
- cgroup_max_depth = (int)config_get_number("plugin:cgroups", "max cgroups depth to monitor", cgroup_max_depth);
-
- 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);
-
- enabled_cgroup_patterns = simple_pattern_create(
- config_get("plugin:cgroups", "enable by default cgroups matching",
- // ----------------------------------------------------------------
-
- " !*/init.scope " // ignore init.scope
- " !/system.slice/run-*.scope " // ignore system.slice/run-XXXX.scope
- " *.scope " // we need all other *.scope for sure
-
- // ----------------------------------------------------------------
-
- " /machine.slice/*.service " // #3367 systemd-nspawn
-
- // ----------------------------------------------------------------
-
- " !*/vcpu* " // libvirtd adds these sub-cgroups
- " !*/emulator " // libvirtd adds these sub-cgroups
- " !*.mount "
- " !*.partition "
- " !*.service "
- " !*.socket "
- " !*.slice "
- " !*.swap "
- " !*.user "
- " !/ "
- " !/docker "
- " !/libvirt "
- " !/lxc "
- " !/lxc/*/* " // #1397 #2649
- " !/machine "
- " !/qemu "
- " !/system "
- " !/systemd "
- " !/user "
- " * " // enable anything else
- ), NULL, SIMPLE_PATTERN_EXACT);
-
- enabled_cgroup_paths = simple_pattern_create(
- config_get("plugin:cgroups", "search for cgroups in subpaths matching",
- " !*/init.scope " // ignore init.scope
- " !*-qemu " // #345
- " !*.libvirt-qemu " // #3010
- " !/init.scope "
- " !/system "
- " !/systemd "
- " !/user "
- " !/user.slice "
- " !/lxc/*/* " // #2161 #2649
- " * "
- ), NULL, SIMPLE_PATTERN_EXACT);
-
- snprintfz(filename, FILENAME_MAX, "%s/cgroup-name.sh", netdata_configured_plugins_dir);
- cgroups_rename_script = config_get("plugin:cgroups", "script to get cgroup names", filename);
-
- snprintfz(filename, FILENAME_MAX, "%s/cgroup-network", netdata_configured_plugins_dir);
- cgroups_network_interface_script = config_get("plugin:cgroups", "script to get cgroup network interfaces", filename);
-
- enabled_cgroup_renames = simple_pattern_create(
- config_get("plugin:cgroups", "run script to rename cgroups matching",
- " !/ "
- " !*.mount "
- " !*.socket "
- " !*.partition "
- " /machine.slice/*.service " // #3367 systemd-nspawn
- " !*.service "
- " !*.slice "
- " !*.swap "
- " !*.user "
- " !init.scope "
- " !*.scope/vcpu* " // libvirtd adds these sub-cgroups
- " !*.scope/emulator " // libvirtd adds these sub-cgroups
- " *.scope "
- " *docker* "
- " *lxc* "
- " *qemu* "
- " *kubepods* " // #3396 kubernetes
- " *.libvirt-qemu " // #3010
- " * "
- ), NULL, SIMPLE_PATTERN_EXACT);
-
- if(cgroup_enable_systemd_services) {
- systemd_services_cgroups = simple_pattern_create(
- config_get("plugin:cgroups", "cgroups to match as systemd services",
- " !/system.slice/*/*.service "
- " /system.slice/*.service "
- ), NULL, SIMPLE_PATTERN_EXACT);
- }
-
- mountinfo_free_all(root);
-}
-
-// ----------------------------------------------------------------------------
-// cgroup objects
-
-struct blkio {
- int updated;
- int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
- int delay_counter;
-
- char *filename;
-
- unsigned long long Read;
- unsigned long long Write;
-/*
- unsigned long long Sync;
- unsigned long long Async;
- unsigned long long Total;
-*/
-};
-
-// https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt
-struct memory {
- ARL_BASE *arl_base;
- ARL_ENTRY *arl_dirty;
- ARL_ENTRY *arl_swap;
-
- int updated_detailed;
- int updated_usage_in_bytes;
- int updated_msw_usage_in_bytes;
- int updated_failcnt;
-
- int enabled_detailed; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
- int enabled_usage_in_bytes; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
- int enabled_msw_usage_in_bytes; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
- int enabled_failcnt; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
-
- int delay_counter_detailed;
- int delay_counter_failcnt;
-
- char *filename_detailed;
- char *filename_usage_in_bytes;
- char *filename_msw_usage_in_bytes;
- char *filename_failcnt;
-
- int detailed_has_dirty;
- int detailed_has_swap;
-
- // detailed metrics
- unsigned long long cache;
- unsigned long long rss;
- unsigned long long rss_huge;
- unsigned long long mapped_file;
- unsigned long long writeback;
- unsigned long long dirty;
- unsigned long long swap;
- unsigned long long pgpgin;
- unsigned long long pgpgout;
- unsigned long long pgfault;
- unsigned long long pgmajfault;
-/*
- unsigned long long inactive_anon;
- unsigned long long active_anon;
- unsigned long long inactive_file;
- unsigned long long active_file;
- unsigned long long unevictable;
- unsigned long long hierarchical_memory_limit;
- unsigned long long total_cache;
- unsigned long long total_rss;
- unsigned long long total_rss_huge;
- unsigned long long total_mapped_file;
- unsigned long long total_writeback;
- unsigned long long total_dirty;
- unsigned long long total_swap;
- unsigned long long total_pgpgin;
- unsigned long long total_pgpgout;
- unsigned long long total_pgfault;
- unsigned long long total_pgmajfault;
- unsigned long long total_inactive_anon;
- unsigned long long total_active_anon;
- unsigned long long total_inactive_file;
- unsigned long long total_active_file;
- unsigned long long total_unevictable;
-*/
-
- // single file metrics
- unsigned long long usage_in_bytes;
- unsigned long long msw_usage_in_bytes;
- unsigned long long failcnt;
-};
-
-// https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt
-struct cpuacct_stat {
- int updated;
- int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
-
- char *filename;
-
- unsigned long long user;
- unsigned long long system;
-};
-
-// https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt
-struct cpuacct_usage {
- int updated;
- int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
-
- char *filename;
-
- unsigned int cpus;
- unsigned long long *cpu_percpu;
-};
-
-struct cgroup_network_interface {
- const char *host_device;
- const char *container_device;
- struct cgroup_network_interface *next;
-};
-
-#define CGROUP_OPTIONS_DISABLED_DUPLICATE 0x00000001
-#define CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE 0x00000002
-
-struct cgroup {
- uint32_t options;
-
- char available; // found in the filesystem
- char enabled; // enabled in the config
-
- char *id;
- uint32_t hash;
-
- char *chart_id;
- uint32_t hash_chart;
-
- char *chart_title;
-
- struct cpuacct_stat cpuacct_stat;
- struct cpuacct_usage cpuacct_usage;
-
- struct memory memory;
-
- struct blkio io_service_bytes; // bytes
- struct blkio io_serviced; // operations
-
- struct blkio throttle_io_service_bytes; // bytes
- struct blkio throttle_io_serviced; // operations
-
- struct blkio io_merged; // operations
- struct blkio io_queued; // operations
-
- struct cgroup_network_interface *interfaces;
-
- // per cgroup charts
- RRDSET *st_cpu;
- RRDSET *st_cpu_per_core;
- RRDSET *st_mem;
- RRDSET *st_writeback;
- RRDSET *st_mem_activity;
- RRDSET *st_pgfaults;
- RRDSET *st_mem_usage;
- RRDSET *st_mem_failcnt;
- RRDSET *st_io;
- RRDSET *st_serviced_ops;
- RRDSET *st_throttle_io;
- RRDSET *st_throttle_serviced_ops;
- RRDSET *st_queued_ops;
- RRDSET *st_merged_ops;
-
- // services
- RRDDIM *rd_cpu;
- RRDDIM *rd_mem_usage;
- RRDDIM *rd_mem_failcnt;
- RRDDIM *rd_swap_usage;
-
- RRDDIM *rd_mem_detailed_cache;
- RRDDIM *rd_mem_detailed_rss;
- RRDDIM *rd_mem_detailed_mapped;
- RRDDIM *rd_mem_detailed_writeback;
- RRDDIM *rd_mem_detailed_pgpgin;
- RRDDIM *rd_mem_detailed_pgpgout;
- RRDDIM *rd_mem_detailed_pgfault;
- RRDDIM *rd_mem_detailed_pgmajfault;
-
- RRDDIM *rd_io_service_bytes_read;
- RRDDIM *rd_io_serviced_read;
- RRDDIM *rd_throttle_io_read;
- RRDDIM *rd_throttle_io_serviced_read;
- RRDDIM *rd_io_queued_read;
- RRDDIM *rd_io_merged_read;
-
- RRDDIM *rd_io_service_bytes_write;
- RRDDIM *rd_io_serviced_write;
- RRDDIM *rd_throttle_io_write;
- RRDDIM *rd_throttle_io_serviced_write;
- RRDDIM *rd_io_queued_write;
- RRDDIM *rd_io_merged_write;
-
- struct cgroup *next;
-
-} *cgroup_root = NULL;
-
-// ----------------------------------------------------------------------------
-// read values from /sys
-
-static inline void cgroup_read_cpuacct_stat(struct cpuacct_stat *cp) {
- static procfile *ff = NULL;
-
- if(likely(cp->filename)) {
- ff = procfile_reopen(ff, cp->filename, NULL, PROCFILE_FLAG_DEFAULT);
- if(unlikely(!ff)) {
- cp->updated = 0;
- cgroups_check = 1;
- return;
- }
-
- ff = procfile_readall(ff);
- if(unlikely(!ff)) {
- cp->updated = 0;
- cgroups_check = 1;
- return;
- }
-
- unsigned long i, lines = procfile_lines(ff);
-
- if(unlikely(lines < 1)) {
- error("CGROUP: file '%s' should have 1+ lines.", cp->filename);
- cp->updated = 0;
- return;
- }
-
- for(i = 0; i < lines ; i++) {
- char *s = procfile_lineword(ff, i, 0);
- uint32_t hash = simple_hash(s);
-
- if(unlikely(hash == user_hash && !strcmp(s, "user")))
- cp->user = str2ull(procfile_lineword(ff, i, 1));
-
- else if(unlikely(hash == system_hash && !strcmp(s, "system")))
- cp->system = str2ull(procfile_lineword(ff, i, 1));
- }
-
- cp->updated = 1;
-
- if(unlikely(cp->enabled == CONFIG_BOOLEAN_AUTO && (cp->user || cp->system)))
- cp->enabled = CONFIG_BOOLEAN_YES;
- }
-}
-
-static inline void cgroup_read_cpuacct_usage(struct cpuacct_usage *ca) {
- static procfile *ff = NULL;
-
- if(likely(ca->filename)) {
- ff = procfile_reopen(ff, ca->filename, NULL, PROCFILE_FLAG_DEFAULT);
- if(unlikely(!ff)) {
- ca->updated = 0;
- cgroups_check = 1;
- return;
- }
-
- ff = procfile_readall(ff);
- if(unlikely(!ff)) {
- ca->updated = 0;
- cgroups_check = 1;
- return;
- }
-
- if(unlikely(procfile_lines(ff) < 1)) {
- error("CGROUP: file '%s' should have 1+ lines but has %zu.", ca->filename, procfile_lines(ff));
- ca->updated = 0;
- return;
- }
-
- unsigned long i = procfile_linewords(ff, 0);
- if(unlikely(i == 0)) {
- ca->updated = 0;
- return;
- }
-
- // we may have 1 more CPU reported
- while(i > 0) {
- char *s = procfile_lineword(ff, 0, i - 1);
- if(!*s) i--;
- else break;
- }
-
- if(unlikely(i != ca->cpus)) {
- freez(ca->cpu_percpu);
- ca->cpu_percpu = mallocz(sizeof(unsigned long long) * i);
- ca->cpus = (unsigned int)i;
- }
-
- unsigned long long total = 0;
- for(i = 0; i < ca->cpus ;i++) {
- unsigned long long n = str2ull(procfile_lineword(ff, 0, i));
- ca->cpu_percpu[i] = n;
- total += n;
- }
-
- ca->updated = 1;
-
- if(unlikely(ca->enabled == CONFIG_BOOLEAN_AUTO && total))
- ca->enabled = CONFIG_BOOLEAN_YES;
- }
-}
-
-static inline void cgroup_read_blkio(struct blkio *io) {
- if(unlikely(io->enabled == CONFIG_BOOLEAN_AUTO && io->delay_counter > 0)) {
- io->delay_counter--;
- return;
- }
-
- if(likely(io->filename)) {
- static procfile *ff = NULL;
-
- ff = procfile_reopen(ff, io->filename, NULL, PROCFILE_FLAG_DEFAULT);
- if(unlikely(!ff)) {
- io->updated = 0;
- cgroups_check = 1;
- return;
- }
-
- ff = procfile_readall(ff);
- if(unlikely(!ff)) {
- io->updated = 0;
- cgroups_check = 1;
- return;
- }
-
- unsigned long i, lines = procfile_lines(ff);
-
- if(unlikely(lines < 1)) {
- error("CGROUP: file '%s' should have 1+ lines.", io->filename);
- io->updated = 0;
- return;
- }
-
- io->Read = 0;
- io->Write = 0;
-/*
- io->Sync = 0;
- io->Async = 0;
- io->Total = 0;
-*/
-
- for(i = 0; i < lines ; i++) {
- char *s = procfile_lineword(ff, i, 1);
- uint32_t hash = simple_hash(s);
-
- if(unlikely(hash == Read_hash && !strcmp(s, "Read")))
- io->Read += str2ull(procfile_lineword(ff, i, 2));
-
- else if(unlikely(hash == Write_hash && !strcmp(s, "Write")))
- io->Write += str2ull(procfile_lineword(ff, i, 2));
-
-/*
- else if(unlikely(hash == Sync_hash && !strcmp(s, "Sync")))
- io->Sync += str2ull(procfile_lineword(ff, i, 2));
-
- else if(unlikely(hash == Async_hash && !strcmp(s, "Async")))
- io->Async += str2ull(procfile_lineword(ff, i, 2));
-
- else if(unlikely(hash == Total_hash && !strcmp(s, "Total")))
- io->Total += str2ull(procfile_lineword(ff, i, 2));
-*/
- }
-
- io->updated = 1;
-
- if(unlikely(io->enabled == CONFIG_BOOLEAN_AUTO)) {
- if(unlikely(io->Read || io->Write))
- io->enabled = CONFIG_BOOLEAN_YES;
- else
- io->delay_counter = cgroup_recheck_zero_blkio_every_iterations;
- }
- }
-}
-
-static inline void cgroup_read_memory(struct memory *mem) {
- static procfile *ff = NULL;
-
- // read detailed ram usage
- if(likely(mem->filename_detailed)) {
- if(unlikely(mem->enabled_detailed == CONFIG_BOOLEAN_AUTO && mem->delay_counter_detailed > 0)) {
- mem->delay_counter_detailed--;
- goto memory_next;
- }
-
- ff = procfile_reopen(ff, mem->filename_detailed, NULL, PROCFILE_FLAG_DEFAULT);
- if(unlikely(!ff)) {
- mem->updated_detailed = 0;
- cgroups_check = 1;
- goto memory_next;
- }
-
- ff = procfile_readall(ff);
- if(unlikely(!ff)) {
- mem->updated_detailed = 0;
- cgroups_check = 1;
- goto memory_next;
- }
-
- unsigned long i, lines = procfile_lines(ff);
-
- if(unlikely(lines < 1)) {
- error("CGROUP: file '%s' should have 1+ lines.", mem->filename_detailed);
- mem->updated_detailed = 0;
- goto memory_next;
- }
-
- if(unlikely(!mem->arl_base)) {
- mem->arl_base = arl_create("cgroup/memory", NULL, 60);
-
- arl_expect(mem->arl_base, "cache", &mem->cache);
- arl_expect(mem->arl_base, "rss", &mem->rss);
- arl_expect(mem->arl_base, "rss_huge", &mem->rss_huge);
- arl_expect(mem->arl_base, "mapped_file", &mem->mapped_file);
- arl_expect(mem->arl_base, "writeback", &mem->writeback);
- mem->arl_dirty = arl_expect(mem->arl_base, "dirty", &mem->dirty);
- mem->arl_swap = arl_expect(mem->arl_base, "swap", &mem->swap);
- arl_expect(mem->arl_base, "pgpgin", &mem->pgpgin);
- arl_expect(mem->arl_base, "pgpgout", &mem->pgpgout);
- arl_expect(mem->arl_base, "pgfault", &mem->pgfault);
- arl_expect(mem->arl_base, "pgmajfault", &mem->pgmajfault);
- }
-
- arl_begin(mem->arl_base);
-
- for(i = 0; i < lines ; i++) {
- if(arl_check(mem->arl_base,
- procfile_lineword(ff, i, 0),
- procfile_lineword(ff, i, 1))) break;
- }
-
- if(unlikely(mem->arl_dirty->flags & ARL_ENTRY_FLAG_FOUND))
- mem->detailed_has_dirty = 1;
-
- if(unlikely(mem->arl_swap->flags & ARL_ENTRY_FLAG_FOUND))
- mem->detailed_has_swap = 1;
-
- // 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);
-
- mem->updated_detailed = 1;
-
- if(unlikely(mem->enabled_detailed == CONFIG_BOOLEAN_AUTO)) {
- 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)
- mem->enabled_detailed = CONFIG_BOOLEAN_YES;
- else
- mem->delay_counter_detailed = cgroup_recheck_zero_mem_detailed_every_iterations;
- }
- }
-
-memory_next:
-
- // read usage_in_bytes
- if(likely(mem->filename_usage_in_bytes)) {
- mem->updated_usage_in_bytes = !read_single_number_file(mem->filename_usage_in_bytes, &mem->usage_in_bytes);
- if(unlikely(mem->updated_usage_in_bytes && mem->enabled_usage_in_bytes == CONFIG_BOOLEAN_AUTO && mem->usage_in_bytes))
- mem->enabled_usage_in_bytes = CONFIG_BOOLEAN_YES;
- }
-
- // read msw_usage_in_bytes
- if(likely(mem->filename_msw_usage_in_bytes)) {
- mem->updated_msw_usage_in_bytes = !read_single_number_file(mem->filename_msw_usage_in_bytes, &mem->msw_usage_in_bytes);
- if(unlikely(mem->updated_msw_usage_in_bytes && mem->enabled_msw_usage_in_bytes == CONFIG_BOOLEAN_AUTO && mem->msw_usage_in_bytes))
- mem->enabled_msw_usage_in_bytes = CONFIG_BOOLEAN_YES;
- }
-
- // read failcnt
- if(likely(mem->filename_failcnt)) {
- if(unlikely(mem->enabled_failcnt == CONFIG_BOOLEAN_AUTO && mem->delay_counter_failcnt > 0)) {
- mem->updated_failcnt = 0;
- mem->delay_counter_failcnt--;
- }
- else {
- mem->updated_failcnt = !read_single_number_file(mem->filename_failcnt, &mem->failcnt);
- if(unlikely(mem->updated_failcnt && mem->enabled_failcnt == CONFIG_BOOLEAN_AUTO)) {
- if(unlikely(!mem->failcnt))
- mem->delay_counter_failcnt = cgroup_recheck_zero_mem_failcnt_every_iterations;
- else
- mem->enabled_failcnt = CONFIG_BOOLEAN_YES;
- }
- }
- }
-}
-
-static inline void cgroup_read(struct cgroup *cg) {
- debug(D_CGROUP, "reading metrics for cgroups '%s'", cg->id);
-
- cgroup_read_cpuacct_stat(&cg->cpuacct_stat);
- cgroup_read_cpuacct_usage(&cg->cpuacct_usage);
- cgroup_read_memory(&cg->memory);
- cgroup_read_blkio(&cg->io_service_bytes);
- cgroup_read_blkio(&cg->io_serviced);
- cgroup_read_blkio(&cg->throttle_io_service_bytes);
- cgroup_read_blkio(&cg->throttle_io_serviced);
- cgroup_read_blkio(&cg->io_merged);
- cgroup_read_blkio(&cg->io_queued);
-}
-
-static inline void read_all_cgroups(struct cgroup *root) {
- debug(D_CGROUP, "reading metrics for all cgroups");
-
- struct cgroup *cg;
-
- for(cg = root; cg ; cg = cg->next)
- if(cg->enabled && cg->available)
- cgroup_read(cg);
-}
-
-// ----------------------------------------------------------------------------
-// cgroup network interfaces
-
-#define CGROUP_NETWORK_INTERFACE_MAX_LINE 2048
-static inline void read_cgroup_network_interfaces(struct cgroup *cg) {
- debug(D_CGROUP, "looking for the network interfaces of cgroup '%s' with chart id '%s' and title '%s'", cg->id, cg->chart_id, cg->chart_title);
-
- pid_t cgroup_pid;
- char command[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1];
-
- snprintfz(command, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec %s --cgroup '%s%s'", cgroups_network_interface_script, cgroup_cpuacct_base, cg->id);
-
- debug(D_CGROUP, "executing command '%s' for cgroup '%s'", command, cg->id);
- FILE *fp = mypopen(command, &cgroup_pid);
- if(!fp) {
- error("CGROUP: cannot popen(\"%s\", \"r\").", command);
- return;
- }
-
- char *s;
- char buffer[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1];
- while((s = fgets(buffer, CGROUP_NETWORK_INTERFACE_MAX_LINE, fp))) {
- trim(s);
-
- if(*s && *s != '\n') {
- char *t = s;
- while(*t && *t != ' ') t++;
- if(*t == ' ') {
- *t = '\0';
- t++;
- }
-
- if(!*s) {
- error("CGROUP: empty host interface returned by script");
- continue;
- }
-
- if(!*t) {
- error("CGROUP: empty guest interface returned by script");
- continue;
- }
-
- struct cgroup_network_interface *i = callocz(1, sizeof(struct cgroup_network_interface));
- i->host_device = strdupz(s);
- i->container_device = strdupz(t);
- i->next = cg->interfaces;
- cg->interfaces = i;
-
- info("CGROUP: cgroup '%s' has network interface '%s' as '%s'", cg->id, i->host_device, i->container_device);
-
- // register a device rename to proc_net_dev.c
- netdev_rename_device_add(i->host_device, i->container_device, cg->chart_id);
- }
- }
-
- mypclose(fp, cgroup_pid);
- // debug(D_CGROUP, "closed command for cgroup '%s'", cg->id);
-}
-
-static inline void free_cgroup_network_interfaces(struct cgroup *cg) {
- while(cg->interfaces) {
- struct cgroup_network_interface *i = cg->interfaces;
- cg->interfaces = i->next;
-
- // delete the registration of proc_net_dev rename
- netdev_rename_device_del(i->host_device);
-
- freez((void *)i->host_device);
- freez((void *)i->container_device);
- freez((void *)i);
- }
-}
-
-// ----------------------------------------------------------------------------
-// add/remove/find cgroup objects
-
-#define CGROUP_CHARTID_LINE_MAX 1024
-
-static inline char *cgroup_title_strdupz(const char *s) {
- if(!s || !*s) s = "/";
-
- if(*s == '/' && s[1] != '\0') s++;
-
- char *r = strdupz(s);
- netdata_fix_chart_name(r);
-
- return r;
-}
-
-static inline char *cgroup_chart_id_strdupz(const char *s) {
- if(!s || !*s) s = "/";
-
- if(*s == '/' && s[1] != '\0') s++;
-
- char *r = strdupz(s);
- netdata_fix_chart_id(r);
-
- return r;
-}
-
-static inline void cgroup_get_chart_name(struct cgroup *cg) {
- 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);
-
- pid_t cgroup_pid;
- char command[CGROUP_CHARTID_LINE_MAX + 1];
-
- snprintfz(command, CGROUP_CHARTID_LINE_MAX, "exec %s '%s' '%s'", cgroups_rename_script, cg->chart_id, cg->id);
-
- debug(D_CGROUP, "executing command \"%s\" for cgroup '%s'", command, cg->id);
- FILE *fp = mypopen(command, &cgroup_pid);
- if(fp) {
- // debug(D_CGROUP, "reading from command '%s' for cgroup '%s'", command, cg->id);
- char buffer[CGROUP_CHARTID_LINE_MAX + 1];
- char *s = fgets(buffer, CGROUP_CHARTID_LINE_MAX, fp);
- // debug(D_CGROUP, "closing command for cgroup '%s'", cg->id);
- mypclose(fp, cgroup_pid);
- // debug(D_CGROUP, "closed command for cgroup '%s'", cg->id);
-
- if(s && *s && *s != '\n') {
- debug(D_CGROUP, "cgroup '%s' should be renamed to '%s'", cg->id, s);
-
- trim(s);
-
- freez(cg->chart_title);
- cg->chart_title = cgroup_title_strdupz(s);
-
- freez(cg->chart_id);
- cg->chart_id = cgroup_chart_id_strdupz(s);
- cg->hash_chart = simple_hash(cg->chart_id);
- }
- }
- else
- error("CGROUP: cannot popen(\"%s\", \"r\").", command);
-}
-
-static inline struct cgroup *cgroup_add(const char *id) {
- if(!id || !*id) id = "/";
- debug(D_CGROUP, "adding to list, cgroup with id '%s'", id);
-
- if(cgroup_root_count >= cgroup_root_max) {
- info("CGROUP: maximum number of cgroups reached (%d). Not adding cgroup '%s'", cgroup_root_count, id);
- return NULL;
- }
-
- int def = simple_pattern_matches(enabled_cgroup_patterns, id)?cgroup_enable_new_cgroups_detected_at_runtime:0;
- struct cgroup *cg = callocz(1, sizeof(struct cgroup));
-
- cg->id = strdupz(id);<