Skip to content

Commit 2e82c0d

Browse files
joshuahahnhtejun
authored andcommitted
cgroup/rstat: Selftests for niced CPU statistics
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> Signed-off-by: Tejun Heo <tj@kernel.org>
1 parent aefa398 commit 2e82c0d

1 file changed

Lines changed: 75 additions & 0 deletions

File tree

tools/testing/selftests/cgroup/test_cpu.c

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <pthread.h>
99
#include <stdio.h>
1010
#include <time.h>
11+
#include <unistd.h>
1112

1213
#include "../kselftest.h"
1314
#include "cgroup_util.h"
@@ -229,6 +230,79 @@ static int test_cpucg_stats(const char *root)
229230
return ret;
230231
}
231232

233+
/*
234+
* Creates a nice process that consumes CPU and checks that the elapsed
235+
* usertime in the cgroup is close to the expected time.
236+
*/
237+
static int test_cpucg_nice(const char *root)
238+
{
239+
int ret = KSFT_FAIL;
240+
int status;
241+
long user_usec, nice_usec;
242+
long usage_seconds = 2;
243+
long expected_nice_usec = usage_seconds * USEC_PER_SEC;
244+
char *cpucg;
245+
pid_t pid;
246+
247+
cpucg = cg_name(root, "cpucg_test");
248+
if (!cpucg)
249+
goto cleanup;
250+
251+
if (cg_create(cpucg))
252+
goto cleanup;
253+
254+
user_usec = cg_read_key_long(cpucg, "cpu.stat", "user_usec");
255+
nice_usec = cg_read_key_long(cpucg, "cpu.stat", "nice_usec");
256+
if (nice_usec == -1)
257+
ret = KSFT_SKIP;
258+
if (user_usec != 0 || nice_usec != 0)
259+
goto cleanup;
260+
261+
/*
262+
* We fork here to create a new process that can be niced without
263+
* polluting the nice value of other selftests
264+
*/
265+
pid = fork();
266+
if (pid < 0) {
267+
goto cleanup;
268+
} else if (pid == 0) {
269+
struct cpu_hog_func_param param = {
270+
.nprocs = 1,
271+
.ts = {
272+
.tv_sec = usage_seconds,
273+
.tv_nsec = 0,
274+
},
275+
.clock_type = CPU_HOG_CLOCK_PROCESS,
276+
};
277+
char buf[64];
278+
snprintf(buf, sizeof(buf), "%d", getpid());
279+
if (cg_write(cpucg, "cgroup.procs", buf))
280+
goto cleanup;
281+
282+
/* Try to keep niced CPU usage as constrained to hog_cpu as possible */
283+
nice(1);
284+
hog_cpus_timed(cpucg, param);
285+
exit(0);
286+
} else {
287+
waitpid(pid, &status, 0);
288+
if (!WIFEXITED(status))
289+
goto cleanup;
290+
291+
user_usec = cg_read_key_long(cpucg, "cpu.stat", "user_usec");
292+
nice_usec = cg_read_key_long(cpucg, "cpu.stat", "nice_usec");
293+
if (!values_close(nice_usec, expected_nice_usec, 1))
294+
goto cleanup;
295+
296+
ret = KSFT_PASS;
297+
}
298+
299+
cleanup:
300+
cg_destroy(cpucg);
301+
free(cpucg);
302+
303+
return ret;
304+
}
305+
232306
static int
233307
run_cpucg_weight_test(
234308
const char *root,
@@ -686,6 +760,7 @@ struct cpucg_test {
686760
} tests[] = {
687761
T(test_cpucg_subtree_control),
688762
T(test_cpucg_stats),
763+
T(test_cpucg_nice),
689764
T(test_cpucg_weight_overprovisioned),
690765
T(test_cpucg_weight_underprovisioned),
691766
T(test_cpucg_nested_weight_overprovisioned),

0 commit comments

Comments
 (0)