|
|
52b84b |
From 11df25536319a4c0f3276c2218054243d9ee213c Mon Sep 17 00:00:00 2001
|
|
|
52b84b |
From: Filipe Brandenburger <filbranden@google.com>
|
|
|
52b84b |
Date: Fri, 2 Nov 2018 09:21:57 -0700
|
|
|
52b84b |
Subject: [PATCH] core: add CPUQuotaPeriodSec=
|
|
|
52b84b |
|
|
|
52b84b |
This new setting allows configuration of CFS period on the CPU cgroup, instead
|
|
|
52b84b |
of using a hardcoded default of 100ms.
|
|
|
52b84b |
|
|
|
52b84b |
Tested:
|
|
|
52b84b |
- Legacy cgroup + Unified cgroup
|
|
|
52b84b |
- systemctl set-property
|
|
|
52b84b |
- systemctl show
|
|
|
52b84b |
- Confirmed that the cgroup settings (such as cpu.cfs_period_ns) were set
|
|
|
52b84b |
appropriately, including updating the CPU quota (cpu.cfs_quota_ns) when
|
|
|
52b84b |
CPUQuotaPeriodSec= is updated.
|
|
|
52b84b |
- Checked that clamping works properly when either period or (quota * period)
|
|
|
52b84b |
are below the resolution of 1ms, or if period is above the max of 1s.
|
|
|
52b84b |
|
|
|
52b84b |
(cherry picked from commit 10f28641115733c61754342d5dcbe70b083bea4b)
|
|
|
52b84b |
|
|
|
52b84b |
Resolves: #1770379
|
|
|
52b84b |
---
|
|
|
52b84b |
doc/TRANSIENT-SETTINGS.md | 1 +
|
|
|
52b84b |
man/systemd.resource-control.xml | 19 +++++++++
|
|
|
52b84b |
src/core/cgroup.c | 61 ++++++++++++++++++++++-----
|
|
|
52b84b |
src/core/cgroup.h | 3 ++
|
|
|
52b84b |
src/core/dbus-cgroup.c | 23 ++++++++++
|
|
|
52b84b |
src/core/load-fragment-gperf.gperf.m4 | 1 +
|
|
|
52b84b |
src/core/load-fragment.c | 1 +
|
|
|
52b84b |
src/shared/bus-unit-util.c | 14 ++++++
|
|
|
52b84b |
src/test/meson.build | 5 +++
|
|
|
52b84b |
src/test/test-cgroup-cpu.c | 38 +++++++++++++++++
|
|
|
52b84b |
10 files changed, 155 insertions(+), 11 deletions(-)
|
|
|
52b84b |
create mode 100644 src/test/test-cgroup-cpu.c
|
|
|
52b84b |
|
|
|
52b84b |
diff --git a/doc/TRANSIENT-SETTINGS.md b/doc/TRANSIENT-SETTINGS.md
|
|
|
52b84b |
index 23fe84e4d1..0d2d3e9065 100644
|
|
|
52b84b |
--- a/doc/TRANSIENT-SETTINGS.md
|
|
|
52b84b |
+++ b/doc/TRANSIENT-SETTINGS.md
|
|
|
52b84b |
@@ -218,6 +218,7 @@ All cgroup/resource control settings are available for transient units
|
|
|
52b84b |
✓ CPUShares=
|
|
|
52b84b |
✓ StartupCPUShares=
|
|
|
52b84b |
✓ CPUQuota=
|
|
|
52b84b |
+✓ CPUQuotaPeriodSec=
|
|
|
52b84b |
✓ AllowedCPUs=
|
|
|
52b84b |
✓ AllowedMemoryNodes=
|
|
|
52b84b |
✓ MemoryAccounting=
|
|
|
52b84b |
diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml
|
|
|
52b84b |
index b0064bf98f..cfe19a6574 100644
|
|
|
52b84b |
--- a/man/systemd.resource-control.xml
|
|
|
52b84b |
+++ b/man/systemd.resource-control.xml
|
|
|
52b84b |
@@ -231,6 +231,25 @@
|
|
|
52b84b |
</listitem>
|
|
|
52b84b |
</varlistentry>
|
|
|
52b84b |
|
|
|
52b84b |
+ <varlistentry>
|
|
|
52b84b |
+ <term><varname>CPUQuotaPeriodSec=</varname></term>
|
|
|
52b84b |
+
|
|
|
52b84b |
+ <listitem>
|
|
|
52b84b |
+ <para>Assign the duration over which the CPU time quota specified by <varname>CPUQuota=</varname> is measured.
|
|
|
52b84b |
+ Takes a time duration value in seconds, with an optional suffix such as "ms" for milliseconds (or "s" for seconds.)
|
|
|
52b84b |
+ The default setting is 100ms. The period is clamped to the range supported by the kernel, which is [1ms, 1000ms].
|
|
|
52b84b |
+ Additionally, the period is adjusted up so that the quota interval is also at least 1ms.
|
|
|
52b84b |
+ Setting <varname>CPUQuotaPeriodSec=</varname> to an empty value resets it to the default.</para>
|
|
|
52b84b |
+
|
|
|
52b84b |
+ <para>This controls the second field of <literal>cpu.max</literal> attribute on the unified control group hierarchy
|
|
|
52b84b |
+ and <literal>cpu.cfs_period_us</literal> on legacy. For details about these control group attributes, see
|
|
|
52b84b |
+ <ulink url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink> and
|
|
|
52b84b |
+ <ulink url="https://www.kernel.org/doc/Documentation/scheduler/sched-design-CFS.txt">sched-design-CFS.txt</ulink>.</para>
|
|
|
52b84b |
+
|
|
|
52b84b |
+ <para>Example: <varname>CPUQuotaPeriodSec=10ms</varname> to request that the CPU quota is measured in periods of 10ms.</para>
|
|
|
52b84b |
+ </listitem>
|
|
|
52b84b |
+ </varlistentry>
|
|
|
52b84b |
+
|
|
|
52b84b |
<varlistentry>
|
|
|
52b84b |
<term><varname>MemoryAccounting=</varname></term>
|
|
|
52b84b |
|
|
|
52b84b |
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
|
|
|
52b84b |
index 7aa7db9261..45fd64a394 100644
|
|
|
52b84b |
--- a/src/core/cgroup.c
|
|
|
52b84b |
+++ b/src/core/cgroup.c
|
|
|
52b84b |
@@ -23,7 +23,7 @@
|
|
|
52b84b |
#include "string-util.h"
|
|
|
52b84b |
#include "virt.h"
|
|
|
52b84b |
|
|
|
52b84b |
-#define CGROUP_CPU_QUOTA_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC)
|
|
|
52b84b |
+#define CGROUP_CPU_QUOTA_DEFAULT_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC)
|
|
|
52b84b |
|
|
|
52b84b |
bool manager_owns_root_cgroup(Manager *m) {
|
|
|
52b84b |
assert(m);
|
|
|
52b84b |
@@ -77,6 +77,7 @@ void cgroup_context_init(CGroupContext *c) {
|
|
|
52b84b |
.cpu_weight = CGROUP_WEIGHT_INVALID,
|
|
|
52b84b |
.startup_cpu_weight = CGROUP_WEIGHT_INVALID,
|
|
|
52b84b |
.cpu_quota_per_sec_usec = USEC_INFINITY,
|
|
|
52b84b |
+ .cpu_quota_period_usec = USEC_INFINITY,
|
|
|
52b84b |
|
|
|
52b84b |
.cpu_shares = CGROUP_CPU_SHARES_INVALID,
|
|
|
52b84b |
.startup_cpu_shares = CGROUP_CPU_SHARES_INVALID,
|
|
|
52b84b |
@@ -190,6 +191,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
|
|
|
52b84b |
CGroupDeviceAllow *a;
|
|
|
52b84b |
IPAddressAccessItem *iaai;
|
|
|
52b84b |
char u[FORMAT_TIMESPAN_MAX];
|
|
|
52b84b |
+ char v[FORMAT_TIMESPAN_MAX];
|
|
|
52b84b |
|
|
|
52b84b |
assert(c);
|
|
|
52b84b |
assert(f);
|
|
|
52b84b |
@@ -211,6 +213,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
|
|
|
52b84b |
"%sCPUShares=%" PRIu64 "\n"
|
|
|
52b84b |
"%sStartupCPUShares=%" PRIu64 "\n"
|
|
|
52b84b |
"%sCPUQuotaPerSecSec=%s\n"
|
|
|
52b84b |
+ "%sCPUQuotaPeriodSec=%s\n"
|
|
|
52b84b |
"%sAllowedCPUs=%s\n"
|
|
|
52b84b |
"%sAllowedMemoryNodes=%s\n"
|
|
|
52b84b |
"%sIOWeight=%" PRIu64 "\n"
|
|
|
52b84b |
@@ -236,6 +239,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
|
|
|
52b84b |
prefix, c->cpu_shares,
|
|
|
52b84b |
prefix, c->startup_cpu_shares,
|
|
|
52b84b |
prefix, format_timespan(u, sizeof(u), c->cpu_quota_per_sec_usec, 1),
|
|
|
52b84b |
+ prefix, format_timespan(v, sizeof(v), c->cpu_quota_period_usec, 1),
|
|
|
52b84b |
prefix, cpuset_cpus,
|
|
|
52b84b |
prefix, cpuset_mems,
|
|
|
52b84b |
prefix, c->io_weight,
|
|
|
52b84b |
@@ -515,7 +519,40 @@ static uint64_t cgroup_context_cpu_shares(CGroupContext *c, ManagerState state)
|
|
|
52b84b |
return CGROUP_CPU_SHARES_DEFAULT;
|
|
|
52b84b |
}
|
|
|
52b84b |
|
|
|
52b84b |
-static void cgroup_apply_unified_cpu_config(Unit *u, uint64_t weight, uint64_t quota) {
|
|
|
52b84b |
+usec_t cgroup_cpu_adjust_period(usec_t period, usec_t quota, usec_t resolution, usec_t max_period) {
|
|
|
52b84b |
+ /* kernel uses a minimum resolution of 1ms, so both period and (quota * period)
|
|
|
52b84b |
+ * need to be higher than that boundary. quota is specified in USecPerSec.
|
|
|
52b84b |
+ * Additionally, period must be at most max_period. */
|
|
|
52b84b |
+ assert(quota > 0);
|
|
|
52b84b |
+
|
|
|
52b84b |
+ return MIN(MAX3(period, resolution, resolution * USEC_PER_SEC / quota), max_period);
|
|
|
52b84b |
+}
|
|
|
52b84b |
+
|
|
|
52b84b |
+static usec_t cgroup_cpu_adjust_period_and_log(Unit *u, usec_t period, usec_t quota) {
|
|
|
52b84b |
+ usec_t new_period;
|
|
|
52b84b |
+
|
|
|
52b84b |
+ if (quota == USEC_INFINITY)
|
|
|
52b84b |
+ /* Always use default period for infinity quota. */
|
|
|
52b84b |
+ return CGROUP_CPU_QUOTA_DEFAULT_PERIOD_USEC;
|
|
|
52b84b |
+
|
|
|
52b84b |
+ if (period == USEC_INFINITY)
|
|
|
52b84b |
+ /* Default period was requested. */
|
|
|
52b84b |
+ period = CGROUP_CPU_QUOTA_DEFAULT_PERIOD_USEC;
|
|
|
52b84b |
+
|
|
|
52b84b |
+ /* Clamp to interval [1ms, 1s] */
|
|
|
52b84b |
+ new_period = cgroup_cpu_adjust_period(period, quota, USEC_PER_MSEC, USEC_PER_SEC);
|
|
|
52b84b |
+
|
|
|
52b84b |
+ if (new_period != period) {
|
|
|
52b84b |
+ char v[FORMAT_TIMESPAN_MAX];
|
|
|
52b84b |
+ log_unit_full(u, LOG_WARNING, 0,
|
|
|
52b84b |
+ "Clamping CPU interval for cpu.max: period is now %s",
|
|
|
52b84b |
+ format_timespan(v, sizeof(v), new_period, 1));
|
|
|
52b84b |
+ }
|
|
|
52b84b |
+
|
|
|
52b84b |
+ return new_period;
|
|
|
52b84b |
+}
|
|
|
52b84b |
+
|
|
|
52b84b |
+static void cgroup_apply_unified_cpu_config(Unit *u, uint64_t weight, uint64_t quota, usec_t period) {
|
|
|
52b84b |
char buf[MAX(DECIMAL_STR_MAX(uint64_t) + 1, (DECIMAL_STR_MAX(usec_t) + 1) * 2)];
|
|
|
52b84b |
int r;
|
|
|
52b84b |
|
|
|
52b84b |
@@ -525,11 +562,12 @@ static void cgroup_apply_unified_cpu_config(Unit *u, uint64_t weight, uint64_t q
|
|
|
52b84b |
log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
|
|
|
52b84b |
"Failed to set cpu.weight: %m");
|
|
|
52b84b |
|
|
|
52b84b |
+ period = cgroup_cpu_adjust_period_and_log(u, period, quota);
|
|
|
52b84b |
if (quota != USEC_INFINITY)
|
|
|
52b84b |
xsprintf(buf, USEC_FMT " " USEC_FMT "\n",
|
|
|
52b84b |
- quota * CGROUP_CPU_QUOTA_PERIOD_USEC / USEC_PER_SEC, CGROUP_CPU_QUOTA_PERIOD_USEC);
|
|
|
52b84b |
+ MAX(quota * period / USEC_PER_SEC, USEC_PER_MSEC), period);
|
|
|
52b84b |
else
|
|
|
52b84b |
- xsprintf(buf, "max " USEC_FMT "\n", CGROUP_CPU_QUOTA_PERIOD_USEC);
|
|
|
52b84b |
+ xsprintf(buf, "max " USEC_FMT "\n", period);
|
|
|
52b84b |
|
|
|
52b84b |
r = cg_set_attribute("cpu", u->cgroup_path, "cpu.max", buf);
|
|
|
52b84b |
|
|
|
52b84b |
@@ -538,7 +576,7 @@ static void cgroup_apply_unified_cpu_config(Unit *u, uint64_t weight, uint64_t q
|
|
|
52b84b |
"Failed to set cpu.max: %m");
|
|
|
52b84b |
}
|
|
|
52b84b |
|
|
|
52b84b |
-static void cgroup_apply_legacy_cpu_config(Unit *u, uint64_t shares, uint64_t quota) {
|
|
|
52b84b |
+static void cgroup_apply_legacy_cpu_config(Unit *u, uint64_t shares, uint64_t quota, usec_t period) {
|
|
|
52b84b |
char buf[MAX(DECIMAL_STR_MAX(uint64_t), DECIMAL_STR_MAX(usec_t)) + 1];
|
|
|
52b84b |
int r;
|
|
|
52b84b |
|
|
|
52b84b |
@@ -548,20 +586,21 @@ static void cgroup_apply_legacy_cpu_config(Unit *u, uint64_t shares, uint64_t qu
|
|
|
52b84b |
log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
|
|
|
52b84b |
"Failed to set cpu.shares: %m");
|
|
|
52b84b |
|
|
|
52b84b |
- xsprintf(buf, USEC_FMT "\n", CGROUP_CPU_QUOTA_PERIOD_USEC);
|
|
|
52b84b |
+ period = cgroup_cpu_adjust_period_and_log(u, period, quota);
|
|
|
52b84b |
+
|
|
|
52b84b |
+ xsprintf(buf, USEC_FMT "\n", period);
|
|
|
52b84b |
r = cg_set_attribute("cpu", u->cgroup_path, "cpu.cfs_period_us", buf);
|
|
|
52b84b |
if (r < 0)
|
|
|
52b84b |
log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
|
|
|
52b84b |
"Failed to set cpu.cfs_period_us: %m");
|
|
|
52b84b |
|
|
|
52b84b |
if (quota != USEC_INFINITY) {
|
|
|
52b84b |
- xsprintf(buf, USEC_FMT "\n", quota * CGROUP_CPU_QUOTA_PERIOD_USEC / USEC_PER_SEC);
|
|
|
52b84b |
- r = cg_set_attribute("cpu", u->cgroup_path, "cpu.cfs_quota_us", buf);
|
|
|
52b84b |
- } else
|
|
|
52b84b |
+ xsprintf(buf, USEC_FMT "\n", MAX(quota * period / USEC_PER_SEC, USEC_PER_MSEC));
|
|
|
52b84b |
r = cg_set_attribute("cpu", u->cgroup_path, "cpu.cfs_quota_us", "-1");
|
|
|
52b84b |
if (r < 0)
|
|
|
52b84b |
log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
|
|
|
52b84b |
"Failed to set cpu.cfs_quota_us: %m");
|
|
|
52b84b |
+ }
|
|
|
52b84b |
}
|
|
|
52b84b |
|
|
|
52b84b |
static uint64_t cgroup_cpu_shares_to_weight(uint64_t shares) {
|
|
|
52b84b |
@@ -815,7 +854,7 @@ static void cgroup_context_apply(
|
|
|
52b84b |
} else
|
|
|
52b84b |
weight = CGROUP_WEIGHT_DEFAULT;
|
|
|
52b84b |
|
|
|
52b84b |
- cgroup_apply_unified_cpu_config(u, weight, c->cpu_quota_per_sec_usec);
|
|
|
52b84b |
+ cgroup_apply_unified_cpu_config(u, weight, c->cpu_quota_per_sec_usec, c->cpu_quota_period_usec);
|
|
|
52b84b |
} else {
|
|
|
52b84b |
uint64_t shares;
|
|
|
52b84b |
|
|
|
52b84b |
@@ -831,7 +870,7 @@ static void cgroup_context_apply(
|
|
|
52b84b |
else
|
|
|
52b84b |
shares = CGROUP_CPU_SHARES_DEFAULT;
|
|
|
52b84b |
|
|
|
52b84b |
- cgroup_apply_legacy_cpu_config(u, shares, c->cpu_quota_per_sec_usec);
|
|
|
52b84b |
+ cgroup_apply_legacy_cpu_config(u, shares, c->cpu_quota_per_sec_usec, c->cpu_quota_period_usec);
|
|
|
52b84b |
}
|
|
|
52b84b |
}
|
|
|
52b84b |
|
|
|
52b84b |
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
|
|
|
52b84b |
index f7365b4c46..2ba57d3ded 100644
|
|
|
52b84b |
--- a/src/core/cgroup.h
|
|
|
52b84b |
+++ b/src/core/cgroup.h
|
|
|
52b84b |
@@ -84,6 +84,7 @@ struct CGroupContext {
|
|
|
52b84b |
uint64_t cpu_weight;
|
|
|
52b84b |
uint64_t startup_cpu_weight;
|
|
|
52b84b |
usec_t cpu_quota_per_sec_usec;
|
|
|
52b84b |
+ usec_t cpu_quota_period_usec;
|
|
|
52b84b |
|
|
|
52b84b |
CPUSet cpuset_cpus;
|
|
|
52b84b |
CPUSet cpuset_mems;
|
|
|
52b84b |
@@ -136,6 +137,8 @@ typedef enum CGroupIPAccountingMetric {
|
|
|
52b84b |
typedef struct Unit Unit;
|
|
|
52b84b |
typedef struct Manager Manager;
|
|
|
52b84b |
|
|
|
52b84b |
+usec_t cgroup_cpu_adjust_period(usec_t period, usec_t quota, usec_t resolution, usec_t max_period);
|
|
|
52b84b |
+
|
|
|
52b84b |
void cgroup_context_init(CGroupContext *c);
|
|
|
52b84b |
void cgroup_context_done(CGroupContext *c);
|
|
|
52b84b |
void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix);
|
|
|
52b84b |
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
|
|
|
52b84b |
index a1d3014d61..c8b918e45d 100644
|
|
|
52b84b |
--- a/src/core/dbus-cgroup.c
|
|
|
52b84b |
+++ b/src/core/dbus-cgroup.c
|
|
|
52b84b |
@@ -334,6 +334,7 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
|
|
|
52b84b |
SD_BUS_PROPERTY("CPUShares", "t", NULL, offsetof(CGroupContext, cpu_shares), 0),
|
|
|
52b84b |
SD_BUS_PROPERTY("StartupCPUShares", "t", NULL, offsetof(CGroupContext, startup_cpu_shares), 0),
|
|
|
52b84b |
SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0),
|
|
|
52b84b |
+ SD_BUS_PROPERTY("CPUQuotaPeriodUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_period_usec), 0),
|
|
|
52b84b |
SD_BUS_PROPERTY("AllowedCPUs", "ay", property_get_cpuset, offsetof(CGroupContext, cpuset_cpus), 0),
|
|
|
52b84b |
SD_BUS_PROPERTY("AllowedMemoryNodes", "ay", property_get_cpuset, offsetof(CGroupContext, cpuset_mems), 0),
|
|
|
52b84b |
SD_BUS_PROPERTY("IOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, io_accounting), 0),
|
|
|
52b84b |
@@ -725,6 +726,28 @@ int bus_cgroup_set_property(
|
|
|
52b84b |
|
|
|
52b84b |
return 1;
|
|
|
52b84b |
|
|
|
52b84b |
+ } else if (streq(name, "CPUQuotaPeriodUSec")) {
|
|
|
52b84b |
+ uint64_t u64;
|
|
|
52b84b |
+
|
|
|
52b84b |
+ r = sd_bus_message_read(message, "t", &u64);
|
|
|
52b84b |
+ if (r < 0)
|
|
|
52b84b |
+ return r;
|
|
|
52b84b |
+
|
|
|
52b84b |
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
|
|
52b84b |
+ c->cpu_quota_period_usec = u64;
|
|
|
52b84b |
+ unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
|
|
|
52b84b |
+ if (c->cpu_quota_period_usec == USEC_INFINITY)
|
|
|
52b84b |
+ unit_write_setting(u, flags, "CPUQuotaPeriodSec", "CPUQuotaPeriodSec=");
|
|
|
52b84b |
+ else {
|
|
|
52b84b |
+ char v[FORMAT_TIMESPAN_MAX];
|
|
|
52b84b |
+ unit_write_settingf(u, flags, "CPUQuotaPeriodSec",
|
|
|
52b84b |
+ "CPUQuotaPeriodSec=%s",
|
|
|
52b84b |
+ format_timespan(v, sizeof(v), c->cpu_quota_period_usec, 1));
|
|
|
52b84b |
+ }
|
|
|
52b84b |
+ }
|
|
|
52b84b |
+
|
|
|
52b84b |
+ return 1;
|
|
|
52b84b |
+
|
|
|
52b84b |
} else if (STR_IN_SET(name, "AllowedCPUs", "AllowedMemoryNodes")) {
|
|
|
52b84b |
const void *a;
|
|
|
52b84b |
size_t n;
|
|
|
52b84b |
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
|
|
|
52b84b |
index 23879c001f..4defa82ac1 100644
|
|
|
52b84b |
--- a/src/core/load-fragment-gperf.gperf.m4
|
|
|
52b84b |
+++ b/src/core/load-fragment-gperf.gperf.m4
|
|
|
52b84b |
@@ -169,6 +169,7 @@ $1.StartupCPUWeight, config_parse_cg_weight, 0,
|
|
|
52b84b |
$1.CPUShares, config_parse_cpu_shares, 0, offsetof($1, cgroup_context.cpu_shares)
|
|
|
52b84b |
$1.StartupCPUShares, config_parse_cpu_shares, 0, offsetof($1, cgroup_context.startup_cpu_shares)
|
|
|
52b84b |
$1.CPUQuota, config_parse_cpu_quota, 0, offsetof($1, cgroup_context)
|
|
|
52b84b |
+$1.CPUQuotaPeriodSec, config_parse_sec_def_infinity, 0, offsetof($1, cgroup_context.cpu_quota_period_usec)
|
|
|
52b84b |
$1.MemoryAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.memory_accounting)
|
|
|
52b84b |
$1.MemoryLow, config_parse_memory_limit, 0, offsetof($1, cgroup_context)
|
|
|
52b84b |
$1.MemoryHigh, config_parse_memory_limit, 0, offsetof($1, cgroup_context)
|
|
|
52b84b |
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
|
|
|
52b84b |
index 1e22013b75..762b106007 100644
|
|
|
52b84b |
--- a/src/core/load-fragment.c
|
|
|
52b84b |
+++ b/src/core/load-fragment.c
|
|
|
52b84b |
@@ -55,6 +55,7 @@
|
|
|
52b84b |
#include "unit-name.h"
|
|
|
52b84b |
#include "unit-printf.h"
|
|
|
52b84b |
#include "user-util.h"
|
|
|
52b84b |
+#include "time-util.h"
|
|
|
52b84b |
#include "web-util.h"
|
|
|
52b84b |
|
|
|
52b84b |
static int supported_socket_protocol_from_string(const char *s) {
|
|
|
52b84b |
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
|
|
|
52b84b |
index 3c1ecf2027..ec45d6f86d 100644
|
|
|
52b84b |
--- a/src/shared/bus-unit-util.c
|
|
|
52b84b |
+++ b/src/shared/bus-unit-util.c
|
|
|
52b84b |
@@ -480,6 +480,20 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
|
|
|
52b84b |
return 1;
|
|
|
52b84b |
}
|
|
|
52b84b |
|
|
|
52b84b |
+ if (streq(field, "CPUQuotaPeriodSec")) {
|
|
|
52b84b |
+ usec_t u = USEC_INFINITY;
|
|
|
52b84b |
+
|
|
|
52b84b |
+ r = parse_sec_def_infinity(eq, &u);
|
|
|
52b84b |
+ if (r < 0)
|
|
|
52b84b |
+ return log_error_errno(r, "CPU quota period '%s' invalid.", eq);
|
|
|
52b84b |
+
|
|
|
52b84b |
+ r = sd_bus_message_append(m, "(sv)", "CPUQuotaPeriodUSec", "t", u);
|
|
|
52b84b |
+ if (r < 0)
|
|
|
52b84b |
+ return bus_log_create_error(r);
|
|
|
52b84b |
+
|
|
|
52b84b |
+ return 1;
|
|
|
52b84b |
+ }
|
|
|
52b84b |
+
|
|
|
52b84b |
if (streq(field, "DeviceAllow")) {
|
|
|
52b84b |
|
|
|
52b84b |
if (isempty(eq))
|
|
|
52b84b |
diff --git a/src/test/meson.build b/src/test/meson.build
|
|
|
52b84b |
index ead000e30c..22264d034c 100644
|
|
|
52b84b |
--- a/src/test/meson.build
|
|
|
52b84b |
+++ b/src/test/meson.build
|
|
|
52b84b |
@@ -513,6 +513,11 @@ tests += [
|
|
|
52b84b |
[],
|
|
|
52b84b |
'', 'manual'],
|
|
|
52b84b |
|
|
|
52b84b |
+ [['src/test/test-cgroup-cpu.c'],
|
|
|
52b84b |
+ [libcore,
|
|
|
52b84b |
+ libshared],
|
|
|
52b84b |
+ []],
|
|
|
52b84b |
+
|
|
|
52b84b |
[['src/test/test-cgroup-mask.c',
|
|
|
52b84b |
'src/test/test-helper.c'],
|
|
|
52b84b |
[libcore,
|
|
|
52b84b |
diff --git a/src/test/test-cgroup-cpu.c b/src/test/test-cgroup-cpu.c
|
|
|
52b84b |
new file mode 100644
|
|
|
52b84b |
index 0000000000..a445acc955
|
|
|
52b84b |
--- /dev/null
|
|
|
52b84b |
+++ b/src/test/test-cgroup-cpu.c
|
|
|
52b84b |
@@ -0,0 +1,38 @@
|
|
|
52b84b |
+/* SPDX-License-Identifier: LGPL-2.1+ */
|
|
|
52b84b |
+
|
|
|
52b84b |
+#include "cgroup.h"
|
|
|
52b84b |
+#include "log.h"
|
|
|
52b84b |
+
|
|
|
52b84b |
+static void test_cgroup_cpu_adjust_period(void) {
|
|
|
52b84b |
+ log_info("/* %s */", __func__);
|
|
|
52b84b |
+
|
|
|
52b84b |
+ /* Period 1ms, quota 40% -> Period 2.5ms */
|
|
|
52b84b |
+ assert_se(2500 == cgroup_cpu_adjust_period(USEC_PER_MSEC, 400 * USEC_PER_MSEC, USEC_PER_MSEC, USEC_PER_SEC));
|
|
|
52b84b |
+ /* Period 10ms, quota 10% -> keep. */
|
|
|
52b84b |
+ assert_se(10 * USEC_PER_MSEC == cgroup_cpu_adjust_period(10 * USEC_PER_MSEC, 100 * USEC_PER_MSEC, USEC_PER_MSEC, USEC_PER_SEC));
|
|
|
52b84b |
+ /* Period 1ms, quota 1000% -> keep. */
|
|
|
52b84b |
+ assert_se(USEC_PER_MSEC == cgroup_cpu_adjust_period(USEC_PER_MSEC, 10000 * USEC_PER_MSEC, USEC_PER_MSEC, USEC_PER_SEC));
|
|
|
52b84b |
+ /* Period 100ms, quota 30% -> keep. */
|
|
|
52b84b |
+ assert_se(100 * USEC_PER_MSEC == cgroup_cpu_adjust_period(100 * USEC_PER_MSEC, 300 * USEC_PER_MSEC, USEC_PER_MSEC, USEC_PER_SEC));
|
|
|
52b84b |
+ /* Period 5s, quota 40% -> adjust to 1s. */
|
|
|
52b84b |
+ assert_se(USEC_PER_SEC == cgroup_cpu_adjust_period(5 * USEC_PER_SEC, 400 * USEC_PER_MSEC, USEC_PER_MSEC, USEC_PER_SEC));
|
|
|
52b84b |
+ /* Period 2s, quota 250% -> adjust to 1s. */
|
|
|
52b84b |
+ assert_se(USEC_PER_SEC == cgroup_cpu_adjust_period(2 * USEC_PER_SEC, 2500 * USEC_PER_MSEC, USEC_PER_MSEC, USEC_PER_SEC));
|
|
|
52b84b |
+ /* Period 10us, quota 5,000,000% -> adjust to 1ms. */
|
|
|
52b84b |
+ assert_se(USEC_PER_MSEC == cgroup_cpu_adjust_period(10, 50000000 * USEC_PER_MSEC, USEC_PER_MSEC, USEC_PER_SEC));
|
|
|
52b84b |
+ /* Period 10ms, quota 50,000% -> keep. */
|
|
|
52b84b |
+ assert_se(10 * USEC_PER_MSEC == cgroup_cpu_adjust_period(10 * USEC_PER_MSEC, 500000 * USEC_PER_MSEC, USEC_PER_MSEC, USEC_PER_SEC));
|
|
|
52b84b |
+ /* Period 10ms, quota 1% -> adjust to 100ms. */
|
|
|
52b84b |
+ assert_se(100 * USEC_PER_MSEC == cgroup_cpu_adjust_period(10 * USEC_PER_MSEC, 10 * USEC_PER_MSEC, USEC_PER_MSEC, USEC_PER_SEC));
|
|
|
52b84b |
+ /* Period 10ms, quota .001% -> adjust to 1s. */
|
|
|
52b84b |
+ assert_se(1 * USEC_PER_SEC == cgroup_cpu_adjust_period(10 * USEC_PER_MSEC, 10, USEC_PER_MSEC, USEC_PER_SEC));
|
|
|
52b84b |
+ /* Period 0ms, quota 200% -> adjust to 1ms. */
|
|
|
52b84b |
+ assert_se(1 * USEC_PER_MSEC == cgroup_cpu_adjust_period(0, 2 * USEC_PER_SEC, USEC_PER_MSEC, USEC_PER_SEC));
|
|
|
52b84b |
+ /* Period 0ms, quota 40% -> adjust to 2.5ms. */
|
|
|
52b84b |
+ assert_se(2500 == cgroup_cpu_adjust_period(0, 400 * USEC_PER_MSEC, USEC_PER_MSEC, USEC_PER_SEC));
|
|
|
52b84b |
+}
|
|
|
52b84b |
+
|
|
|
52b84b |
+int main(int argc, char *argv[]) {
|
|
|
52b84b |
+ test_cgroup_cpu_adjust_period();
|
|
|
52b84b |
+ return 0;
|
|
|
52b84b |
+}
|