unified cgroup support (#5407)
* WiP unified cgroup support * add cpu usage support and disk iops support * memory limits * WIP working memory charts * detailed memory chart * docs change
This commit is contained in:
parent
ab6f1c0b25
commit
6724b631de
|
@ -123,5 +123,6 @@ username|name|email (optional)
|
|||
@vladmovchan|Vladyslav Movchan|vladislav.movchan@gmail.com
|
||||
@gmosx|George Moschovitis
|
||||
@adherzog|Adam Herzog|adam@adamherzog.com
|
||||
@skrzyp1|Jerzy S.|
|
||||
|
||||
[![analytics](https://www.google-analytics.com/collect?v=1&aip=1&t=pageview&_s=1&ds=github&dr=https%3A%2F%2Fgithub.com%2Fnetdata%2Fnetdata&dl=https%3A%2F%2Fmy-netdata.io%2Fgithub%2FCONTRIBUTORS&_u=MAC~&cid=5792dfd7-8dc4-476b-af31-da2fdb9f93d2&tid=UA-64295674-3)]()
|
||||
|
|
|
@ -56,6 +56,18 @@ To provide a sane default for this setting, netdata uses the following pattern l
|
|||
|
||||
So, we disable checking for **child cgroups** in systemd internal cgroups ([systemd services are monitored by netdata](#monitoring-systemd-services)), user cgroups (normally used for desktop and remote user sessions), qemu virtual machines (child cgroups of virtual machines) and `init.scope`. All others are enabled.
|
||||
|
||||
### unified cgroups (cgroups v2) support
|
||||
|
||||
Basic unified cgroups metrics are supported. To use them instead of v1 cgroups add:
|
||||
|
||||
```
|
||||
[plugin:cgroups]
|
||||
use unified cgroups = yes
|
||||
path to unified cgroups = /sys/fs/cgroup
|
||||
```
|
||||
|
||||
Unified cgroups use same name pattern matching as v1 cgroups. `cgroup_enable_systemd_services_detailed_memory` is currently unsupported when using unified cgroups.
|
||||
|
||||
|
||||
### enabled cgroups
|
||||
|
||||
|
|
|
@ -28,6 +28,9 @@ 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_use_unified_cgroups = CONFIG_BOOLEAN_NO;
|
||||
static int cgroup_unified_exist = CONFIG_BOOLEAN_AUTO;
|
||||
|
||||
static int cgroup_search_in_devices = 1;
|
||||
|
||||
static int cgroup_enable_new_cgroups_detected_at_runtime = 1;
|
||||
|
@ -44,6 +47,7 @@ static char *cgroup_cpuset_base = NULL;
|
|||
static char *cgroup_blkio_base = NULL;
|
||||
static char *cgroup_memory_base = NULL;
|
||||
static char *cgroup_devices_base = NULL;
|
||||
static char *cgroup_unified_base = NULL;
|
||||
|
||||
static int cgroup_root_count = 0;
|
||||
static int cgroup_root_max = 1000;
|
||||
|
@ -80,6 +84,8 @@ void read_cgroup_plugin_configuration() {
|
|||
if(cgroup_check_for_new_every < cgroup_update_every)
|
||||
cgroup_check_for_new_every = cgroup_update_every;
|
||||
|
||||
cgroup_use_unified_cgroups = config_get_boolean_ondemand("plugin:cgroups", "use unified cgroups", cgroup_use_unified_cgroups);
|
||||
|
||||
cgroup_containers_chart_priority = (int)config_get_number("plugin:cgroups", "containers priority", cgroup_containers_chart_priority);
|
||||
if(cgroup_containers_chart_priority < 1)
|
||||
cgroup_containers_chart_priority = NETDATA_CHART_PRIO_CGROUPS_CONTAINERS;
|
||||
|
@ -109,7 +115,7 @@ void read_cgroup_plugin_configuration() {
|
|||
|
||||
char filename[FILENAME_MAX + 1], *s;
|
||||
struct mountinfo *mi, *root = mountinfo_read(0);
|
||||
|
||||
if(!cgroup_use_unified_cgroups) {
|
||||
mi = mountinfo_find_by_filesystem_super_option(root, "cgroup", "cpuacct");
|
||||
if(!mi) mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup", "cpuacct");
|
||||
if(!mi) {
|
||||
|
@ -159,6 +165,40 @@ void read_cgroup_plugin_configuration() {
|
|||
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);
|
||||
}
|
||||
else {
|
||||
//cgroup_enable_cpuacct_stat =
|
||||
cgroup_enable_cpuacct_usage =
|
||||
//cgroup_enable_memory =
|
||||
//cgroup_enable_detailed_memory =
|
||||
cgroup_enable_memory_failcnt =
|
||||
//cgroup_enable_swap =
|
||||
//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 = CONFIG_BOOLEAN_NO;
|
||||
cgroup_search_in_devices = 0;
|
||||
cgroup_enable_systemd_services_detailed_memory = CONFIG_BOOLEAN_NO;
|
||||
cgroup_used_memory_without_cache = CONFIG_BOOLEAN_NO; //unified cgroups use different values
|
||||
|
||||
//TODO: can there be more than 1 cgroup2 mount point?
|
||||
mi = mountinfo_find_by_filesystem_super_option(root, "cgroup2", "rw"); //there is no cgroup2 specific super option - for now use 'rw' option
|
||||
if(mi) debug(D_CGROUP, "found unified cgroup root using super options, with path: '%s'", mi->mount_point);
|
||||
if(!mi) {
|
||||
mi = mountinfo_find_by_filesystem_mount_source(root, "cgroup2", "cgroup");
|
||||
if(mi) debug(D_CGROUP, "found unified cgroup root using mountsource info, with path: '%s'", mi->mount_point);
|
||||
}
|
||||
if(!mi) {
|
||||
error("CGROUP: cannot find cgroup2 mountinfo. Assuming default: /sys/fs/cgroup");
|
||||
s = "/sys/fs/cgroup";
|
||||
}
|
||||
else s = mi->mount_point;
|
||||
snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, s);
|
||||
cgroup_unified_base = config_get("plugin:cgroups", "path to unified cgroups", filename);
|
||||
debug(D_CGROUP, "using cgroup root: '%s'", cgroup_unified_base);
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -321,6 +361,17 @@ struct memory {
|
|||
unsigned long long unevictable;
|
||||
unsigned long long hierarchical_memory_limit;
|
||||
*/
|
||||
//unified cgroups metrics
|
||||
unsigned long long anon;
|
||||
unsigned long long kernel_stack;
|
||||
unsigned long long slab;
|
||||
unsigned long long sock;
|
||||
unsigned long long shmem;
|
||||
unsigned long long anon_thp;
|
||||
//unsigned long long file_writeback;
|
||||
//unsigned long long file_dirty;
|
||||
//unsigned long long file;
|
||||
|
||||
unsigned long long total_cache;
|
||||
unsigned long long total_rss;
|
||||
unsigned long long total_rss_huge;
|
||||
|
@ -376,6 +427,7 @@ struct cgroup_network_interface {
|
|||
|
||||
#define CGROUP_OPTIONS_DISABLED_DUPLICATE 0x00000001
|
||||
#define CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE 0x00000002
|
||||
#define CGROUP_OPTIONS_IS_UNIFIED 0x00000004
|
||||
|
||||
struct cgroup {
|
||||
uint32_t options;
|
||||
|
@ -528,6 +580,42 @@ static inline void cgroup_read_cpuacct_stat(struct cpuacct_stat *cp) {
|
|||
}
|
||||
}
|
||||
|
||||
static inline void cgroup2_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 lines = procfile_lines(ff);
|
||||
|
||||
if(unlikely(lines < 3)) {
|
||||
error("CGROUP: file '%s' should have 3+ lines.", cp->filename);
|
||||
cp->updated = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
cp->user = str2ull(procfile_lineword(ff, 1, 1));
|
||||
cp->system = str2ull(procfile_lineword(ff, 2, 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;
|
||||
|
||||
|
@ -657,7 +745,57 @@ static inline void cgroup_read_blkio(struct blkio *io) {
|
|||
}
|
||||
}
|
||||
|
||||
static inline void cgroup_read_memory(struct memory *mem) {
|
||||
static inline void cgroup2_read_blkio(struct blkio *io, unsigned int word_offset) {
|
||||
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;
|
||||
|
||||
for (i = 0; i < lines; i++) {
|
||||
io->Read += str2ull(procfile_lineword(ff, i, 2 + word_offset));
|
||||
io->Write += str2ull(procfile_lineword(ff, i, 4 + word_offset));
|
||||
}
|
||||
|
||||
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, char parent_cg_is_unified) {
|
||||
static procfile *ff = NULL;
|
||||
|
||||
// read detailed ram usage
|
||||
|
@ -689,7 +827,9 @@ static inline void cgroup_read_memory(struct memory *mem) {
|
|||
goto memory_next;
|
||||
}
|
||||
|
||||
|
||||
if(unlikely(!mem->arl_base)) {
|
||||
if(parent_cg_is_unified == 0){
|
||||
mem->arl_base = arl_create("cgroup/memory", NULL, 60);
|
||||
|
||||
arl_expect(mem->arl_base, "total_cache", &mem->total_cache);
|
||||
|
@ -703,6 +843,20 @@ static inline void cgroup_read_memory(struct memory *mem) {
|
|||
arl_expect(mem->arl_base, "total_pgpgout", &mem->total_pgpgout);
|
||||
arl_expect(mem->arl_base, "total_pgfault", &mem->total_pgfault);
|
||||
arl_expect(mem->arl_base, "total_pgmajfault", &mem->total_pgmajfault);
|
||||
} else {
|
||||
mem->arl_base = arl_create("cgroup/memory", NULL, 60);
|
||||
|
||||
arl_expect(mem->arl_base, "anon", &mem->anon);
|
||||
arl_expect(mem->arl_base, "kernel_stack", &mem->kernel_stack);
|
||||
arl_expect(mem->arl_base, "slab", &mem->slab);
|
||||
arl_expect(mem->arl_base, "sock", &mem->sock);
|
||||
arl_expect(mem->arl_base, "anon_thp", &mem->anon_thp);
|
||||
arl_expect(mem->arl_base, "file", &mem->total_mapped_file);
|
||||
arl_expect(mem->arl_base, "file_writeback", &mem->total_writeback);
|
||||
mem->arl_dirty = arl_expect(mem->arl_base, "file_dirty", &mem->total_dirty);
|
||||
arl_expect(mem->arl_base, "pgfault", &mem->total_pgfault);
|
||||
arl_expect(mem->arl_base, "pgmajfault", &mem->total_pgmajfault);
|
||||
}
|
||||
}
|
||||
|
||||
arl_begin(mem->arl_base);
|
||||
|
@ -716,7 +870,7 @@ static inline void cgroup_read_memory(struct memory *mem) {
|
|||
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))
|
||||
if(unlikely(parent_cg_is_unified == 0 && 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);
|
||||
|
@ -724,8 +878,10 @@ static inline void cgroup_read_memory(struct memory *mem) {
|
|||
mem->updated_detailed = 1;
|
||||
|
||||
if(unlikely(mem->enabled_detailed == CONFIG_BOOLEAN_AUTO)) {
|
||||
if(mem->total_cache || mem->total_dirty || mem->total_rss || mem->total_rss_huge || mem->total_mapped_file || mem->total_writeback
|
||||
|| mem->total_swap || mem->total_pgpgin || mem->total_pgpgout || mem->total_pgfault || mem->total_pgmajfault)
|
||||
if(( (!parent_cg_is_unified) && ( mem->total_cache || mem->total_dirty || mem->total_rss || mem->total_rss_huge || mem->total_mapped_file || mem->total_writeback
|
||||
|| mem->total_swap || mem->total_pgpgin || mem->total_pgpgout || mem->total_pgfault || mem->total_pgmajfault))
|
||||
|| (parent_cg_is_unified && ( mem->anon || mem->total_dirty || mem->kernel_stack || mem->slab || mem->sock || mem->total_writeback
|
||||
|| mem->anon_thp || mem->total_pgfault || mem->total_pgmajfault)))
|
||||
mem->enabled_detailed = CONFIG_BOOLEAN_YES;
|
||||
else
|
||||
mem->delay_counter_detailed = cgroup_recheck_zero_mem_detailed_every_iterations;
|
||||
|
@ -768,10 +924,10 @@ memory_next:
|
|||
|
||||
static inline void cgroup_read(struct cgroup *cg) {
|
||||
debug(D_CGROUP, "reading metrics for cgroups '%s'", cg->id);
|
||||
|
||||
if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
|
||||
cgroup_read_cpuacct_stat(&cg->cpuacct_stat);
|
||||
cgroup_read_cpuacct_usage(&cg->cpuacct_usage);
|
||||
cgroup_read_memory(&cg->memory);
|
||||
cgroup_read_memory(&cg->memory, 0);
|
||||
cgroup_read_blkio(&cg->io_service_bytes);
|
||||
cgroup_read_blkio(&cg->io_serviced);
|
||||
cgroup_read_blkio(&cg->throttle_io_service_bytes);
|
||||
|
@ -779,6 +935,14 @@ static inline void cgroup_read(struct cgroup *cg) {
|
|||
cgroup_read_blkio(&cg->io_merged);
|
||||
cgroup_read_blkio(&cg->io_queued);
|
||||
}
|
||||
else {
|
||||
//TODO: io_service_bytes and io_serviced use same file merge into 1 function
|
||||
cgroup2_read_blkio(&cg->io_service_bytes, 0);
|
||||
cgroup2_read_blkio(&cg->io_serviced, 4);
|
||||
cgroup2_read_cpuacct_stat(&cg->cpuacct_stat);
|
||||
cgroup_read_memory(&cg->memory, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void read_all_cgroups(struct cgroup *root) {
|
||||
debug(D_CGROUP, "reading metrics for all cgroups");
|
||||
|
@ -800,7 +964,12 @@ static inline void read_cgroup_network_interfaces(struct cgroup *cg) {
|
|||
pid_t cgroup_pid;
|
||||
char command[CGROUP_NETWORK_INTERFACE_MAX_LINE + 1];
|
||||
|
||||
if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
|
||||
snprintfz(command, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec %s --cgroup '%s%s'", cgroups_network_interface_script, cgroup_cpuacct_base, cg->id);
|
||||
}
|
||||
else {
|
||||
snprintfz(command, CGROUP_NETWORK_INTERFACE_MAX_LINE, "exec %s --cgroup '%s%s'", cgroups_network_interface_script, cgroup_unified_base, cg->id);
|
||||
}
|
||||
|
||||
debug(D_CGROUP, "executing command '%s' for cgroup '%s'", command, cg->id);
|
||||
FILE *fp = mypopen(command, &cgroup_pid);
|
||||
|
@ -955,6 +1124,8 @@ static inline struct cgroup *cgroup_add(const char *id) {
|
|||
cg->chart_id = cgroup_chart_id_strdupz(id);
|
||||
cg->hash_chart = simple_hash(cg->chart_id);
|
||||
|
||||
if(cgroup_use_unified_cgroups) cg->options |= CGROUP_OPTIONS_IS_UNIFIED;
|
||||
|
||||
if(!cgroup_root)
|
||||
cgroup_root = cg;
|
||||
else {
|
||||
|
@ -1295,7 +1466,7 @@ static inline void find_all_cgroups() {
|
|||
debug(D_CGROUP, "searching for cgroups");
|
||||
|
||||
mark_all_cgroups_as_not_available();
|
||||
|
||||
if(!cgroup_use_unified_cgroups) {
|
||||
if(cgroup_enable_cpuacct_stat || cgroup_enable_cpuacct_usage) {
|
||||
if(find_dir_in_subdirs(cgroup_cpuacct_base, NULL, found_subdir_in_dir) == -1) {
|
||||
cgroup_enable_cpuacct_stat =
|
||||
|
@ -1332,6 +1503,13 @@ static inline void find_all_cgroups() {
|
|||
error("CGROUP: disabled devices statistics.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (find_dir_in_subdirs(cgroup_unified_base, NULL, found_subdir_in_dir) == -1) {
|
||||
cgroup_unified_exist = CONFIG_BOOLEAN_NO;
|
||||
error("CGROUP: disabled unified cgroups statistics.");
|
||||
}
|
||||
}
|
||||
|
||||
// remove any non-existing cgroups
|
||||
cleanup_all_cgroups();
|
||||
|
@ -1352,6 +1530,7 @@ static inline void find_all_cgroups() {
|
|||
// check for newly added cgroups
|
||||
// and update the filenames they read
|
||||
char filename[FILENAME_MAX + 1];
|
||||
if(!cgroup_use_unified_cgroups) {
|
||||
if(unlikely(cgroup_enable_cpuacct_stat && !cg->cpuacct_stat.filename)) {
|
||||
snprintfz(filename, FILENAME_MAX, "%s%s/cpuacct.stat", cgroup_cpuacct_base, cg->id);
|
||||
if(likely(stat(filename, &buf) != -1)) {
|
||||
|
@ -1494,6 +1673,76 @@ static inline void find_all_cgroups() {
|
|||
debug(D_CGROUP, "io_queued file for cgroup '%s': '%s' does not exist.", cg->id, filename);
|
||||
}
|
||||
}
|
||||
else if(likely(cgroup_unified_exist)) {
|
||||
if(unlikely(cgroup_enable_blkio_io && !cg->io_service_bytes.filename)) {
|
||||
snprintfz(filename, FILENAME_MAX, "%s%s/io.stat", cgroup_unified_base, cg->id);
|
||||
if(likely(stat(filename, &buf) != -1)) {
|
||||
cg->io_service_bytes.filename = strdupz(filename);
|
||||
cg->io_service_bytes.enabled = cgroup_enable_blkio_io;
|
||||
debug(D_CGROUP, "io.stat filename for unified cgroup '%s': '%s'", cg->id, cg->io_service_bytes.filename);
|
||||
} else
|
||||
debug(D_CGROUP, "io.stat file for unified cgroup '%s': '%s' does not exist.", cg->id, filename);
|
||||
}
|
||||
if (unlikely(cgroup_enable_blkio_ops && !cg->io_serviced.filename)) {
|
||||
snprintfz(filename, FILENAME_MAX, "%s%s/io.stat", cgroup_unified_base, cg->id);
|
||||
if (likely(stat(filename, &buf) != -1)) {
|
||||
cg->io_serviced.filename = strdupz(filename);
|
||||
cg->io_serviced.enabled = cgroup_enable_blkio_ops;
|
||||
debug(D_CGROUP, "io.stat filename for unified cgroup '%s': '%s'", cg->id, cg->io_service_bytes.filename);
|
||||
} else
|
||||
debug(D_CGROUP, "io.stat file for unified cgroup '%s': '%s' does not exist.", cg->id, filename);
|
||||
}
|
||||
if(unlikely(cgroup_enable_cpuacct_stat && !cg->cpuacct_stat.filename)) {
|
||||
snprintfz(filename, FILENAME_MAX, "%s%s/cpu.stat", cgroup_unified_base, cg->id);
|
||||
if(likely(stat(filename, &buf) != -1)) {
|
||||
cg->cpuacct_stat.filename = strdupz(filename);
|
||||
cg->cpuacct_stat.enabled = cgroup_enable_cpuacct_stat;
|
||||
cg->filename_cpuset_cpus = NULL;
|
||||
cg->filename_cpu_cfs_period = NULL;
|
||||
cg->filename_cpu_cfs_quota = NULL;
|
||||
debug(D_CGROUP, "cpu.stat filename for unified cgroup '%s': '%s'", cg->id, cg->cpuacct_stat.filename);
|
||||
}
|
||||
else
|
||||
debug(D_CGROUP, "cpu.stat file for unified cgroup '%s': '%s' does not exist.", cg->id, filename);
|
||||
}
|
||||
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)))) {
|
||||
snprintfz(filename, FILENAME_MAX, "%s%s/memory.stat", cgroup_unified_base, cg->id);
|
||||
if(likely(stat(filename, &buf) != -1)) {
|
||||
cg->memory.filename_detailed = strdupz(filename);
|
||||
cg->memory.enabled_detailed = (cgroup_enable_detailed_memory == CONFIG_BOOLEAN_YES)?CONFIG_BOOLEAN_YES:CONFIG_BOOLEAN_AUTO;
|
||||
debug(D_CGROUP, "memory.stat filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_detailed);
|
||||
}
|
||||
else
|
||||
debug(D_CGROUP, "memory.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename);
|
||||
}
|
||||
|
||||
if(unlikely(cgroup_enable_memory && !cg->memory.filename_usage_in_bytes)) {
|
||||
snprintfz(filename, FILENAME_MAX, "%s%s/memory.current", cgroup_unified_base, cg->id);
|
||||
if(likely(stat(filename, &buf) != -1)) {
|
||||
cg->memory.filename_usage_in_bytes = strdupz(filename);
|
||||
cg->memory.enabled_usage_in_bytes = cgroup_enable_memory;
|
||||
debug(D_CGROUP, "memory.current filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_usage_in_bytes);
|
||||
snprintfz(filename, FILENAME_MAX, "%s%s/memory.max", cgroup_unified_base, cg->id);
|
||||
cg->filename_memory_limit = strdupz(filename);
|
||||
}
|
||||
else
|
||||
debug(D_CGROUP, "memory.current file for cgroup '%s': '%s' does not exist.", cg->id, filename);
|
||||
}
|
||||
|
||||
if(unlikely(cgroup_enable_swap && !cg->memory.filename_msw_usage_in_bytes)) {
|
||||
snprintfz(filename, FILENAME_MAX, "%s%s/memory.swap.current", cgroup_unified_base, cg->id);
|
||||
if(likely(stat(filename, &buf) != -1)) {
|
||||
cg->memory.filename_msw_usage_in_bytes = strdupz(filename);
|
||||
cg->memory.enabled_msw_usage_in_bytes = cgroup_enable_swap;
|
||||
snprintfz(filename, FILENAME_MAX, "%s%s/memory.swap.max", cgroup_unified_base, cg->id);
|
||||
cg->filename_memoryswap_limit = strdupz(filename);
|
||||
debug(D_CGROUP, "memory.swap.current filename for cgroup '%s': '%s'", cg->id, cg->memory.filename_msw_usage_in_bytes);
|
||||
}
|
||||
else
|
||||
debug(D_CGROUP, "memory.swap file for cgroup '%s': '%s' does not exist.", cg->id, filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug(D_CGROUP, "done searching for cgroups");
|
||||
}
|
||||
|
@ -2083,8 +2332,15 @@ void update_systemd_services_charts(
|
|||
continue;
|
||||
|
||||
if(likely(do_cpu && cg->cpuacct_stat.updated)) {
|
||||
if(unlikely(!cg->rd_cpu))
|
||||
if(unlikely(!cg->rd_cpu)){
|
||||
|
||||
|
||||
if (!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
|
||||
cg->rd_cpu = rrddim_add(st_cpu, cg->chart_id, cg->chart_title, 100, system_hz, RRD_ALGORITHM_INCREMENTAL);
|
||||
} else {
|
||||
cg->rd_cpu = rrddim_add(st_cpu, cg->chart_id, cg->chart_title, 100, 1000000, RRD_ALGORITHM_INCREMENTAL);
|
||||
}
|
||||
}
|
||||
|
||||
rrddim_set_by_pointer(st_cpu, cg->rd_cpu, cg->cpuacct_stat.user + cg->cpuacct_stat.system);
|
||||
}
|
||||
|
@ -2368,6 +2624,7 @@ static inline int update_memory_limits(char **filename, RRDSETVAR **chart_var, u
|
|||
}
|
||||
|
||||
if(*filename && *chart_var) {
|
||||
if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
|
||||
if(read_single_number_file(*filename, value)) {
|
||||
error("Cannot refresh cgroup %s memory limit by reading '%s'. Will not update its limit anymore.", cg->id, *filename);
|
||||
freez(*filename);
|
||||
|
@ -2377,6 +2634,25 @@ static inline int update_memory_limits(char **filename, RRDSETVAR **chart_var, u
|
|||
rrdsetvar_custom_chart_variable_set(*chart_var, (calculated_number)(*value / (1024 * 1024)));
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
char buffer[30 + 1];
|
||||
int ret = read_file(*filename, buffer, 30);
|
||||
if(ret) {
|
||||
error("Cannot refresh cgroup %s memory limit by reading '%s'. Will not update its limit anymore.", cg->id, *filename);
|
||||
freez(*filename);
|
||||
*filename = NULL;
|
||||
return 0;
|
||||
}
|
||||
char *s = "max\n\0";
|
||||
if(strsame(s, buffer) == 0){
|
||||
*value = UINT64_MAX;
|
||||
rrdsetvar_custom_chart_variable_set(*chart_var, (calculated_number)(*value / (1024 * 1024)));
|
||||
return 1;
|
||||
}
|
||||
*value = str2ull(buffer);
|
||||
rrdsetvar_custom_chart_variable_set(*chart_var, (calculated_number)(*value / (1024 * 1024)));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -2442,10 +2718,15 @@ void update_cgroup_charts(int update_every) {
|
|||
, update_every
|
||||
, RRDSET_TYPE_STACKED
|
||||
);
|
||||
|
||||
if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
|
||||
rrddim_add(cg->st_cpu, "user", NULL, 100, system_hz, RRD_ALGORITHM_INCREMENTAL);
|
||||
rrddim_add(cg->st_cpu, "system", NULL, 100, system_hz, RRD_ALGORITHM_INCREMENTAL);
|
||||
}
|
||||
else {
|
||||
rrddim_add(cg->st_cpu, "user", NULL, 100, 1000000, RRD_ALGORITHM_INCREMENTAL);
|
||||
rrddim_add(cg->st_cpu, "system", NULL, 100, 1000000, RRD_ALGORITHM_INCREMENTAL);
|
||||
}
|
||||
}
|
||||
else
|
||||
rrdset_next(cg->st_cpu);
|
||||
|
||||
|
@ -2585,7 +2866,7 @@ void update_cgroup_charts(int update_every) {
|
|||
, update_every
|
||||
, RRDSET_TYPE_STACKED
|
||||
);
|
||||
|
||||
if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
|
||||
rrddim_add(cg->st_mem, "cache", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
|
||||
rrddim_add(cg->st_mem, "rss", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
|
||||
|
||||
|
@ -2594,10 +2875,19 @@ void update_cgroup_charts(int update_every) {
|
|||
|
||||
rrddim_add(cg->st_mem, "rss_huge", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
|
||||
rrddim_add(cg->st_mem, "mapped_file", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
|
||||
} else {
|
||||
rrddim_add(cg->st_mem, "anon", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
|
||||
rrddim_add(cg->st_mem, "kernel_stack", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
|
||||
rrddim_add(cg->st_mem, "slab", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
|
||||
rrddim_add(cg->st_mem, "sock", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
|
||||
rrddim_add(cg->st_mem, "anon_thp", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
|
||||
rrddim_add(cg->st_mem, "file", NULL, 1, 1024 * 1024, RRD_ALGORITHM_ABSOLUTE);
|
||||
}
|
||||
}
|
||||
else
|
||||
rrdset_next(cg->st_mem);
|
||||
|
||||
if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
|
||||
rrddim_set(cg->st_mem, "cache", cg->memory.total_cache);
|
||||
rrddim_set(cg->st_mem, "rss", (cg->memory.total_rss > cg->memory.total_rss_huge)?(cg->memory.total_rss - cg->memory.total_rss_huge):0);
|
||||
|
||||
|
@ -2606,6 +2896,14 @@ void update_cgroup_charts(int update_every) {
|
|||
|
||||
rrddim_set(cg->st_mem, "rss_huge", cg->memory.total_rss_huge);
|
||||
rrddim_set(cg->st_mem, "mapped_file", cg->memory.total_mapped_file);
|
||||
} else {
|
||||
rrddim_set(cg->st_mem, "anon", cg->memory.anon);
|
||||
rrddim_set(cg->st_mem, "kernel_stack", cg->memory.kernel_stack);
|
||||
rrddim_set(cg->st_mem, "slab", cg->memory.slab);
|
||||
rrddim_set(cg->st_mem, "sock", cg->memory.sock);
|
||||
rrddim_set(cg->st_mem, "anon_thp", cg->memory.anon_thp);
|
||||
rrddim_set(cg->st_mem, "file", cg->memory.total_mapped_file);
|
||||
}
|
||||
rrdset_done(cg->st_mem);
|
||||
|
||||
if(unlikely(!cg->st_writeback)) {
|
||||
|
@ -2640,6 +2938,7 @@ void update_cgroup_charts(int update_every) {
|
|||
rrddim_set(cg->st_writeback, "writeback", cg->memory.total_writeback);
|
||||
rrdset_done(cg->st_writeback);
|
||||
|
||||
if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
|
||||
if(unlikely(!cg->st_mem_activity)) {
|
||||
snprintfz(title, CHART_TITLE_MAX, "Memory Activity for cgroup %s", cg->chart_title);
|
||||
|
||||
|
@ -2667,6 +2966,7 @@ void update_cgroup_charts(int update_every) {
|
|||
rrddim_set(cg->st_mem_activity, "pgpgin", cg->memory.total_pgpgin);
|
||||
rrddim_set(cg->st_mem_activity, "pgpgout", cg->memory.total_pgpgout);
|
||||
rrdset_done(cg->st_mem_activity);
|
||||
}
|
||||
|
||||
if(unlikely(!cg->st_pgfaults)) {
|
||||
snprintfz(title, CHART_TITLE_MAX, "Memory Page Faults for cgroup %s", cg->chart_title);
|
||||
|
@ -2723,7 +3023,11 @@ void update_cgroup_charts(int update_every) {
|
|||
rrdset_next(cg->st_mem_usage);
|
||||
|
||||
rrddim_set(cg->st_mem_usage, "ram", cg->memory.usage_in_bytes - ((cgroup_used_memory_without_cache)?cg->memory.total_cache:0));
|
||||
if(!(cg->options & CGROUP_OPTIONS_IS_UNIFIED)) {
|
||||
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);
|
||||
} else {
|
||||
rrddim_set(cg->st_mem_usage, "swap", cg->memory.msw_usage_in_bytes);
|
||||
}
|
||||
rrdset_done(cg->st_mem_usage);
|
||||
|
||||
if (likely(update_memory_limits(&cg->filename_memory_limit, &cg->chart_var_memory_limit, &cg->memory_limit, "memory_limit", cg))) {
|
||||
|
|
Loading…
Reference in New Issue