@cryptotaxi247 / netdata-1 / commits / 79cf06f6a

feat(cgroups.plugin): add "CPU Time Relative Share" chart (#12741)

Ilya Mashchenko committed Apr 25, 2022 at 16:36 UTC 79cf06f6a016edf44dbb084f83208e00c183589e
2 files changed +98
collectors/cgroups.plugin/sys_fs_cgroup.c
+91
@@ -14,6 +14,7 @@ static long system_page_size = 4096; // system will be queried via sysconf() in
14 static int cgroup_enable_cpuacct_stat = CONFIG_BOOLEAN_AUTO;
15 static int cgroup_enable_cpuacct_usage = CONFIG_BOOLEAN_AUTO;
16 static int cgroup_enable_cpuacct_cpu_throttling = CONFIG_BOOLEAN_YES;
17 +static int cgroup_enable_cpuacct_cpu_shares = CONFIG_BOOLEAN_NO;
18 static int cgroup_enable_memory = CONFIG_BOOLEAN_AUTO;
19 static int cgroup_enable_detailed_memory = CONFIG_BOOLEAN_AUTO;
20 static int cgroup_enable_memory_failcnt = CONFIG_BOOLEAN_AUTO;
@@ -283,6 +284,7 @@ void read_cgroup_plugin_configuration() {
284 cgroup_enable_cpuacct_stat = config_get_boolean_ondemand("plugin:cgroups", "enable cpuacct stat (total CPU)", cgroup_enable_cpuacct_stat);
285 cgroup_enable_cpuacct_usage = config_get_boolean_ondemand("plugin:cgroups", "enable cpuacct usage (per core CPU)", cgroup_enable_cpuacct_usage);
286 cgroup_enable_cpuacct_cpu_throttling = config_get_boolean_ondemand("plugin:cgroups", "enable cpuacct cpu throttling", cgroup_enable_cpuacct_cpu_throttling);
287 + cgroup_enable_cpuacct_cpu_shares = config_get_boolean_ondemand("plugin:cgroups", "enable cpuacct cpu shares", cgroup_enable_cpuacct_cpu_shares);
288
289 cgroup_enable_memory = config_get_boolean_ondemand("plugin:cgroups", "enable memory", cgroup_enable_memory);
290 cgroup_enable_detailed_memory = config_get_boolean_ondemand("plugin:cgroups", "enable detailed memory", cgroup_enable_detailed_memory);
@@ -707,6 +709,17 @@ struct cpuacct_cpu_throttling {
709 unsigned long long nr_throttled_perc;
710 };
711
712 +// https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/resource_management_guide/sec-cpu#sect-cfs
713 +// https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/managing_monitoring_and_updating_the_kernel/using-cgroups-v2-to-control-distribution-of-cpu-time-for-applications_managing-monitoring-and-updating-the-kernel#proc_controlling-distribution-of-cpu-time-for-applications-by-adjusting-cpu-weight_using-cgroups-v2-to-control-distribution-of-cpu-time-for-applications
714 +struct cpuacct_cpu_shares {
715 + int updated;
716 + int enabled; // CONFIG_BOOLEAN_YES or CONFIG_BOOLEAN_AUTO
717 +
718 + char *filename;
719 +
720 + unsigned long long shares;
721 +};
722 +
723 struct cgroup_network_interface {
724 const char *host_device;
725 const char *container_device;
@@ -736,6 +749,7 @@ struct cgroup {
749 struct cpuacct_stat cpuacct_stat;
750 struct cpuacct_usage cpuacct_usage;
751 struct cpuacct_cpu_throttling cpuacct_cpu_throttling;
752 + struct cpuacct_cpu_shares cpuacct_cpu_shares;
753
754 struct memory memory;
755
@@ -760,6 +774,7 @@ struct cgroup {
774 RRDSET *st_cpu_per_core;
775 RRDSET *st_cpu_nr_throttled;
776 RRDSET *st_cpu_throttled_time;
777 + RRDSET *st_cpu_shares;
778
779 RRDSET *st_mem;
780 RRDSET *st_mem_utilization;
@@ -1031,6 +1046,24 @@ static inline void cgroup2_read_cpuacct_cpu_stat(struct cpuacct_stat *cp, struct
1046 }
1047 }
1048
1049 +static inline void cgroup_read_cpuacct_cpu_shares(struct cpuacct_cpu_shares *cp) {
1050 + if (unlikely(!cp->filename)) {
1051 + return;
1052 + }
1053 +
1054 + if (unlikely(read_single_number_file(cp->filename, &cp->shares))) {
1055 + cp->updated = 0;
1056 + cgroups_check = 1;
1057 + return;
1058 + }
1059 +
1060 + cp->updated = 1;
1061 + if (unlikely((cp->enabled == CONFIG_BOOLEAN_AUTO)) &&
1062 + (cp->shares || netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES)) {
1063 + cp->enabled = CONFIG_BOOLEAN_YES;
1064 + }
1065 +}
1066 +
1067 static inline void cgroup_read_cpuacct_usage(struct cpuacct_usage *ca) {
1068 static procfile *ff = NULL;
1069
@@ -1402,6 +1435,7 @@ static inline void cgroup_read(struct cgroup *cg) {
1435 cgroup_read_cpuacct_stat(&cg->cpuacct_stat);
1436 cgroup_read_cpuacct_usage(&cg->cpuacct_usage);
1437 cgroup_read_cpuacct_cpu_stat(&cg->cpuacct_cpu_throttling);
1438 + cgroup_read_cpuacct_cpu_shares(&cg->cpuacct_cpu_shares);
1439 cgroup_read_memory(&cg->memory, 0);
1440 cgroup_read_blkio(&cg->io_service_bytes);
1441 cgroup_read_blkio(&cg->io_serviced);
@@ -1415,6 +1449,7 @@ static inline void cgroup_read(struct cgroup *cg) {
1449 cgroup2_read_blkio(&cg->io_service_bytes, 0);
1450 cgroup2_read_blkio(&cg->io_serviced, 4);
1451 cgroup2_read_cpuacct_cpu_stat(&cg->cpuacct_stat, &cg->cpuacct_cpu_throttling);
1452 + cgroup_read_cpuacct_cpu_shares(&cg->cpuacct_cpu_shares);
1453 cgroup2_read_pressure(&cg->cpu_pressure);
1454 cgroup2_read_pressure(&cg->io_pressure);
1455 cgroup2_read_pressure(&cg->memory_pressure);
@@ -1767,6 +1802,7 @@ static inline void cgroup_free(struct cgroup *cg) {
1802 if(cg->st_cpu_per_core) rrdset_is_obsolete(cg->st_cpu_per_core);
1803 if(cg->st_cpu_nr_throttled) rrdset_is_obsolete(cg->st_cpu_nr_throttled);
1804 if(cg->st_cpu_throttled_time) rrdset_is_obsolete(cg->st_cpu_throttled_time);
1805 + if(cg->st_cpu_shares) rrdset_is_obsolete(cg->st_cpu_shares);
1806 if(cg->st_mem) rrdset_is_obsolete(cg->st_mem);
1807 if(cg->st_writeback) rrdset_is_obsolete(cg->st_writeback);
1808 if(cg->st_mem_activity) rrdset_is_obsolete(cg->st_mem_activity);
@@ -1795,6 +1831,7 @@ static inline void cgroup_free(struct cgroup *cg) {
1831 freez(cg->cpuacct_stat.filename);
1832 freez(cg->cpuacct_usage.filename);
1833 freez(cg->cpuacct_cpu_throttling.filename);
1834 + freez(cg->cpuacct_cpu_shares.filename);
1835
1836 arl_free(cg->memory.arl_base);
1837 freez(cg->memory.filename_detailed);
@@ -2021,6 +2058,18 @@ static inline void update_filenames()
2058 else
2059 debug(D_CGROUP, "cpu.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2060 }
2061 + if (unlikely(
2062 + cgroup_enable_cpuacct_cpu_shares && !cg->cpuacct_cpu_shares.filename &&
2063 + !(cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE))) {
2064 + snprintfz(filename, FILENAME_MAX, "%s%s/cpu.shares", cgroup_cpuacct_base, cg->id);
2065 + if (likely(stat(filename, &buf) != -1)) {
2066 + cg->cpuacct_cpu_shares.filename = strdupz(filename);
2067 + cg->cpuacct_cpu_shares.enabled = cgroup_enable_cpuacct_cpu_shares;
2068 + debug(
2069 + D_CGROUP, "cpu.shares filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_cpu_shares.filename);
2070 + } else
2071 + debug(D_CGROUP, "cpu.shares file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2072 + }
2073
2074 if(unlikely((cgroup_enable_detailed_memory || cgroup_used_memory) && !cg->memory.filename_detailed && (cgroup_used_memory || cgroup_enable_systemd_services_detailed_memory || !(cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE)))) {
2075 snprintfz(filename, FILENAME_MAX, "%s%s/memory.stat", cgroup_memory_base, cg->id);
@@ -2221,6 +2270,16 @@ static inline void update_filenames()
2270 else
2271 debug(D_CGROUP, "cpu.stat file for unified cgroup '%s': '%s' does not exist.", cg->id, filename);
2272 }
2273 + if (unlikely(cgroup_enable_cpuacct_cpu_shares && !cg->cpuacct_cpu_shares.filename)) {
2274 + snprintfz(filename, FILENAME_MAX, "%s%s/cpu.weight", cgroup_unified_base, cg->id);
2275 + if (likely(stat(filename, &buf) != -1)) {
2276 + cg->cpuacct_cpu_shares.filename = strdupz(filename);
2277 + cg->cpuacct_cpu_shares.enabled = cgroup_enable_cpuacct_cpu_shares;
2278 + debug(D_CGROUP, "cpu.weight filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_cpu_shares.filename);
2279 + } else
2280 + debug(D_CGROUP, "cpu.weight file for cgroup '%s': '%s' does not exist.", cg->id, filename);
2281 + }
2282 +
2283 if(unlikely((cgroup_enable_detailed_memory || cgroup_used_memory) && !cg->memory.filename_detailed && (cgroup_used_memory || cgroup_enable_systemd_services_detailed_memory || !(cg->options & CGROUP_OPTIONS_SYSTEM_SLICE_SERVICE)))) {
2284 snprintfz(filename, FILENAME_MAX, "%s%s/memory.stat", cgroup_unified_base, cg->id);
2285 if(likely(stat(filename, &buf) != -1)) {
@@ -3672,6 +3731,34 @@ void update_cgroup_charts(int update_every) {
3731 }
3732 }
3733
3734 + if (likely(cg->cpuacct_cpu_shares.updated && cg->cpuacct_cpu_shares.enabled == CONFIG_BOOLEAN_YES)) {
3735 + if (unlikely(!cg->st_cpu_shares)) {
3736 + snprintfz(title, CHART_TITLE_MAX, "CPU Time Relative Share");
3737 +
3738 + cg->st_cpu_shares = rrdset_create_localhost(
3739 + cgroup_chart_type(type, cg->chart_id, RRD_ID_LENGTH_MAX)
3740 + , "cpu_shares"
3741 + , NULL
3742 + , "cpu"
3743 + , "cgroup.cpu_shares"
3744 + , title
3745 + , "shares"
3746 + , PLUGIN_CGROUPS_NAME
3747 + , PLUGIN_CGROUPS_MODULE_CGROUPS_NAME
3748 + , cgroup_containers_chart_priority + 20
3749 + , update_every
3750 + , RRDSET_TYPE_LINE
3751 + );
3752 +
3753 + rrdset_update_labels(cg->st_cpu_shares, cg->chart_labels);
3754 + rrddim_add(cg->st_cpu_shares, "shares", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
3755 + } else {
3756 + rrdset_next(cg->st_cpu_shares);
3757 + rrddim_set(cg->st_cpu_shares, "shares", cg->cpuacct_cpu_shares.shares);
3758 + rrdset_done(cg->st_cpu_shares);
3759 + }
3760 + }
3761 +
3762 if(likely(cg->cpuacct_usage.updated && cg->cpuacct_usage.enabled == CONFIG_BOOLEAN_YES)) {
3763 char id[RRD_ID_LENGTH_MAX + 1];
3764 unsigned int i;
@@ -4461,6 +4548,10 @@ void *cgroups_main(void *ptr) {
4548
4549 struct rusage thread;
4550
4551 + if (getenv("KUBERNETES_SERVICE_HOST") != NULL && getenv("KUBERNETES_SERVICE_PORT") != NULL) {
4552 + cgroup_enable_cpuacct_cpu_shares = CONFIG_BOOLEAN_YES;
4553 + }
4554 +
4555 // when ZERO, attempt to do it
4556 int vdo_cpu_netdata = config_get_boolean("plugin:cgroups", "cgroups plugin resource charts", 1);
4557
web/gui/dashboard_info.js
+7
@@ -4026,6 +4026,13 @@ netdataDashboard.context = {
4026 'When an application has used its allotted CPU quota for a given period, it gets throttled until the next period.'
4027 },
4028
4029 + 'cgroup.cpu_shares': {
4030 + info: '<p>The weight of each group living in the same hierarchy, that translates into the amount of CPU it is expected to get. '+
4031 + 'The percentage of CPU assigned to the cgroup is the value of shares divided by the sum of all shares in all cgroups in the same level.</p>'+
4032 + '<p>For example, tasks in two cgroups that have <b>cpu.shares</b> set to 100 will receive equal CPU time, '+
4033 + 'but tasks in a cgroup that has <b>cpu.shares</b> set to 200 receive twice the CPU time of tasks in a cgroup where <b>cpu.shares</b> is set to 100.</p>'
4034 + },
4035 +
4036 'cgroup.cpu_per_core': {
4037 info: 'Total CPU utilization per core within the system-wide CPU resources.'
4038 },