From f3743190bb46f164de6628a8e79809571d224f5f Mon Sep 17 00:00:00 2001 From: Xunlei Pang Date: Mon, 23 Nov 2020 14:17:09 +0800 Subject: [PATCH 2421/2944] alinux: cpuinfo: Add cpuinfo support of cpu quota and cpu.shares to #31381921 lxcfs supports rich container cpuinfo from cpu quota, also sigma cpushare has the requirement of getting cpuinfo from cpu.shares. Thus, introduce new knobs to support these: /proc/sys/kernel/rich_container_cpuinfo_source - 0 uses cpu quota "quota/period" by default. It will fall back to use cpuset.cpus if quota not set. - 1 uses cpuset.cpus. - 2 uses cpushare "cpu.shares/1024" (1024 can be configured below) /proc/sys/kernel/rich_container_cpuinfo_sharesbase - when rich_container_cpuinfo_source is 2, this is the divisor. Note that, after faking cpuinfo in dockers, it's impossible to make /proc/stat match them accordingly, but we only care about the following stats not /proc/stat: /proc/cpuinfo, sysfs online and /proc/meminfo Reviewed-by: Alex Shi Signed-off-by: Xunlei Pang --- drivers/base/cpu.c | 2 +- include/linux/pid_namespace.h | 3 ++ include/linux/sched.h | 7 ++++- kernel/sched/cpuacct.c | 72 ++++++++++++++++++++++++++++++++++++++++++- kernel/sched/sched.h | 5 +++ kernel/sysctl.c | 18 ++++++++++- 6 files changed, 103 insertions(+), 4 deletions(-) diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 73f588e..6e7ba8b 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -229,7 +229,7 @@ static ssize_t show_cpus_attr(struct device *dev, rcu_read_unlock(); if (rich_container && !strcmp(attr->attr.name, "online")) - cpuset_cpus_allowed(scenario, &cpuset_allowed); + rich_container_get_cpus(scenario, &cpuset_allowed); else cpumask_copy(&cpuset_allowed, ca->map); diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h index 4d3751a..bf10188 100644 --- a/include/linux/pid_namespace.h +++ b/include/linux/pid_namespace.h @@ -103,6 +103,9 @@ static inline int reboot_pid_ns(struct pid_namespace *pid_ns, int cmd) #ifdef CONFIG_RICH_CONTAINER extern int sysctl_rich_container_enable; extern int sysctl_rich_container_source; +extern int sysctl_rich_container_cpuinfo_source; +extern unsigned int sysctl_rich_container_cpuinfo_sharesbase; + static inline bool in_rich_container(struct task_struct *tsk) { if (sysctl_rich_container_enable == 0) diff --git a/include/linux/sched.h b/include/linux/sched.h index adc53a2..cf41ea0 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -2010,13 +2010,18 @@ struct cpuacct_usage_result { bool child_cpuacct(struct task_struct *tsk); bool check_rich_container(unsigned int cpu, unsigned int *index, bool *rich_container, unsigned int *total); - +void rich_container_get_cpus(struct task_struct *tsk, struct cpumask *pmask); #else static inline bool check_rich_container(unsigned int cpu, unsigned int *index, bool *rich_container, unsigned int *total) { return false; } + +static inline +void rich_container_get_cpus(struct task_struct *tsk, struct cpumask *pmask) +{ +} #endif #endif diff --git a/kernel/sched/cpuacct.c b/kernel/sched/cpuacct.c index 1abe417..13783c1 100644 --- a/kernel/sched/cpuacct.c +++ b/kernel/sched/cpuacct.c @@ -1181,7 +1181,7 @@ bool check_rich_container(unsigned int cpu, unsigned int *index, scenario = rich_container_get_scenario(); get_task_struct(scenario); read_unlock(&tasklist_lock); - cpuset_cpus_allowed(scenario, &cpuset_allowed); + rich_container_get_cpus(scenario, &cpuset_allowed); put_task_struct(scenario); *total = cpumask_weight(&cpuset_allowed); @@ -1198,4 +1198,74 @@ bool check_rich_container(unsigned int cpu, unsigned int *index, /* Hide this cpu in the container */ return true; } + +/* 0 - cpu quota; 1 - cpuset.cpus; 2 - cpu.shares */ +int sysctl_rich_container_cpuinfo_source; +/* when cpu.shares */ +unsigned int sysctl_rich_container_cpuinfo_sharesbase = 1024; + +static inline struct task_group *css_tg(struct cgroup_subsys_state *css) +{ + return css ? container_of(css, struct task_group, css) : NULL; +} + +static inline struct task_group *task_tg(struct task_struct *tsk) +{ + return css_tg(task_css(tsk, cpu_cgrp_id)); +} + +void rich_container_get_cpus(struct task_struct *tsk, struct cpumask *pmask) +{ + struct task_group *tg; + int i, cpus; + + /* cfs quota source */ + if (sysctl_rich_container_cpuinfo_source == 0) { + long quota, period; + + rcu_read_lock(); + tg = task_tg(tsk); + quota = tg_get_cfs_quota(tg); + period = tg_get_cfs_period(tg); + rcu_read_unlock(); + + if (quota == -1) { + /* Fallback to use cpuset.cpus if quota not set */ + goto cpuset_source; + } else { + /* period can't be 0 */ + cpus = (quota + period - 1) / period; + cpus = clamp(cpus, 1, (int)num_online_cpus()); + cpumask_clear(pmask); + for (i = 0; i < cpus; i++) + cpumask_set_cpu(i, pmask); + } + + return; + } + + /* cpu.shares source */ + if (sysctl_rich_container_cpuinfo_source == 2) { + unsigned long shares; + + rcu_read_lock(); + tg = task_tg(tsk); + shares = scale_load_down(tg->shares); + rcu_read_unlock(); + + /* sysctl_rich_container_cpuinfo_sharesbase can't be 0 */ + cpus = (shares + sysctl_rich_container_cpuinfo_sharesbase - 1) / + sysctl_rich_container_cpuinfo_sharesbase; + cpus = clamp(cpus, 1, (int)num_online_cpus()); + cpumask_clear(pmask); + for (i = 0; i < cpus; i++) + cpumask_set_cpu(i, pmask); + + return; + } + +cpuset_source: + /* cpuset.cpus source */ + cpuset_cpus_allowed(tsk, pmask); +} #endif diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index ac0807d..09aa58f 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -2309,3 +2309,8 @@ static inline void task_ca_update_block(struct task_struct *tsk, #ifdef CONFIG_PSI extern struct cftype cgroup_v1_psi_files[]; #endif + +#ifdef CONFIG_RICH_CONTAINER +long tg_get_cfs_quota(struct task_group *tg); +long tg_get_cfs_period(struct task_group *tg); +#endif diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 363cfea..64d07d1 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1312,7 +1312,23 @@ static int sysrq_sysctl_handler(struct ctl_table *table, int write, .extra1 = &zero, .extra2 = &one, }, - + { + .procname = "rich_container_cpuinfo_source", + .data = &sysctl_rich_container_cpuinfo_source, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &two, + }, + { + .procname = "rich_container_cpuinfo_sharesbase", + .data = &sysctl_rich_container_cpuinfo_sharesbase, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = proc_douintvec_minmax, + .extra1 = &two, + }, #endif { } }; -- 1.8.3.1