From nobody Wed Oct 8 05:47:00 2025 Received: from jpms-ob01-os7.noc.sony.co.jp (jpms-ob01-os7.noc.sony.co.jp [211.125.139.71]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 48623277C9F; Tue, 1 Jul 2025 14:14:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.125.139.71 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751379274; cv=none; b=YeZ2O/D2OmPzVFYRxdqVaUo/sgMautan6dba6Y0z/R0K2+C6BvBsV5PO4k45aUYQ9PCRZX6Ddnsv/vaYBmFZ15KTRqkO0uSBd046vmmWev4j8GZKuCWYZYznmJieTjJNjNlQqEv/4vthty07fL5e/DqKfAzqwJN5/vwUh3KDP8U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751379274; c=relaxed/simple; bh=bXuJLPTLDbbHnYV4dbJjzAbMiGO8yl0jOjOXRDCZff0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=RA2QcOwQB2ugsAoa6+LBJY2uGgPcgzy1+Jas2CC/LWYCUdXGKNPIqhh1Rbl7HF9KGbevz89D00ht/bqrykYBnhVqSd9O/C+x6wvGAqxQw+EckB8GJBR44PvwtOFYFbqH/jGf2WdOXk9zDmQQ8aShqUx2ngV8AexVFoQvjlPMPUU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=sony.com; spf=fail smtp.mailfrom=sony.com; dkim=pass (2048-bit key) header.d=sony.com header.i=@sony.com header.b=B07RFzmW; arc=none smtp.client-ip=211.125.139.71 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=sony.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=sony.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=sony.com header.i=@sony.com header.b="B07RFzmW" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sony.com; s=s1jp; t=1751379273; x=1782915273; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=qEn21RhlS91E/y3X/SxTP2la2eNKogK7MDafYiol9Kk=; b=B07RFzmW6f1dk0h7mjpCtx5il9z1cOv1EpN9g84tgrc+WjsT7bMstQZw Gj6aA8EUxZA/pqbqtAE6D82DaemhVvzI+4w7NDdMIbJLyVD/Q/LCa3Jr8 e7HrIr10PQZurWfRS4BImTp6a8OYtu/qrdxinKbv23N3x/ws1446hbnj1 mH+uobHlqlTc1ZZzWe+kiOb5+Q28cwE2Sh7rL+sgYxhU6Qm9vHlDqzqlf Chc7bpDOO3WJh4yZ+2dU2KrI/9YiKebI4rAZ/ogzjxVDB+inC/uTF6heq v6JXUEJlG4y3dpRG2kk11M/8vJzkVFswcy3UoqOuyFNlWANdN2g9GK7eB A==; Received: from unknown (HELO jpmta-ob02-os7.noc.sony.co.jp) ([IPv6:2001:cf8:acf:1104::7]) by jpms-ob01-os7.noc.sony.co.jp with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 01 Jul 2025 23:14:22 +0900 X-IronPort-AV: E=Sophos;i="6.16,279,1744038000"; d="scan'208";a="3310508" Received: from unknown (HELO [127.0.1.1]) ([IPv6:2001:cf8:1:573:0:dddd:eb3e:119e]) by jpmta-ob02-os7.noc.sony.co.jp with ESMTP; 01 Jul 2025 23:14:22 +0900 From: Shashank Balaji Date: Tue, 01 Jul 2025 23:13:55 +0900 Subject: [PATCH 1/2] selftests/cgroup: rename `expected` to `duration` in cpu.max tests Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250701-kselftest-cgroup-fix-cpu-max-v1-1-049507ad6832@sony.com> References: <20250701-kselftest-cgroup-fix-cpu-max-v1-0-049507ad6832@sony.com> In-Reply-To: <20250701-kselftest-cgroup-fix-cpu-max-v1-0-049507ad6832@sony.com> To: Tejun Heo , Johannes Weiner , =?utf-8?q?Michal_Koutn=C3=BD?= , Shuah Khan Cc: cgroups@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Shinya Takumi , Shashank Balaji X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=3346; i=shashank.mahadasyam@sony.com; h=from:subject:message-id; bh=bXuJLPTLDbbHnYV4dbJjzAbMiGO8yl0jOjOXRDCZff0=; b=owGbwMvMwCV2mPH4Ij++H1mMp9WSGDKS39oya86oOMUa0vW2eIKzwfX6rTaPvX3kea6uF7/3T tj1klZ4RykLgxgXg6yYIss7mXUXDlpZNn09zvANZg4rE8gQBi5OAZhIw2SG/4kLRU9v4/x2dflk OfWXohssODYlr3/y+MeisBXMJ5PnXrzKyLB753vBaAVuxkunvyg3LTkaV16ct+Np9sWInkuzJ3J dO8YLAA== X-Developer-Key: i=shashank.mahadasyam@sony.com; a=openpgp; fpr=EE1CAED0C13A3982F5C700F6C301C7A24E0EF86A usage_seconds is renamed to duration_seconds and expected_usage_usec is renamed to duration_usec to better reflect the meaning of those variables: they're the duration for which the cpu hog runs for as per wall clock time. Using `usage` for this purpose conflicts with the meaning of `usage` as per cpu.stat. In the cpu.stat case, `usage` is the duration for which the cgroup processes get to run for. Since in the cpu.max tests (both the normal one and the nested test), the cpu hog is set to use the wall clock time, because of throttling, the usage as per cpu.stat will be lower than the duration for which the cpu hog was set to run for. Now it should ring an alarm to see `values_close` being called on usage_usec and duration_usec, because they are not supposed to be close! This is fixed in the next patch. No functional changes. Signed-off-by: Shashank Balaji --- tools/testing/selftests/cgroup/test_cpu.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/testing/selftests/cgroup/test_cpu.c b/tools/testing/self= tests/cgroup/test_cpu.c index a2b50af8e9eeede0cf61d8394300cac02ccaf005..26b0df338505526cc0c5de8f417= 9b8ec9bad43d7 100644 --- a/tools/testing/selftests/cgroup/test_cpu.c +++ b/tools/testing/selftests/cgroup/test_cpu.c @@ -646,8 +646,8 @@ static int test_cpucg_max(const char *root) { int ret =3D KSFT_FAIL; long usage_usec, user_usec; - long usage_seconds =3D 1; - long expected_usage_usec =3D usage_seconds * USEC_PER_SEC; + long duration_seconds =3D 1; + long duration_usec =3D duration_seconds * USEC_PER_SEC; char *cpucg; =20 cpucg =3D cg_name(root, "cpucg_test"); @@ -663,7 +663,7 @@ static int test_cpucg_max(const char *root) struct cpu_hog_func_param param =3D { .nprocs =3D 1, .ts =3D { - .tv_sec =3D usage_seconds, + .tv_sec =3D duration_seconds, .tv_nsec =3D 0, }, .clock_type =3D CPU_HOG_CLOCK_WALL, @@ -676,10 +676,10 @@ static int test_cpucg_max(const char *root) if (user_usec <=3D 0) goto cleanup; =20 - if (user_usec >=3D expected_usage_usec) + if (user_usec >=3D duration_usec) goto cleanup; =20 - if (values_close(usage_usec, expected_usage_usec, 95)) + if (values_close(usage_usec, duration_usec, 95)) goto cleanup; =20 ret =3D KSFT_PASS; @@ -699,8 +699,8 @@ static int test_cpucg_max_nested(const char *root) { int ret =3D KSFT_FAIL; long usage_usec, user_usec; - long usage_seconds =3D 1; - long expected_usage_usec =3D usage_seconds * USEC_PER_SEC; + long duration_seconds =3D 1; + long duration_usec =3D duration_seconds * USEC_PER_SEC; char *parent, *child; =20 parent =3D cg_name(root, "cpucg_parent"); @@ -723,7 +723,7 @@ static int test_cpucg_max_nested(const char *root) struct cpu_hog_func_param param =3D { .nprocs =3D 1, .ts =3D { - .tv_sec =3D usage_seconds, + .tv_sec =3D duration_seconds, .tv_nsec =3D 0, }, .clock_type =3D CPU_HOG_CLOCK_WALL, @@ -736,10 +736,10 @@ static int test_cpucg_max_nested(const char *root) if (user_usec <=3D 0) goto cleanup; =20 - if (user_usec >=3D expected_usage_usec) + if (user_usec >=3D duration_usec) goto cleanup; =20 - if (values_close(usage_usec, expected_usage_usec, 95)) + if (values_close(usage_usec, duration_usec, 95)) goto cleanup; =20 ret =3D KSFT_PASS; --=20 2.43.0 From nobody Wed Oct 8 05:47:00 2025 Received: from jpms-ob01-os7.noc.sony.co.jp (jpms-ob01-os7.noc.sony.co.jp [211.125.139.71]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 689ED278143; Tue, 1 Jul 2025 14:14:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.125.139.71 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751379276; cv=none; b=OgSJdDWYe02vxt1KXvfbYoVJeaWjZKayN4+9hnStCfbmUwRJaGu2S6SVKd/qI5S0VALGf3mUfgpVWRC91Kfu2HTrp5c/otOHSqpZ+avY29V6FRyfCNnK/T+YD+4un4d56Mr8LOXj9+s0ho7j9Pvyv4OBnpOO919M6ddLp688Pdk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751379276; c=relaxed/simple; bh=kqFaZwOq1c8NL2QVuZAFmyI28sb7OjXf6Gf6ByZX1qQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=nPOFZbznXpmjp++D3Cn4I/+j6eZsTPApcuW8Qk8YR9s0v0CVyh626sKB0dBGFoywxeK2RBqJH2tYm+D6sVweYC6dIhnpvJR+3pULqJTYkG86WP7PF7V1Iz3M6Ap5xigfue3JgKi+hwHB+G8TEnSU5IIfz8AOjiel0xYz2a7hkgw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=sony.com; spf=fail smtp.mailfrom=sony.com; dkim=pass (2048-bit key) header.d=sony.com header.i=@sony.com header.b=amqFuhsp; arc=none smtp.client-ip=211.125.139.71 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=sony.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=sony.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=sony.com header.i=@sony.com header.b="amqFuhsp" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sony.com; s=s1jp; t=1751379274; x=1782915274; h=from:date:subject:mime-version:content-transfer-encoding: message-id:references:in-reply-to:to:cc; bh=nojilaL/3AL8ig7k4WoYT/DekocQo+4nJIJWkp0Ipms=; b=amqFuhspwB1LjlKe99tYBMG1HvYWQI8N7AGYGQQ7GEuJ34DrfVJWUDEP T67RcViimZ6TzJmvvW0dQi92wDe+r0LNFvBl+uItLjG4ZC32oSC/jtuFr snmSHIQKzYYW6YiVxr8uDpnNfhgLtekYuGkpuidGan5ww1qOUnCSxTWxc jBnmn6TSCggWEYxBNey4B6DjHmOc4saTwKb9FTJebIkC5kcEnTGxuukA+ 1eF/TFdSEA63ryQl74+FAhtrKf0Rs+DjrAIqksYGafstoK0XV2GOw3GkV E9gQ0iCFSz0diXRajjqEsANj30Gdof+ziDphphV5bxIMOQv22C7jeFUfH g==; Received: from unknown (HELO jpmta-ob02-os7.noc.sony.co.jp) ([IPv6:2001:cf8:acf:1104::7]) by jpms-ob01-os7.noc.sony.co.jp with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 01 Jul 2025 23:14:23 +0900 X-IronPort-AV: E=Sophos;i="6.16,279,1744038000"; d="scan'208";a="3310512" Received: from unknown (HELO [127.0.1.1]) ([IPv6:2001:cf8:1:573:0:dddd:eb3e:119e]) by jpmta-ob02-os7.noc.sony.co.jp with ESMTP; 01 Jul 2025 23:14:22 +0900 From: Shashank Balaji Date: Tue, 01 Jul 2025 23:13:56 +0900 Subject: [PATCH 2/2] selftests/cgroup: better bound in cpu.max tests Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250701-kselftest-cgroup-fix-cpu-max-v1-2-049507ad6832@sony.com> References: <20250701-kselftest-cgroup-fix-cpu-max-v1-0-049507ad6832@sony.com> In-Reply-To: <20250701-kselftest-cgroup-fix-cpu-max-v1-0-049507ad6832@sony.com> To: Tejun Heo , Johannes Weiner , =?utf-8?q?Michal_Koutn=C3=BD?= , Shuah Khan Cc: cgroups@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Shinya Takumi , Shashank Balaji X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=4932; i=shashank.mahadasyam@sony.com; h=from:subject:message-id; bh=kqFaZwOq1c8NL2QVuZAFmyI28sb7OjXf6Gf6ByZX1qQ=; b=owGbwMvMwCV2mPH4Ij++H1mMp9WSGDKS39rm/eM+dGCb1oy0Wt3z16LPa9xtbRYvTMq92z8nK c+fafnfjlIWBjEuBlkxRZZ3MusuHLSybPp6nOEbzBxWJpAhDFycAjCRJTMY/heKf+6L4P4ewbzp Jd8Ph21cn9V1BGw0AnRdWZZYp92tWcLIMMP+8Y8fRVkPjs1acFjbwz/yp1LHHd2XJyILLrsvmLL ZhgEA X-Developer-Key: i=shashank.mahadasyam@sony.com; a=openpgp; fpr=EE1CAED0C13A3982F5C700F6C301C7A24E0EF86A The cpu.max test (both the normal one and the nested one) setup cpu.max with 1000 us runtime 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. Enforce this bound correc= tly. Previously, this approximate equality test was done by `!values_close(usage_usec, duration_usec, 95)`: if the absolute difference between usage_usec and duration_usec is greater than 95% of their sum, then we pass. This is problematic for two reasons: 1. Semantics: When one sees `values_close` they expect the error percentage to be some small number, not 95. The intent behind using `values_close` is lost by using a high error percent such as 95. The intent it's actually going for is "values far". 2. Bound too wide: The condition translates to the following expression: |usage_usec - duration_usec| > (usage_usec + duration_usec)*0.95 0.05*duration_usec > 1.95*usage_usec (usage < duration) usage_usec < 0.0257*duration_usec =3D 25,641 us So, this condition passes as long as usage_usec is lower than 25,641 us, while all we want is for it to be close to 10,000 us. To address these issues, the condition is changed to `labs(usage_usec - expected_usage_usec) < 2000` meaning pass. Now the meaning is much clearer. `labs` is used instead of `values_close` because we don't expect the error in usage_usec compared to expected_usage_usec to scale with either of the terms. The error is because of the cpu hog process running for slightly longer than the duration. So, using a proportional error estimate, such as `values_close`, does not make sense. The maximum tolerable error is set to 2000 us because on running this test 10 times, the maximum `usage_usec` observed was 11,513 us, which corresponds to an error of 1513 us. user_usec is removed because it will always be less than usage_usec. usage_usec is what really represents the throttling. Signed-off-by: Shashank Balaji --- tools/testing/selftests/cgroup/test_cpu.c | 34 ++++++++++++++++++---------= ---- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/tools/testing/selftests/cgroup/test_cpu.c b/tools/testing/self= tests/cgroup/test_cpu.c index 26b0df338505526cc0c5de8f4179b8ec9bad43d7..fcef90d2948e1344b7741214a0c= dd10609069624 100644 --- a/tools/testing/selftests/cgroup/test_cpu.c +++ b/tools/testing/selftests/cgroup/test_cpu.c @@ -645,9 +645,8 @@ test_cpucg_nested_weight_underprovisioned(const char *r= oot) static int test_cpucg_max(const char *root) { int ret =3D KSFT_FAIL; - long usage_usec, user_usec; + long usage_usec, expected_usage_usec; long duration_seconds =3D 1; - long duration_usec =3D duration_seconds * USEC_PER_SEC; char *cpucg; =20 cpucg =3D cg_name(root, "cpucg_test"); @@ -672,14 +671,18 @@ static int test_cpucg_max(const char *root) goto cleanup; =20 usage_usec =3D cg_read_key_long(cpucg, "cpu.stat", "usage_usec"); - user_usec =3D cg_read_key_long(cpucg, "cpu.stat", "user_usec"); - if (user_usec <=3D 0) + if (usage_usec <=3D 0) goto cleanup; =20 - if (user_usec >=3D duration_usec) - goto cleanup; + /* + * Since the cpu hog is set to run as per wall clock time, it's expected = to + * run for 10 periods (duration_usec/default_period_usec), and in each + * period, it's throttled to run for 1000 usec. So its expected usage is + * 1000 * 10 =3D 10000 usec. + */ + expected_usage_usec =3D 10000; =20 - if (values_close(usage_usec, duration_usec, 95)) + if (labs(usage_usec - expected_usage_usec) > 2000) goto cleanup; =20 ret =3D KSFT_PASS; @@ -698,9 +701,8 @@ static int test_cpucg_max(const char *root) static int test_cpucg_max_nested(const char *root) { int ret =3D KSFT_FAIL; - long usage_usec, user_usec; + long usage_usec, expected_usage_usec; long duration_seconds =3D 1; - long duration_usec =3D duration_seconds * USEC_PER_SEC; char *parent, *child; =20 parent =3D cg_name(root, "cpucg_parent"); @@ -732,14 +734,18 @@ static int test_cpucg_max_nested(const char *root) goto cleanup; =20 usage_usec =3D cg_read_key_long(child, "cpu.stat", "usage_usec"); - user_usec =3D cg_read_key_long(child, "cpu.stat", "user_usec"); - if (user_usec <=3D 0) + if (usage_usec <=3D 0) goto cleanup; =20 - if (user_usec >=3D duration_usec) - goto cleanup; + /* + * Since the cpu hog is set to run as per wall clock time, it's expected = to + * run for 10 periods (duration_usec/default_period_usec), and in each + * period, it's throttled to run for 1000 usec. So its expected usage is + * 1000 * 10 =3D 10000 usec. + */ + expected_usage_usec =3D 10000; =20 - if (values_close(usage_usec, duration_usec, 95)) + if (labs(usage_usec - expected_usage_usec) > 2000) goto cleanup; =20 ret =3D KSFT_PASS; --=20 2.43.0 From nobody Wed Oct 8 05:47:00 2025 Received: from jpms-ob02-os7.noc.sony.co.jp (jpms-ob02-os7.noc.sony.co.jp [211.125.139.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7D95F253939; Thu, 3 Jul 2025 12:06:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=211.125.139.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751544365; cv=none; b=RqqV2AJ2PWBsbc28THLdIC1ID0ZJRCNMQj/UF3vNUiUGSdozwZ6qf8shQUTN43l31BPuGsqzBSc5LHFue1VYbag6s2ihbLQXl3x+OU60J8gr03QiQpFdAQUVql6QW0TxxMp0tFLlDILNRGwl0LXZO0U8e9iLkwbJA6t0SkkwcFo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1751544365; c=relaxed/simple; bh=raWexe22dvi7aq1OOnkH/6y7PUeW0mewCeOEWWp1QAQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YEvxlOUqPDOJLrgSRq7zaboAvGPdHliqkLCAALkcFLniLNMVjrHVcOSD/zkXloY5BSqndpXQ25nM5nPexd+69KhyQOH4lWyOHQFjHpGdr0rcKExKm+BsjKcxtH7dasfAmYXohtVIkVg36BExFAwtduaMXpWmlg5wuDifk6hBCfc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=sony.com; spf=fail smtp.mailfrom=sony.com; dkim=pass (2048-bit key) header.d=sony.com header.i=@sony.com header.b=Le55KwYb; arc=none smtp.client-ip=211.125.139.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=sony.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=sony.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=sony.com header.i=@sony.com header.b="Le55KwYb" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sony.com; s=s1jp; t=1751544362; x=1783080362; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=FA1lUYQuzgJrq3jDPYzI6xXt+JabSa+YCb1SBMISYiA=; b=Le55KwYbuM42u4rRTQM7tE+oz0LH42yGpGNTiPvWy7UzNgPERu0Yfk5p RufMtkPH1XYCFMXH3fhNdASr5aZylJ4yGUBC9f1/f5V0HNhDG0tiz3Hxw gGJskjafDwFJzHi3k4RcnqP/sJsJm+KPGwwYTt0hBcBir8AWdI49PJ6m0 dbB5f2VHSn9MSLap+j5i9suX6LpXkTkFXdzr1Q5RJCI4K9dQJRtF7FdLv IwjHQ+m6JQKc5l+pbNU8swiYtRlh2kON2vek9PcBjom1JlCYyAAQqpDxU w1ETVzjhynekKGBxjQhHId5iRX6BWqS7iUWjhJAybzjuz75MX0fklyu/b A==; Received: from unknown (HELO jpmta-ob02-os7.noc.sony.co.jp) ([IPv6:2001:cf8:acf:1104::7]) by jpms-ob02-os7.noc.sony.co.jp with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 03 Jul 2025 21:05:59 +0900 X-IronPort-AV: E=Sophos;i="6.16,284,1744038000"; d="scan'208";a="4257026" Received: from unknown (HELO JPC00244420..) ([IPv6:2001:cf8:1:573:0:dddd:eb3e:119e]) by jpmta-ob02-os7.noc.sony.co.jp with ESMTP; 03 Jul 2025 21:05:59 +0900 From: Shashank Balaji To: Tejun Heo , Johannes Weiner , =?UTF-8?q?Michal=20Koutn=C3=BD?= , Shuah Khan Cc: Shashank Balaji , cgroups@vger.kernel.org, linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org, Shinya Takumi Subject: [PATCH v2] selftests/cgroup: improve the accuracy of cpu.max tests Date: Thu, 3 Jul 2025 21:03:20 +0900 Message-ID: <20250703120325.2905314-1-shashank.mahadasyam@sony.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20250701-kselftest-cgroup-fix-cpu-max-v1-0-049507ad6832@sony.com> References: <20250701-kselftest-cgroup-fix-cpu-max-v1-0-049507ad6832@sony.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Current cpu.max tests (both the normal one and the nested one) are inaccura= te. 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 correspo= nds 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, duration_usec, 95)`: if the absolute difference between usage_usec and duration_usec is greater than 95% of their sum, then we pass. This is problematic for two reasons: 1. Semantics: When one sees `values_close` they expect the error percentage to be some small number, not 95. The intent behind using `values_close` is lost by using a high error percent such as 95. The intent it's actually going for is "values far". 2. Bound too wide: The condition translates to the following expression: |usage_usec - duration_usec| > (usage_usec + duration_usec)*0.95 0.05*duration_usec > 1.95*usage_usec (usage < duration) usage_usec < 0.0257*duration_usec =3D 25,641 us So, this condition passes as long as usage_usec is lower than 25,641 us, while all we want is for it 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. Signed-off-by: Shashank Balaji Acked-by: Michal Koutn=C3=BD --- Changes in v2: - Incorporate Michal's suggestions: - Merge two patches into one - Generate the quota string from the variable instead of hardcoding it - Use values_close() instead of labs() - Explicitly calculate expected_usage_usec - v1: https://lore.kernel.org/all/20250701-kselftest-cgroup-fix-cpu-max-v1-= 0-049507ad6832@sony.com/ --- tools/testing/selftests/cgroup/test_cpu.c | 63 ++++++++++++++++------- 1 file changed, 43 insertions(+), 20 deletions(-) diff --git a/tools/testing/selftests/cgroup/test_cpu.c b/tools/testing/self= tests/cgroup/test_cpu.c index a2b50af8e9ee..2a60e6c41940 100644 --- a/tools/testing/selftests/cgroup/test_cpu.c +++ b/tools/testing/selftests/cgroup/test_cpu.c @@ -2,6 +2,7 @@ =20 #define _GNU_SOURCE #include +#include #include #include #include @@ -645,10 +646,16 @@ test_cpucg_nested_weight_underprovisioned(const char = *root) static int test_cpucg_max(const char *root) { int ret =3D KSFT_FAIL; - long usage_usec, user_usec; - long usage_seconds =3D 1; - long expected_usage_usec =3D usage_seconds * USEC_PER_SEC; + long quota_usec =3D 1000; + long default_period_usec =3D 100000; /* cpu.max's default period */ + long duration_seconds =3D 1; + + long duration_usec =3D duration_seconds * USEC_PER_SEC; + long usage_usec, n_periods, remainder_usec, expected_usage_usec; char *cpucg; + char quota_buf[32]; + + snprintf(quota_buf, sizeof(quota_buf), "%ld", quota_usec); =20 cpucg =3D cg_name(root, "cpucg_test"); if (!cpucg) @@ -657,13 +664,13 @@ static int test_cpucg_max(const char *root) if (cg_create(cpucg)) goto cleanup; =20 - if (cg_write(cpucg, "cpu.max", "1000")) + if (cg_write(cpucg, "cpu.max", quota_buf)) goto cleanup; =20 struct cpu_hog_func_param param =3D { .nprocs =3D 1, .ts =3D { - .tv_sec =3D usage_seconds, + .tv_sec =3D duration_seconds, .tv_nsec =3D 0, }, .clock_type =3D CPU_HOG_CLOCK_WALL, @@ -672,14 +679,19 @@ static int test_cpucg_max(const char *root) goto cleanup; =20 usage_usec =3D cg_read_key_long(cpucg, "cpu.stat", "usage_usec"); - user_usec =3D cg_read_key_long(cpucg, "cpu.stat", "user_usec"); - if (user_usec <=3D 0) + if (usage_usec <=3D 0) goto cleanup; =20 - if (user_usec >=3D expected_usage_usec) - goto cleanup; + /* + * The following calculation applies only since + * the cpu hog is set to run as per wall-clock time + */ + n_periods =3D duration_usec / default_period_usec; + remainder_usec =3D duration_usec - n_periods * default_period_usec; + expected_usage_usec + =3D n_periods * quota_usec + MIN(remainder_usec, quota_usec); =20 - if (values_close(usage_usec, expected_usage_usec, 95)) + if (!values_close(usage_usec, expected_usage_usec, 10)) goto cleanup; =20 ret =3D KSFT_PASS; @@ -698,10 +710,16 @@ static int test_cpucg_max(const char *root) static int test_cpucg_max_nested(const char *root) { int ret =3D KSFT_FAIL; - long usage_usec, user_usec; - long usage_seconds =3D 1; - long expected_usage_usec =3D usage_seconds * USEC_PER_SEC; + long quota_usec =3D 1000; + long default_period_usec =3D 100000; /* cpu.max's default period */ + long duration_seconds =3D 1; + + long duration_usec =3D duration_seconds * USEC_PER_SEC; + long usage_usec, n_periods, remainder_usec, expected_usage_usec; char *parent, *child; + char quota_buf[32]; + + snprintf(quota_buf, sizeof(quota_buf), "%ld", quota_usec); =20 parent =3D cg_name(root, "cpucg_parent"); child =3D cg_name(parent, "cpucg_child"); @@ -717,13 +735,13 @@ static int test_cpucg_max_nested(const char *root) if (cg_create(child)) goto cleanup; =20 - if (cg_write(parent, "cpu.max", "1000")) + if (cg_write(parent, "cpu.max", quota_buf)) goto cleanup; =20 struct cpu_hog_func_param param =3D { .nprocs =3D 1, .ts =3D { - .tv_sec =3D usage_seconds, + .tv_sec =3D duration_seconds, .tv_nsec =3D 0, }, .clock_type =3D CPU_HOG_CLOCK_WALL, @@ -732,14 +750,19 @@ static int test_cpucg_max_nested(const char *root) goto cleanup; =20 usage_usec =3D cg_read_key_long(child, "cpu.stat", "usage_usec"); - user_usec =3D cg_read_key_long(child, "cpu.stat", "user_usec"); - if (user_usec <=3D 0) + if (usage_usec <=3D 0) goto cleanup; =20 - if (user_usec >=3D expected_usage_usec) - goto cleanup; + /* + * The following calculation applies only since + * the cpu hog is set to run as per wall-clock time + */ + n_periods =3D duration_usec / default_period_usec; + remainder_usec =3D duration_usec - n_periods * default_period_usec; + expected_usage_usec + =3D n_periods * quota_usec + MIN(remainder_usec, quota_usec); =20 - if (values_close(usage_usec, expected_usage_usec, 95)) + if (!values_close(usage_usec, expected_usage_usec, 10)) goto cleanup; =20 ret =3D KSFT_PASS; --=20 2.43.0