From: Joshua Hahn <joshua.ha...@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.hah...@gmail.com>
---
 tools/testing/selftests/cgroup/test_cpu.c | 72 +++++++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/tools/testing/selftests/cgroup/test_cpu.c 
b/tools/testing/selftests/cgroup/test_cpu.c
index dad2ed82f3ef..cd5550391f49 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,76 @@ 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 (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,
+               };
+
+               /* Try to keep niced CPU usage as constrained to hog_cpu as 
possible */
+               nice(1);
+               cg_run(cpucg, hog_cpus_timed, (void *)&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 (nice_usec > user_usec || user_usec <= 0)
+                       goto cleanup;
+
+               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 +757,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


Reply via email to