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:
skrzyp1 2019-04-09 11:36:22 +02:00 committed by Vladimir Kobal
parent ab6f1c0b25
commit 6724b631de
3 changed files with 586 additions and 269 deletions

View File

@ -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)]()

View File

@ -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

View File

@ -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,16 +924,24 @@ 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);
cgroup_read_blkio(&cg->throttle_io_serviced);
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) {
@ -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))) {