Skip to content

Commit 954bacc

Browse files
shashank-mahadasyamhtejun
authored andcommitted
selftests/cgroup: fix cpu.max tests
Current cpu.max tests (both the normal one and the nested one) are broken. They setup cpu.max with 1000 us quota and the default period (100,000 us). A cpu hog is run for a duration of 1s as per wall clock time. This corresponds to 10 periods, hence an expected usage of 10,000 us. We want the measured usage (as per cpu.stat) to be close to 10,000 us. Previously, this approximate equality test was done by `!values_close(usage_usec, expected_usage_usec, 95)`: if the absolute difference between usage_usec and expected_usage_usec is greater than 95% of their sum, then we pass. And expected_usage_usec was set to 1,000,000 us. Mathematically, this translates to the following being true for pass: |usage - expected_usage| > (usage + expected_usage)*0.95 If usage > expected_usage: usage - expected_usage > (usage + expected_usage)*0.95 0.05*usage > 1.95*expected_usage usage > 39*expected_usage = 39s If usage < expected_usage: expected_usage - usage > (usage + expected_usage)*0.95 0.05*expected_usage > 1.95*usage usage < 0.0256*expected_usage = 25,600 us Combined, Pass if usage < 25,600 us or > 39 s, which makes no sense given that all we need is for usage_usec to be close to 10,000 us. Fix this by explicitly calcuating the expected usage duration based on the configured quota, default period, and the duration, and compare usage_usec and expected_usage_usec using values_close() with a 10% error margin. Also, use snprintf to get the quota string to write to cpu.max instead of hardcoding the quota, ensuring a single source of truth. Remove the check comparing user_usec and expected_usage_usec, since on running this test modified with printfs, it's seen that user_usec and usage_usec can regularly exceed the theoretical expected_usage_usec: $ sudo ./test_cpu user: 10485, usage: 10485, expected: 10000 ok 1 test_cpucg_max user: 11127, usage: 11127, expected: 10000 ok 2 test_cpucg_max_nested $ sudo ./test_cpu user: 10286, usage: 10286, expected: 10000 ok 1 test_cpucg_max user: 10404, usage: 11271, expected: 10000 ok 2 test_cpucg_max_nested Hence, a values_close() check of usage_usec and expected_usage_usec is sufficient. Fixes: a799065 ("cgroup: Add test_cpucg_max_nested() testcase") Fixes: 889ab81 ("cgroup: Add test_cpucg_max() testcase") Acked-by: Michal Koutný <[email protected]> Signed-off-by: Shashank Balaji <[email protected]> Signed-off-by: Tejun Heo <[email protected]>
1 parent dfe25fb commit 954bacc

File tree

1 file changed

+43
-20
lines changed

1 file changed

+43
-20
lines changed

tools/testing/selftests/cgroup/test_cpu.c

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#define _GNU_SOURCE
44
#include <linux/limits.h>
5+
#include <sys/param.h>
56
#include <sys/sysinfo.h>
67
#include <sys/wait.h>
78
#include <errno.h>
@@ -645,10 +646,16 @@ test_cpucg_nested_weight_underprovisioned(const char *root)
645646
static int test_cpucg_max(const char *root)
646647
{
647648
int ret = KSFT_FAIL;
648-
long usage_usec, user_usec;
649-
long usage_seconds = 1;
650-
long expected_usage_usec = usage_seconds * USEC_PER_SEC;
649+
long quota_usec = 1000;
650+
long default_period_usec = 100000; /* cpu.max's default period */
651+
long duration_seconds = 1;
652+
653+
long duration_usec = duration_seconds * USEC_PER_SEC;
654+
long usage_usec, n_periods, remainder_usec, expected_usage_usec;
651655
char *cpucg;
656+
char quota_buf[32];
657+
658+
snprintf(quota_buf, sizeof(quota_buf), "%ld", quota_usec);
652659

653660
cpucg = cg_name(root, "cpucg_test");
654661
if (!cpucg)
@@ -657,13 +664,13 @@ static int test_cpucg_max(const char *root)
657664
if (cg_create(cpucg))
658665
goto cleanup;
659666

660-
if (cg_write(cpucg, "cpu.max", "1000"))
667+
if (cg_write(cpucg, "cpu.max", quota_buf))
661668
goto cleanup;
662669

663670
struct cpu_hog_func_param param = {
664671
.nprocs = 1,
665672
.ts = {
666-
.tv_sec = usage_seconds,
673+
.tv_sec = duration_seconds,
667674
.tv_nsec = 0,
668675
},
669676
.clock_type = CPU_HOG_CLOCK_WALL,
@@ -672,14 +679,19 @@ static int test_cpucg_max(const char *root)
672679
goto cleanup;
673680

674681
usage_usec = cg_read_key_long(cpucg, "cpu.stat", "usage_usec");
675-
user_usec = cg_read_key_long(cpucg, "cpu.stat", "user_usec");
676-
if (user_usec <= 0)
682+
if (usage_usec <= 0)
677683
goto cleanup;
678684

679-
if (user_usec >= expected_usage_usec)
680-
goto cleanup;
685+
/*
686+
* The following calculation applies only since
687+
* the cpu hog is set to run as per wall-clock time
688+
*/
689+
n_periods = duration_usec / default_period_usec;
690+
remainder_usec = duration_usec - n_periods * default_period_usec;
691+
expected_usage_usec
692+
= n_periods * quota_usec + MIN(remainder_usec, quota_usec);
681693

682-
if (values_close(usage_usec, expected_usage_usec, 95))
694+
if (!values_close(usage_usec, expected_usage_usec, 10))
683695
goto cleanup;
684696

685697
ret = KSFT_PASS;
@@ -698,10 +710,16 @@ static int test_cpucg_max(const char *root)
698710
static int test_cpucg_max_nested(const char *root)
699711
{
700712
int ret = KSFT_FAIL;
701-
long usage_usec, user_usec;
702-
long usage_seconds = 1;
703-
long expected_usage_usec = usage_seconds * USEC_PER_SEC;
713+
long quota_usec = 1000;
714+
long default_period_usec = 100000; /* cpu.max's default period */
715+
long duration_seconds = 1;
716+
717+
long duration_usec = duration_seconds * USEC_PER_SEC;
718+
long usage_usec, n_periods, remainder_usec, expected_usage_usec;
704719
char *parent, *child;
720+
char quota_buf[32];
721+
722+
snprintf(quota_buf, sizeof(quota_buf), "%ld", quota_usec);
705723

706724
parent = cg_name(root, "cpucg_parent");
707725
child = cg_name(parent, "cpucg_child");
@@ -717,13 +735,13 @@ static int test_cpucg_max_nested(const char *root)
717735
if (cg_create(child))
718736
goto cleanup;
719737

720-
if (cg_write(parent, "cpu.max", "1000"))
738+
if (cg_write(parent, "cpu.max", quota_buf))
721739
goto cleanup;
722740

723741
struct cpu_hog_func_param param = {
724742
.nprocs = 1,
725743
.ts = {
726-
.tv_sec = usage_seconds,
744+
.tv_sec = duration_seconds,
727745
.tv_nsec = 0,
728746
},
729747
.clock_type = CPU_HOG_CLOCK_WALL,
@@ -732,14 +750,19 @@ static int test_cpucg_max_nested(const char *root)
732750
goto cleanup;
733751

734752
usage_usec = cg_read_key_long(child, "cpu.stat", "usage_usec");
735-
user_usec = cg_read_key_long(child, "cpu.stat", "user_usec");
736-
if (user_usec <= 0)
753+
if (usage_usec <= 0)
737754
goto cleanup;
738755

739-
if (user_usec >= expected_usage_usec)
740-
goto cleanup;
756+
/*
757+
* The following calculation applies only since
758+
* the cpu hog is set to run as per wall-clock time
759+
*/
760+
n_periods = duration_usec / default_period_usec;
761+
remainder_usec = duration_usec - n_periods * default_period_usec;
762+
expected_usage_usec
763+
= n_periods * quota_usec + MIN(remainder_usec, quota_usec);
741764

742-
if (values_close(usage_usec, expected_usage_usec, 95))
765+
if (!values_close(usage_usec, expected_usage_usec, 10))
743766
goto cleanup;
744767

745768
ret = KSFT_PASS;

0 commit comments

Comments
 (0)