* [PATCH v4 1/2] cgroup/rstat: Tracking cgroup-level niced CPU time
2024-10-02 18:47 [PATCH v4 0/2] Exposing nice CPU usage to userspace Joshua Hahn
@ 2024-10-02 18:47 ` Joshua Hahn
2024-10-02 18:47 ` [PATCH v4 2/2] cgroup/rstat: Selftests for niced CPU statistics Joshua Hahn
2024-10-08 18:51 ` [PATCH v4 0/2] Exposing nice CPU usage to userspace Tejun Heo
2 siblings, 0 replies; 4+ messages in thread
From: Joshua Hahn @ 2024-10-02 18:47 UTC (permalink / raw)
To: tj, mkoutny
Cc: cgroups, hannes, linux-kernel, linux-kselftest, lizefan.x, shuah
From: Joshua Hahn <joshua.hahn6@gmail.com>
Cgroup-level CPU statistics currently include time spent on
user/system processes, but do not include niced CPU time (despite
already being tracked). This patch exposes niced CPU time to the
userspace, allowing users to get a better understanding of their
hardware limits and can facilitate more informed workload distribution.
A new field 'ntime' is added to struct cgroup_base_stat as opposed to
struct task_cputime to minimize footprint.
Signed-off-by: Joshua Hahn <joshua.hahnjy@gmail.com>
---
include/linux/cgroup-defs.h | 1 +
kernel/cgroup/rstat.c | 19 ++++++++++++++-----
2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
index ae04035b6cbe..a2fcb3db6c52 100644
--- a/include/linux/cgroup-defs.h
+++ b/include/linux/cgroup-defs.h
@@ -315,6 +315,7 @@ struct cgroup_base_stat {
#ifdef CONFIG_SCHED_CORE
u64 forceidle_sum;
#endif
+ u64 ntime;
};
/*
diff --git a/kernel/cgroup/rstat.c b/kernel/cgroup/rstat.c
index a06b45272411..5877974ece92 100644
--- a/kernel/cgroup/rstat.c
+++ b/kernel/cgroup/rstat.c
@@ -444,6 +444,7 @@ static void cgroup_base_stat_add(struct cgroup_base_stat *dst_bstat,
#ifdef CONFIG_SCHED_CORE
dst_bstat->forceidle_sum += src_bstat->forceidle_sum;
#endif
+ dst_bstat->ntime += src_bstat->ntime;
}
static void cgroup_base_stat_sub(struct cgroup_base_stat *dst_bstat,
@@ -455,6 +456,7 @@ static void cgroup_base_stat_sub(struct cgroup_base_stat *dst_bstat,
#ifdef CONFIG_SCHED_CORE
dst_bstat->forceidle_sum -= src_bstat->forceidle_sum;
#endif
+ dst_bstat->ntime -= src_bstat->ntime;
}
static void cgroup_base_stat_flush(struct cgroup *cgrp, int cpu)
@@ -534,8 +536,10 @@ void __cgroup_account_cputime_field(struct cgroup *cgrp,
rstatc = cgroup_base_stat_cputime_account_begin(cgrp, &flags);
switch (index) {
- case CPUTIME_USER:
case CPUTIME_NICE:
+ rstatc->bstat.ntime += delta_exec;
+ fallthrough;
+ case CPUTIME_USER:
rstatc->bstat.cputime.utime += delta_exec;
break;
case CPUTIME_SYSTEM:
@@ -591,6 +595,7 @@ static void root_cgroup_cputime(struct cgroup_base_stat *bstat)
#ifdef CONFIG_SCHED_CORE
bstat->forceidle_sum += cpustat[CPUTIME_FORCEIDLE];
#endif
+ bstat->ntime += cpustat[CPUTIME_NICE];
}
}
@@ -608,13 +613,14 @@ static void cgroup_force_idle_show(struct seq_file *seq, struct cgroup_base_stat
void cgroup_base_stat_cputime_show(struct seq_file *seq)
{
struct cgroup *cgrp = seq_css(seq)->cgroup;
- u64 usage, utime, stime;
+ u64 usage, utime, stime, ntime;
if (cgroup_parent(cgrp)) {
cgroup_rstat_flush_hold(cgrp);
usage = cgrp->bstat.cputime.sum_exec_runtime;
cputime_adjust(&cgrp->bstat.cputime, &cgrp->prev_cputime,
&utime, &stime);
+ ntime = cgrp->bstat.ntime;
cgroup_rstat_flush_release(cgrp);
} else {
/* cgrp->bstat of root is not actually used, reuse it */
@@ -622,16 +628,19 @@ void cgroup_base_stat_cputime_show(struct seq_file *seq)
usage = cgrp->bstat.cputime.sum_exec_runtime;
utime = cgrp->bstat.cputime.utime;
stime = cgrp->bstat.cputime.stime;
+ ntime = cgrp->bstat.ntime;
}
do_div(usage, NSEC_PER_USEC);
do_div(utime, NSEC_PER_USEC);
do_div(stime, NSEC_PER_USEC);
+ do_div(ntime, NSEC_PER_USEC);
seq_printf(seq, "usage_usec %llu\n"
- "user_usec %llu\n"
- "system_usec %llu\n",
- usage, utime, stime);
+ "user_usec %llu\n"
+ "system_usec %llu\n"
+ "nice_usec %llu\n",
+ usage, utime, stime, ntime);
cgroup_force_idle_show(seq, &cgrp->bstat);
}
--
2.43.5
^ permalink raw reply related [flat|nested] 4+ messages in thread* [PATCH v4 2/2] cgroup/rstat: Selftests for niced CPU statistics
2024-10-02 18:47 [PATCH v4 0/2] Exposing nice CPU usage to userspace Joshua Hahn
2024-10-02 18:47 ` [PATCH v4 1/2] cgroup/rstat: Tracking cgroup-level niced CPU time Joshua Hahn
@ 2024-10-02 18:47 ` Joshua Hahn
2024-10-08 18:51 ` [PATCH v4 0/2] Exposing nice CPU usage to userspace Tejun Heo
2 siblings, 0 replies; 4+ messages in thread
From: Joshua Hahn @ 2024-10-02 18:47 UTC (permalink / raw)
To: tj, mkoutny
Cc: cgroups, hannes, linux-kernel, linux-kselftest, lizefan.x, shuah
From: Joshua Hahn <joshua.hahn6@gmail.com>
Creates a cgroup with a single nice CPU hog process running.
fork() is called to generate the nice process because un-nicing is
not possible (see man nice(3)). If fork() was not used to generate
the CPU hog, we would run the rest of the cgroup selftest suite as a
nice process.
Signed-off-by: Joshua Hahn <joshua.hahnjy@gmail.com>
---
tools/testing/selftests/cgroup/test_cpu.c | 75 +++++++++++++++++++++++
1 file changed, 75 insertions(+)
diff --git a/tools/testing/selftests/cgroup/test_cpu.c b/tools/testing/selftests/cgroup/test_cpu.c
index dad2ed82f3ef..201ce14cb422 100644
--- a/tools/testing/selftests/cgroup/test_cpu.c
+++ b/tools/testing/selftests/cgroup/test_cpu.c
@@ -8,6 +8,7 @@
#include <pthread.h>
#include <stdio.h>
#include <time.h>
+#include <unistd.h>
#include "../kselftest.h"
#include "cgroup_util.h"
@@ -229,6 +230,79 @@ static int test_cpucg_stats(const char *root)
return ret;
}
+/*
+ * Creates a nice process that consumes CPU and checks that the elapsed
+ * usertime in the cgroup is close to the expected time.
+ */
+static int test_cpucg_nice(const char *root)
+{
+ int ret = KSFT_FAIL;
+ int status;
+ long user_usec, nice_usec;
+ long usage_seconds = 2;
+ long expected_nice_usec = usage_seconds * USEC_PER_SEC;
+ char *cpucg;
+ pid_t pid;
+
+ cpucg = cg_name(root, "cpucg_test");
+ if (!cpucg)
+ goto cleanup;
+
+ if (cg_create(cpucg))
+ goto cleanup;
+
+ user_usec = cg_read_key_long(cpucg, "cpu.stat", "user_usec");
+ nice_usec = cg_read_key_long(cpucg, "cpu.stat", "nice_usec");
+ if (nice_usec == -1)
+ ret = KSFT_SKIP;
+ if (user_usec != 0 || nice_usec != 0)
+ goto cleanup;
+
+ /*
+ * We fork here to create a new process that can be niced without
+ * polluting the nice value of other selftests
+ */
+ pid = fork();
+ if (pid < 0) {
+ goto cleanup;
+ } else if (pid == 0) {
+ struct cpu_hog_func_param param = {
+ .nprocs = 1,
+ .ts = {
+ .tv_sec = usage_seconds,
+ .tv_nsec = 0,
+ },
+ .clock_type = CPU_HOG_CLOCK_PROCESS,
+ };
+ char buf[64];
+ snprintf(buf, sizeof(buf), "%d", getpid());
+ if (cg_write(cpucg, "cgroup.procs", buf))
+ goto cleanup;
+
+ /* Try to keep niced CPU usage as constrained to hog_cpu as possible */
+ nice(1);
+ hog_cpus_timed(cpucg, param);
+ exit(0);
+ } else {
+ waitpid(pid, &status, 0);
+ if (!WIFEXITED(status))
+ goto cleanup;
+
+ user_usec = cg_read_key_long(cpucg, "cpu.stat", "user_usec");
+ nice_usec = cg_read_key_long(cpucg, "cpu.stat", "nice_usec");
+ if (!values_close(nice_usec, expected_nice_usec, 1))
+ goto cleanup;
+
+ ret = KSFT_PASS;
+ }
+
+cleanup:
+ cg_destroy(cpucg);
+ free(cpucg);
+
+ return ret;
+}
+
static int
run_cpucg_weight_test(
const char *root,
@@ -686,6 +760,7 @@ struct cpucg_test {
} tests[] = {
T(test_cpucg_subtree_control),
T(test_cpucg_stats),
+ T(test_cpucg_nice),
T(test_cpucg_weight_overprovisioned),
T(test_cpucg_weight_underprovisioned),
T(test_cpucg_nested_weight_overprovisioned),
--
2.43.5
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH v4 0/2] Exposing nice CPU usage to userspace
2024-10-02 18:47 [PATCH v4 0/2] Exposing nice CPU usage to userspace Joshua Hahn
2024-10-02 18:47 ` [PATCH v4 1/2] cgroup/rstat: Tracking cgroup-level niced CPU time Joshua Hahn
2024-10-02 18:47 ` [PATCH v4 2/2] cgroup/rstat: Selftests for niced CPU statistics Joshua Hahn
@ 2024-10-08 18:51 ` Tejun Heo
2 siblings, 0 replies; 4+ messages in thread
From: Tejun Heo @ 2024-10-08 18:51 UTC (permalink / raw)
To: Joshua Hahn
Cc: mkoutny, cgroups, hannes, linux-kernel, linux-kselftest,
lizefan.x, shuah
On Wed, Oct 02, 2024 at 11:47:15AM -0700, Joshua Hahn wrote:
> Changes in v4
> - Removed unnecessary forking from selftest.
> - Style changes in rstat.c (fallthrough & indents)
> - Fixed a selftest bug that raised false negatives, caused by
> cputime_adjust sometimes adjusting utime below ntime.
> - Reworded cover letter for clarity & motivation
> Changes in v3
> - Signed-off-by & renamed subject for clarity.
> Changes in v2
> - Edited commit messages for clarity.
Applied to cgroup/for-6.13. If there are issues, let's iterate in tree.
Thanks.
--
tejun
^ permalink raw reply [flat|nested] 4+ messages in thread