All of lore.kernel.org
 help / color / mirror / Atom feed
From: Richard Cheng <icheng@nvidia.com>
To: tony.luck@intel.com, reinette.chatre@intel.com, x86@kernel.org
Cc: Dave.Martin@arm.com, james.morse@arm.com, babu.moger@amd.com,
	shuah@kernel.org, linux-kernel@vger.kernel.org,
	linux-kselftest@vger.kernel.org, newtonl@nvidia.com,
	kristinc@nvidia.com, kobak@nvidia.com, kaihengf@nvidia.com,
	fenghuay@nvidia.com, ltrager@nvidia.com,
	Richard Cheng <icheng@nvidia.com>
Subject: [PATCH 4/4] selftests/resctrl: Add MBA schemata per-group isolation selftest
Date: Wed, 22 Jul 2026 10:10:57 +0800	[thread overview]
Message-ID: <20260722021057.9370-5-icheng@nvidia.com> (raw)
In-Reply-To: <20260722021057.9370-1-icheng@nvidia.com>

MB cpas are per control group, implement MBA_SCHEMATA_ISOLATE test to
verify a write to one group leaves other groups and the default group
untouched.

Create 2 groups, set the first to the max and the second to a lower cap,
then read the first after writing the second, each holds its own value.
The default group stays unchanged. The lower cap is gran-aligned and at
or above min_bandwidth, so read-back is exact and provably below the
maximum.

Signed-off-by: Richard Cheng <icheng@nvidia.com>
---
 .../selftests/resctrl/mba_schemata_test.c     | 131 ++++++++++++++++++
 tools/testing/selftests/resctrl/resctrl.h     |   1 +
 .../testing/selftests/resctrl/resctrl_tests.c |   1 +
 3 files changed, 133 insertions(+)

diff --git a/tools/testing/selftests/resctrl/mba_schemata_test.c b/tools/testing/selftests/resctrl/mba_schemata_test.c
index 0cd257dcec91..d98946b831b1 100644
--- a/tools/testing/selftests/resctrl/mba_schemata_test.c
+++ b/tools/testing/selftests/resctrl/mba_schemata_test.c
@@ -388,3 +388,134 @@ struct resctrl_test mba_schemata_inval_test = {
 	.feature_check = mba_schemata_feature_check,
 	.run_test = mba_schemata_inval_run_test,
 };
+
+/*
+ * MB allocations are per control group: two groups hold different
+ * percentages on the same domain without disturbing each other or the
+ * default group.
+ */
+static int mba_schemata_isolate_run_test(const struct resctrl_test *test,
+					 const struct user_params *uparams)
+{
+	unsigned int gran, min_bw, low, num_closids, def_before = 0, def_after = 0;
+	unsigned int got1 = 0, got2 = 0, pct[MB_MAX_DOMAINS];
+	int ids[MB_MAX_DOMAINS], n, ret, dom, fail = 0;
+	char vals[MB_SCHEMATA_LEN], path1[256], path2[256], line[64];
+	const char *grp1 = "mba_schemata_iso1", *grp2 = "mba_schemata_iso2";
+
+	/*
+	 * Isolation works with any CLOSID count, but the
+	 * default group plus the two test groups each need to hold one.
+	 */
+	if (resource_info_unsigned_get(test->resource, "num_closids", &num_closids))
+		return 1;
+	if (num_closids < 3) {
+		ksft_print_msg("Skipping: num_closids=%u < 3, cannot create two test groups\n",
+			       num_closids);
+		return 0;
+	}
+
+	if (resource_info_unsigned_get(test->resource, "bandwidth_gran", &gran) || !gran)
+		return 1;
+	if (resource_info_unsigned_get(test->resource, "min_bandwidth", &min_bw))
+		return 1;
+
+	/* Enumerate the real MB domain ids from the default schemata. */
+	ret = resctrl_get_schemata("", test->resource, vals, sizeof(vals));
+	if (ret) {
+		ksft_print_msg("Fail: could not read %s schemata line (ret=%d)\n",
+			       test->resource, ret);
+		return 1;
+	}
+	n = parse_mb_schemata(vals, ids, pct, MB_MAX_DOMAINS);
+	if (n < 1) {
+		ksft_print_msg("Fail: could not parse %s schemata \"%s\"\n",
+			       test->resource, vals);
+		return 1;
+	}
+	dom = ids[0];
+
+	/*
+	 * grp2's cap must stay provably below grp1's 100% even after the
+	 * kernel rounds it to bandwidth_gran: align it here, at or above
+	 * min_bandwidth, and expect an exact read-back. If no aligned value
+	 * below the maximum exists, the two groups cannot be told apart.
+	 */
+	low = min_bw > 20 ? min_bw : 20;
+	low = (low + gran - 1) / gran * gran;
+	if (low >= MB_PERCENT_MAX) {
+		ksft_print_msg("Skipping: no %s cap below %u representable (min_bw=%u, gran=%u)\n",
+			       test->resource, MB_PERCENT_MAX, min_bw, gran);
+		return 0;
+	}
+
+	if (mb_read_domain("", test->resource, dom, &def_before)) {
+		ksft_print_msg("Fail: read default group %s domain %d\n",
+			       test->resource, dom);
+		return 1;
+	}
+
+	snprintf(path1, sizeof(path1), "%s/%s", RESCTRL_PATH, grp1);
+	if (mkdir(path1, 0755) && errno != EEXIST) {
+		ksft_print_msg("Fail: mkdir %s: %m\n", path1);
+		return 1;
+	}
+	snprintf(path2, sizeof(path2), "%s/%s", RESCTRL_PATH, grp2);
+	if (mkdir(path2, 0755) && errno != EEXIST) {
+		ksft_print_msg("Fail: mkdir %s: %m\n", path2);
+		rmdir(path1);
+		return 1;
+	}
+
+	/* Pin the two groups to different caps on the same domain. */
+	snprintf(line, sizeof(line), "%s:%d=%u",
+		 test->resource, dom, MB_PERCENT_MAX);
+	ret = resctrl_write_schemata(grp1, line);
+	if (ret) {
+		ksft_print_msg("Fail: write \"%s\" to %s (ret=%d)\n",
+			       line, grp1, ret);
+		fail = 1;
+	}
+	snprintf(line, sizeof(line), "%s:%d=%u", test->resource, dom, low);
+	ret = resctrl_write_schemata(grp2, line);
+	if (ret) {
+		ksft_print_msg("Fail: write \"%s\" to %s (ret=%d)\n",
+			       line, grp2, ret);
+		fail = 1;
+	}
+
+	/* Each group keeps its own cap; reading g1 after writing g2. */
+	if (mb_read_domain(grp1, test->resource, dom, &got1) ||
+	    got1 != MB_PERCENT_MAX) {
+		ksft_print_msg("Fail: %s domain %d: %u%%, expected %u%%\n",
+			       grp1, dom, got1, MB_PERCENT_MAX);
+		fail = 1;
+	}
+	if (mb_read_domain(grp2, test->resource, dom, &got2) ||
+	    got2 != low) {
+		ksft_print_msg("Fail: %s domain %d: %u%%, expected %u%%\n",
+			       grp2, dom, got2, low);
+		fail = 1;
+	}
+
+	/* The default group must be untouched by either write. */
+	if (mb_read_domain("", test->resource, dom, &def_after) ||
+	    def_after != def_before) {
+		ksft_print_msg("Fail: default group domain %d changed %u%% -> %u%%\n",
+			       dom, def_before, def_after);
+		fail = 1;
+	}
+
+	rmdir(path1);
+	rmdir(path2);
+
+	return fail;
+}
+
+struct resctrl_test mba_schemata_isolate_test = {
+	.name = "MBA_SCHEMATA_ISOLATE",
+	.group = "MBA_SCHEMATA",
+	.resource = "MB",
+	.feature_check = mba_schemata_feature_check,
+	.run_test = mba_schemata_isolate_run_test,
+};
diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
index c32ab5c2cc56..07a67ac9292c 100644
--- a/tools/testing/selftests/resctrl/resctrl.h
+++ b/tools/testing/selftests/resctrl/resctrl.h
@@ -252,5 +252,6 @@ extern struct resctrl_test l2_noncont_cat_test;
 extern struct resctrl_test mba_schemata_info_test;
 extern struct resctrl_test mba_schemata_rw_test;
 extern struct resctrl_test mba_schemata_inval_test;
+extern struct resctrl_test mba_schemata_isolate_test;
 
 #endif /* RESCTRL_H */
diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c
index 7a7184783e6a..583ee97bac20 100644
--- a/tools/testing/selftests/resctrl/resctrl_tests.c
+++ b/tools/testing/selftests/resctrl/resctrl_tests.c
@@ -24,6 +24,7 @@ static struct resctrl_test *resctrl_tests[] = {
 	&mba_schemata_info_test,
 	&mba_schemata_rw_test,
 	&mba_schemata_inval_test,
+	&mba_schemata_isolate_test,
 };
 
 static unsigned int detect_vendor(void)
-- 
2.43.0


      parent reply	other threads:[~2026-07-22  2:11 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-22  2:10 [PATCH 0/4] selftests/resctrl: MBA schemata ABI selftests for MPAM platforms Richard Cheng
2026-07-22  2:10 ` [PATCH 1/4] selftests/resctrl: Add MBA schemata info selftest Richard Cheng
2026-07-22  2:10 ` [PATCH 2/4] selftests/resctrl: Add MBA schemata write/read-back selftest Richard Cheng
2026-07-22  2:10 ` [PATCH 3/4] selftests/resctrl: Add MBA schemata invalid-write selftest Richard Cheng
2026-07-22  2:10 ` Richard Cheng [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260722021057.9370-5-icheng@nvidia.com \
    --to=icheng@nvidia.com \
    --cc=Dave.Martin@arm.com \
    --cc=babu.moger@amd.com \
    --cc=fenghuay@nvidia.com \
    --cc=james.morse@arm.com \
    --cc=kaihengf@nvidia.com \
    --cc=kobak@nvidia.com \
    --cc=kristinc@nvidia.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=ltrager@nvidia.com \
    --cc=newtonl@nvidia.com \
    --cc=reinette.chatre@intel.com \
    --cc=shuah@kernel.org \
    --cc=tony.luck@intel.com \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.