Skip to content

Commit

Permalink
core/cgroup: CPUWeight/CPUShares support idle input
Browse files Browse the repository at this point in the history
Signed-off-by: wineway <wangyuweihx@gmail.com>
  • Loading branch information
wineway authored and poettering committed Aug 11, 2022
1 parent 1cb3f4a commit c834082
Show file tree
Hide file tree
Showing 14 changed files with 99 additions and 17 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -37,3 +37,4 @@ __pycache__/
/mkosi.default.d/**/*local*.conf
/tags
.dir-locals-2.el
.vscode/
28 changes: 20 additions & 8 deletions man/systemd.resource-control.xml
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/basic/cgroup-util.h
Expand Up @@ -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)
Expand Down
20 changes: 20 additions & 0 deletions src/core/cgroup.c
Expand Up @@ -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];

Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);

Expand Down
30 changes: 29 additions & 1 deletion src/core/dbus-cgroup.c
Expand Up @@ -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);
Expand All @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions src/core/load-fragment-gperf.gperf.in
Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions src/core/load-fragment.c
Expand Up @@ -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");
Expand Down Expand Up @@ -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" },
Expand Down
1 change: 1 addition & 0 deletions src/core/load-fragment.h
Expand Up @@ -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);
Expand Down
6 changes: 4 additions & 2 deletions src/login/pam_systemd.c
Expand Up @@ -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);
Expand Down
5 changes: 4 additions & 1 deletion src/shared/bus-print-properties.c
Expand Up @@ -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) ||
Expand Down
7 changes: 5 additions & 2 deletions src/shared/bus-unit-util.c
Expand Up @@ -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);
Expand Down Expand Up @@ -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);

Expand Down
6 changes: 6 additions & 0 deletions src/shared/cgroup-setup.c
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions src/shared/cgroup-setup.h
Expand Up @@ -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);

Expand Down
4 changes: 3 additions & 1 deletion src/shared/user-record-show.c
Expand Up @@ -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)
Expand Down

0 comments on commit c834082

Please sign in to comment.