core/cgroup: CPUWeight/CPUShares support idle input

Signed-off-by: wineway <wangyuweihx@gmail.com>
This commit is contained in:
wineway 2022-08-06 19:14:44 +08:00 committed by Lennart Poettering
parent 1cb3f4ad6e
commit c8340822cf
14 changed files with 99 additions and 17 deletions

1
.gitignore vendored
View file

@ -37,3 +37,4 @@ __pycache__/
/mkosi.default.d/**/*local*.conf
/tags
.dir-locals-2.el
.vscode/

View file

@ -180,14 +180,26 @@
<term><varname>StartupCPUWeight=<replaceable>weight</replaceable></varname></term>
<listitem>
<para>Assign the specified CPU time weight to the processes executed, if the unified control group
hierarchy is used on the system. These options take an integer value and control the
<literal>cpu.weight</literal> control group attribute. The allowed range is 1 to 10000. Defaults to
100. For details about this control group attribute, see <ulink
url="https://docs.kernel.org/admin-guide/cgroup-v2.html">Control Groups v2</ulink>
and <ulink url="https://docs.kernel.org/scheduler/sched-design-CFS.html">CFS
Scheduler</ulink>. The available CPU time is split up among all units within one slice relative to
their CPU time weight. A higher weight means more CPU time, a lower weight means less.</para>
<para>These options accept an integer value or a the special string "idle":</para>
<itemizedlist>
<listitem>
<para>If set to an integer value, assign the specified CPU time weight to the processes executed,
if the unified control group hierarchy is used on the system. These options control the
<literal>cpu.weight</literal> control group attribute. The allowed range is 1 to 10000. Defaults to
100. For details about this control group attribute, see <ulink
url="https://docs.kernel.org/admin-guide/cgroup-v2.html">Control Groups v2</ulink>
and <ulink url="https://docs.kernel.org/scheduler/sched-design-CFS.html">CFS
Scheduler</ulink>. The available CPU time is split up among all units within one slice relative to
their CPU time weight. A higher weight means more CPU time, a lower weight means less.</para>
</listitem>
<listitem>
<para>If set to the special string "idle", mark the cgroup for "idle scheduling", which means
that it will get CPU resources only when there are no processes not marked in this way to execute in this
cgroup or its siblings. This setting corresponds to the <literal>cpu.idle</literal> cgroup attribute.</para>
<para>Note that this value only has an effect on cgroup-v2, for cgroup-v1 it is equivalent to the minimum weight.</para>
</listitem>
</itemizedlist>
<para>While <varname>StartupCPUWeight=</varname> applies to the startup and shutdown phases of the system,
<varname>CPUWeight=</varname> applies to normal runtime of the system, and if the former is not set also to

View file

@ -86,6 +86,7 @@ bool cpu_accounting_is_cheap(void);
/* Special values for all weight knobs on unified hierarchy */
#define CGROUP_WEIGHT_INVALID UINT64_MAX
#define CGROUP_WEIGHT_IDLE UINT64_C(0)
#define CGROUP_WEIGHT_MIN UINT64_C(1)
#define CGROUP_WEIGHT_MAX UINT64_C(10000)
#define CGROUP_WEIGHT_DEFAULT UINT64_C(100)

View file

@ -949,10 +949,25 @@ static usec_t cgroup_cpu_adjust_period_and_log(Unit *u, usec_t period, usec_t qu
static void cgroup_apply_unified_cpu_weight(Unit *u, uint64_t weight) {
char buf[DECIMAL_STR_MAX(uint64_t) + 2];
if (weight == CGROUP_WEIGHT_IDLE)
return;
xsprintf(buf, "%" PRIu64 "\n", weight);
(void) set_attribute_and_warn(u, "cpu", "cpu.weight", buf);
}
static void cgroup_apply_unified_cpu_idle(Unit *u, uint64_t weight) {
int r;
bool is_idle;
const char *idle_val;
is_idle = weight == CGROUP_WEIGHT_IDLE;
idle_val = one_zero(is_idle);
r = cg_set_attribute("cpu", u->cgroup_path, "cpu.idle", idle_val);
if (r < 0 && (r != -ENOENT || is_idle))
log_unit_full_errno(u, LOG_LEVEL_CGROUP_WRITE(r), r, "Failed to set '%s' attribute on '%s' to '%s': %m",
"cpu.idle", empty_to_root(u->cgroup_path), idle_val);
}
static void cgroup_apply_unified_cpu_quota(Unit *u, usec_t quota, usec_t period) {
char buf[(DECIMAL_STR_MAX(usec_t) + 1) * 2 + 1];
@ -993,6 +1008,10 @@ static uint64_t cgroup_cpu_shares_to_weight(uint64_t shares) {
}
static uint64_t cgroup_cpu_weight_to_shares(uint64_t weight) {
/* we don't support idle in cgroupv1 */
if (weight == CGROUP_WEIGHT_IDLE)
return CGROUP_CPU_SHARES_MIN;
return CLAMP(weight * CGROUP_CPU_SHARES_DEFAULT / CGROUP_WEIGHT_DEFAULT,
CGROUP_CPU_SHARES_MIN, CGROUP_CPU_SHARES_MAX);
}
@ -1398,6 +1417,7 @@ static void cgroup_context_apply(
} else
weight = CGROUP_WEIGHT_DEFAULT;
cgroup_apply_unified_cpu_idle(u, weight);
cgroup_apply_unified_cpu_weight(u, weight);
cgroup_apply_unified_cpu_quota(u, c->cpu_quota_per_sec_usec, c->cpu_quota_period_usec);

View file

@ -894,7 +894,6 @@ static int bus_cgroup_set_boolean(
}
DISABLE_WARNING_TYPE_LIMITS;
BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_weight, CGROUP_MASK_CPU, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID);
BUS_DEFINE_SET_CGROUP_WEIGHT(cpu_shares, CGROUP_MASK_CPU, CGROUP_CPU_SHARES_IS_OK, CGROUP_CPU_SHARES_INVALID);
BUS_DEFINE_SET_CGROUP_WEIGHT(io_weight, CGROUP_MASK_IO, CGROUP_WEIGHT_IS_OK, CGROUP_WEIGHT_INVALID);
BUS_DEFINE_SET_CGROUP_WEIGHT(blockio_weight, CGROUP_MASK_BLKIO, CGROUP_BLKIO_WEIGHT_IS_OK, CGROUP_BLKIO_WEIGHT_INVALID);
@ -903,6 +902,35 @@ BUS_DEFINE_SET_CGROUP_LIMIT(memory_protection, CGROUP_MASK_MEMORY, physical_memo
BUS_DEFINE_SET_CGROUP_LIMIT(swap, CGROUP_MASK_MEMORY, physical_memory_scale, 0);
REENABLE_WARNING;
static int bus_cgroup_set_cpu_weight(
Unit *u,
const char *name,
uint64_t *p,
sd_bus_message *message,
UnitWriteFlags flags,
sd_bus_error *error) {
uint64_t v;
int r;
assert(p);
r = sd_bus_message_read(message, "t", &v);
if (r < 0)
return r;
if (!CGROUP_WEIGHT_IS_OK(v) && v != CGROUP_WEIGHT_IDLE)
return sd_bus_error_setf(
error, SD_BUS_ERROR_INVALID_ARGS, "Value specified in %s is out of range", name);
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
*p = v;
unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
if (v == CGROUP_WEIGHT_INVALID)
unit_write_settingf(u, flags, name, "%s=", name);
else if (v == CGROUP_WEIGHT_IDLE)
unit_write_settingf(u, flags, name, "%s=idle", name);
else
unit_write_settingf(u, flags, name, "%s=%" PRIu64, name, v);
}
return 1;
}
static int bus_cgroup_set_tasks_max(
Unit *u,
const char *name,

View file

@ -191,8 +191,8 @@
{{type}}.AllowedMemoryNodes, config_parse_allowed_cpuset, 0, offsetof({{type}}, cgroup_context.cpuset_mems)
{{type}}.StartupAllowedMemoryNodes, config_parse_allowed_cpuset, 0, offsetof({{type}}, cgroup_context.startup_cpuset_mems)
{{type}}.CPUAccounting, config_parse_bool, 0, offsetof({{type}}, cgroup_context.cpu_accounting)
{{type}}.CPUWeight, config_parse_cg_weight, 0, offsetof({{type}}, cgroup_context.cpu_weight)
{{type}}.StartupCPUWeight, config_parse_cg_weight, 0, offsetof({{type}}, cgroup_context.startup_cpu_weight)
{{type}}.CPUWeight, config_parse_cg_cpu_weight, 0, offsetof({{type}}, cgroup_context.cpu_weight)
{{type}}.StartupCPUWeight, config_parse_cg_cpu_weight, 0, offsetof({{type}}, cgroup_context.startup_cpu_weight)
{{type}}.CPUShares, config_parse_cpu_shares, 0, offsetof({{type}}, cgroup_context.cpu_shares)
{{type}}.StartupCPUShares, config_parse_cpu_shares, 0, offsetof({{type}}, cgroup_context.startup_cpu_shares)
{{type}}.CPUQuota, config_parse_cpu_quota, 0, offsetof({{type}}, cgroup_context)

View file

@ -147,6 +147,7 @@ DEFINE_CONFIG_PARSE_ENUM(config_parse_managed_oom_preference, managed_oom_prefer
DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_ip_tos, ip_tos, int, -1, "Failed to parse IP TOS value");
DEFINE_CONFIG_PARSE_PTR(config_parse_blockio_weight, cg_blkio_weight_parse, uint64_t, "Invalid block IO weight");
DEFINE_CONFIG_PARSE_PTR(config_parse_cg_weight, cg_weight_parse, uint64_t, "Invalid weight");
DEFINE_CONFIG_PARSE_PTR(config_parse_cg_cpu_weight, cg_cpu_weight_parse, uint64_t, "Invalid CPU weight");
DEFINE_CONFIG_PARSE_PTR(config_parse_cpu_shares, cg_cpu_shares_parse, uint64_t, "Invalid CPU shares");
DEFINE_CONFIG_PARSE_PTR(config_parse_exec_mount_flags, mount_propagation_flags_from_string, unsigned long, "Failed to parse mount flag");
DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_numa_policy, mpol, int, -1, "Invalid NUMA policy type");
@ -6286,6 +6287,7 @@ void unit_dump_config_items(FILE *f) {
{ config_parse_restrict_filesystems, "FILESYSTEMS" },
{ config_parse_cpu_shares, "SHARES" },
{ config_parse_cg_weight, "WEIGHT" },
{ config_parse_cg_cpu_weight, "CPUWEIGHT" },
{ config_parse_memory_limit, "LIMIT" },
{ config_parse_device_allow, "DEVICE" },
{ config_parse_device_policy, "POLICY" },

View file

@ -78,6 +78,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_pass_environ);
CONFIG_PARSER_PROTOTYPE(config_parse_unset_environ);
CONFIG_PARSER_PROTOTYPE(config_parse_unit_slice);
CONFIG_PARSER_PROTOTYPE(config_parse_cg_weight);
CONFIG_PARSER_PROTOTYPE(config_parse_cg_cpu_weight);
CONFIG_PARSER_PROTOTYPE(config_parse_cpu_shares);
CONFIG_PARSER_PROTOTYPE(config_parse_memory_limit);
CONFIG_PARSER_PROTOTYPE(config_parse_tasks_max);

View file

@ -411,16 +411,18 @@ static int append_session_tasks_max(pam_handle_t *handle, sd_bus_message *m, con
static int append_session_cg_weight(pam_handle_t *handle, sd_bus_message *m, const char *limit, const char *field) {
uint64_t val;
int r;
bool is_cpu_weight;
is_cpu_weight = streq(field, "CPUWeight");
if (isempty(limit))
return PAM_SUCCESS;
r = cg_weight_parse(limit, &val);
r = is_cpu_weight ? cg_cpu_weight_parse(limit, &val) : cg_weight_parse(limit, &val);
if (r >= 0) {
r = sd_bus_message_append(m, "(sv)", field, "t", val);
if (r < 0)
return pam_bus_log_create_error(handle, r);
} else if (streq(field, "CPUWeight"))
} else if (is_cpu_weight)
pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.cpu_weight, ignoring: %s", limit);
else
pam_syslog(handle, LOG_WARNING, "Failed to parse systemd.io_weight, ignoring: %s", limit);

View file

@ -151,7 +151,10 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
bus_print_property_value(name, expected_value, flags, s);
} else if ((STR_IN_SET(name, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u == CGROUP_WEIGHT_INVALID) ||
} else if (STR_IN_SET(name, "CPUWeight", "StartupCPUWeight") && u == CGROUP_WEIGHT_IDLE)
bus_print_property_value(name, expected_value, flags, "idle");
else if ((STR_IN_SET(name, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u == CGROUP_WEIGHT_INVALID) ||
(STR_IN_SET(name, "CPUShares", "StartupCPUShares") && u == CGROUP_CPU_SHARES_INVALID) ||
(STR_IN_SET(name, "BlockIOWeight", "StartupBlockIOWeight") && u == CGROUP_BLKIO_WEIGHT_INVALID) ||
(STR_IN_SET(name, "MemoryCurrent", "TasksCurrent") && u == UINT64_MAX) ||

View file

@ -130,6 +130,7 @@ DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t, parse_nsec);
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse);
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse);
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse);
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_weight_parse);
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flags_from_string);
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64);
DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t, parse_mode);
@ -466,8 +467,10 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
return bus_append_parse_boolean(m, field, eq);
if (STR_IN_SET(field, "CPUWeight",
"StartupCPUWeight",
"IOWeight",
"StartupCPUWeight"))
return bus_append_cg_cpu_weight_parse(m, field, eq);
if (STR_IN_SET(field, "IOWeight",
"StartupIOWeight"))
return bus_append_cg_weight_parse(m, field, eq);

View file

@ -173,6 +173,12 @@ int cg_weight_parse(const char *s, uint64_t *ret) {
return 0;
}
int cg_cpu_weight_parse(const char *s, uint64_t *ret) {
if (streq_ptr(s, "idle"))
return *ret = CGROUP_WEIGHT_IDLE;
return cg_weight_parse(s, ret);
}
int cg_cpu_shares_parse(const char *s, uint64_t *ret) {
uint64_t u;
int r;

View file

@ -12,6 +12,7 @@ bool cg_is_legacy_wanted(void);
bool cg_is_hybrid_wanted(void);
int cg_weight_parse(const char *s, uint64_t *ret);
int cg_cpu_weight_parse(const char *s, uint64_t *ret);
int cg_cpu_shares_parse(const char *s, uint64_t *ret);
int cg_blkio_weight_parse(const char *s, uint64_t *ret);

View file

@ -276,7 +276,9 @@ void user_record_show(UserRecord *hr, bool show_full_group_info) {
if (hr->memory_max != UINT64_MAX)
printf(" Memory Max: %s\n", FORMAT_BYTES(hr->memory_max));
if (hr->cpu_weight != UINT64_MAX)
if (hr->cpu_weight == CGROUP_WEIGHT_IDLE)
printf(" CPU Weight: %s\n", "idle");
else if (hr->cpu_weight != UINT64_MAX)
printf(" CPU Weight: %" PRIu64 "\n", hr->cpu_weight);
if (hr->io_weight != UINT64_MAX)