|
8 | 8 | #include <pthread.h> |
9 | 9 | #include <stdio.h> |
10 | 10 | #include <time.h> |
| 11 | +#include <unistd.h> |
11 | 12 |
|
12 | 13 | #include "../kselftest.h" |
13 | 14 | #include "cgroup_util.h" |
@@ -229,6 +230,79 @@ static int test_cpucg_stats(const char *root) |
229 | 230 | return ret; |
230 | 231 | } |
231 | 232 |
|
| 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 | + |
232 | 306 | static int |
233 | 307 | run_cpucg_weight_test( |
234 | 308 | const char *root, |
@@ -686,6 +760,7 @@ struct cpucg_test { |
686 | 760 | } tests[] = { |
687 | 761 | T(test_cpucg_subtree_control), |
688 | 762 | T(test_cpucg_stats), |
| 763 | + T(test_cpucg_nice), |
689 | 764 | T(test_cpucg_weight_overprovisioned), |
690 | 765 | T(test_cpucg_weight_underprovisioned), |
691 | 766 | T(test_cpucg_nested_weight_overprovisioned), |
|
0 commit comments