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>
This commit is contained in:
parent
aefa398d93
commit
2e82c0d456
1 changed files with 75 additions and 0 deletions
|
@ -8,6 +8,7 @@
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "../kselftest.h"
|
#include "../kselftest.h"
|
||||||
#include "cgroup_util.h"
|
#include "cgroup_util.h"
|
||||||
|
@ -229,6 +230,79 @@ cleanup:
|
||||||
return ret;
|
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
|
static int
|
||||||
run_cpucg_weight_test(
|
run_cpucg_weight_test(
|
||||||
const char *root,
|
const char *root,
|
||||||
|
@ -686,6 +760,7 @@ struct cpucg_test {
|
||||||
} tests[] = {
|
} tests[] = {
|
||||||
T(test_cpucg_subtree_control),
|
T(test_cpucg_subtree_control),
|
||||||
T(test_cpucg_stats),
|
T(test_cpucg_stats),
|
||||||
|
T(test_cpucg_nice),
|
||||||
T(test_cpucg_weight_overprovisioned),
|
T(test_cpucg_weight_overprovisioned),
|
||||||
T(test_cpucg_weight_underprovisioned),
|
T(test_cpucg_weight_underprovisioned),
|
||||||
T(test_cpucg_nested_weight_overprovisioned),
|
T(test_cpucg_nested_weight_overprovisioned),
|
||||||
|
|
Loading…
Add table
Reference in a new issue