The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH v2 0/2] selftests/resctrl: Increase L3 cache test coverage
@ 2026-08-10  9:51 Richard Cheng
  2026-08-10  9:51 ` [PATCH v2 1/2] selftests/resctrl: Add L3_CBM_VALIDATE to check CBM writes Richard Cheng
  2026-08-10  9:51 ` [PATCH v2 2/2] selftests/resctrl: Add L3_BIT_USAGE to check allocation reporting Richard Cheng
  0 siblings, 2 replies; 3+ messages in thread
From: Richard Cheng @ 2026-08-10  9:51 UTC (permalink / raw)
  To: tony.luck, shuah, reinette.chatre
  Cc: Dave.Martin, james.morse, babu.moger, linux-kernel,
	linux-kselftest, fenghuay, newtonl, kristinc, kaihengf, kobak,
	sdonthineni, Richard Cheng

The resctrl selftests check L3 cache isolation L3_CAT and occupancy
accuracy CMT, but some basic L3 behavior is untested. That CBM writes
are handle correctly and that info/L3/bit_usage reports allocations
correctly.

Add two self-contained tests for these. Each gates on the feature it
needs, so it runs wherever that feature exists and skips otherwise.
They were exercised on an arm64 MPAM platform.

Changes since v1:
- Drop L3_CAT_OCCUP because CMT already tests cache occupancy bounds.
- Rework L3_CAT_VALIDATE as L3_CBM_VALIDATE to check valid and invalid
  CBMs using cbm_mask and min_cbm_bits.
- Rework L3_BIT_USAGE to use valid partial allocations and simplify
  domain bit_usage parsing.


Running checkpatch.pl will have warning on patch 1 about string issue,
I've tweaked it for several times so I'll let you decide whether we
should decrease the message or leave it as is.


Richard Cheng (2):
  selftests/resctrl: Add L3_CBM_VALIDATE to check CBM writes
  selftests/resctrl: Add L3_BIT_USAGE to check allocation reporting

 tools/testing/selftests/resctrl/cat_test.c    | 285 ++++++++++++++++++
 tools/testing/selftests/resctrl/resctrl.h     |   2 +
 .../testing/selftests/resctrl/resctrl_tests.c |   2 +
 3 files changed, 289 insertions(+)


base-commit: 840ef6c78e6a2f694b578ecb9063241c992aaa9e
-- 
2.53.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH v2 1/2] selftests/resctrl: Add L3_CBM_VALIDATE to check CBM writes
  2026-08-10  9:51 [PATCH v2 0/2] selftests/resctrl: Increase L3 cache test coverage Richard Cheng
@ 2026-08-10  9:51 ` Richard Cheng
  2026-08-10  9:51 ` [PATCH v2 2/2] selftests/resctrl: Add L3_BIT_USAGE to check allocation reporting Richard Cheng
  1 sibling, 0 replies; 3+ messages in thread
From: Richard Cheng @ 2026-08-10  9:51 UTC (permalink / raw)
  To: tony.luck, shuah, reinette.chatre
  Cc: Dave.Martin, james.morse, babu.moger, linux-kernel,
	linux-kselftest, fenghuay, newtonl, kristinc, kaihengf, kobak,
	sdonthineni, Richard Cheng

Add L3_CBM_VALIDATE to verify that resctrl enforces the L3 CBM rules
advertised by cbm_mask and min_cbm_bits.

Confirm that the full mask is accepted. Check the empty mask according
to min_cbm_bits, and confirm that out-of-range and undersized masks are
rejected.

This catches inconsistencies between the advertised capabilities and
schemata validation.

Signed-off-by: Richard Cheng <icheng@nvidia.com>
---
Changelog:

v1 -> v2:
    - Rename L3_CAT_VALIDATE to L3_CBM_VALIDATE
    - Handle empty CBMs according to min_cbm_bits
    - Check count_contiguous_bits() before using its result
    - Use KSFT_FAIL and reverse-fir-tree ordering
    - Use a 64-bit out-of-range mask

Best regards,
Richard Cheng.
---
 tools/testing/selftests/resctrl/cat_test.c    | 91 +++++++++++++++++++
 tools/testing/selftests/resctrl/resctrl.h     |  1 +
 .../testing/selftests/resctrl/resctrl_tests.c |  1 +
 3 files changed, 93 insertions(+)

diff --git a/tools/testing/selftests/resctrl/cat_test.c b/tools/testing/selftests/resctrl/cat_test.c
index 371a2f26dc47..a06c57954740 100644
--- a/tools/testing/selftests/resctrl/cat_test.c
+++ b/tools/testing/selftests/resctrl/cat_test.c
@@ -357,6 +357,89 @@ static bool noncont_cat_feature_check(const struct resctrl_test *test)
 	return resource_info_file_exists(test->resource, "sparse_masks");
 }
 
+/*
+ * L3_CBM_VALIDATE - Verify L3 CBM write validation.
+ *
+ * A full CBM must be accepted. An empty CBM is valid only when min_cbm_bits
+ * is zero. Masks with bits outside cbm_mask or fewer than min_cbm_bits must
+ * be rejected.
+ */
+static int cbm_validate_run_test(const struct resctrl_test *test,
+				 const struct user_params *uparams)
+{
+	unsigned int min_cbm_bits, contiguous_bits;
+	unsigned long long invalid_mask;
+	unsigned int count_of_bits;
+	unsigned long full_mask;
+	unsigned int start;
+	char schemata[64];
+	int ret;
+
+	ret = get_full_cbm(test->resource, &full_mask);
+	if (ret)
+		return ret;
+
+	ret = resource_info_unsigned_get(test->resource, "min_cbm_bits",
+					 &min_cbm_bits);
+	if (ret)
+		return ret;
+
+	count_of_bits = count_bits(full_mask);
+
+	/* A valid full CBM must be accepted. */
+	snprintf(schemata, sizeof(schemata), "%lx", full_mask);
+	if (write_schemata("", schemata, uparams->cpu, test->resource)) {
+		ksft_print_msg("Valid CBM 0x%lx was rejected\n", full_mask);
+		return KSFT_FAIL;
+	}
+
+	ret = write_schemata("", "0", uparams->cpu, test->resource);
+	if (min_cbm_bits && !ret) {
+		ksft_print_msg("Empty CBM was accepted, must be rejected\n");
+		return KSFT_FAIL;
+	}
+	if (!min_cbm_bits && ret) {
+		ksft_print_msg("Empty CBM was rejected, must be accepted\n");
+		return KSFT_FAIL;
+	}
+
+	/* A mask with a bit outside cbm_mask must be rejected. */
+	invalid_mask = (unsigned long long)full_mask | (1ULL << count_of_bits);
+	snprintf(schemata, sizeof(schemata), "%llx", invalid_mask);
+	if (!write_schemata("", schemata, uparams->cpu, test->resource)) {
+		ksft_print_msg("Out-of-range CBM 0x%llx was accepted, must be rejected\n",
+			       invalid_mask);
+		return KSFT_FAIL;
+	}
+
+	/*
+	 * When min_cbm_bits is greater than one, a non-empty mask with fewer
+	 * bits must be rejected.
+	 */
+	if (min_cbm_bits > 1) {
+		contiguous_bits = count_contiguous_bits(full_mask, &start);
+		if (contiguous_bits < min_cbm_bits) {
+			ksft_print_msg("Full CBM has %u contiguous bits, fewer than "
+				       "min_cbm_bits=%u\n",
+				       contiguous_bits, min_cbm_bits);
+			return KSFT_FAIL;
+		}
+
+		invalid_mask = create_bit_mask(start, min_cbm_bits - 1);
+		snprintf(schemata, sizeof(schemata), "%llx", invalid_mask);
+		if (!write_schemata("", schemata, uparams->cpu,
+				    test->resource)) {
+			ksft_print_msg("CBM 0x%llx with too few bits was accepted\n",
+				       invalid_mask);
+			return KSFT_FAIL;
+		}
+	}
+
+	ksft_print_msg("Pass: L3 CBM writes were validated correctly\n");
+
+	return 0;
+}
+
 struct resctrl_test l3_cat_test = {
 	.name = "L3_CAT",
 	.group = "CAT",
@@ -366,6 +449,14 @@ struct resctrl_test l3_cat_test = {
 	.cleanup = cat_test_cleanup,
 };
 
+struct resctrl_test l3_cbm_validate_test = {
+	.name = "L3_CBM_VALIDATE",
+	.group = "CAT",
+	.resource = "L3",
+	.feature_check = test_resource_feature_check,
+	.run_test = cbm_validate_run_test,
+};
+
 struct resctrl_test l3_noncont_cat_test = {
 	.name = "L3_NONCONT_CAT",
 	.group = "CAT",
diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
index 175101022bf3..a6fc688ed997 100644
--- a/tools/testing/selftests/resctrl/resctrl.h
+++ b/tools/testing/selftests/resctrl/resctrl.h
@@ -240,6 +240,7 @@ extern struct resctrl_test mbm_test;
 extern struct resctrl_test mba_test;
 extern struct resctrl_test cmt_test;
 extern struct resctrl_test l3_cat_test;
+extern struct resctrl_test l3_cbm_validate_test;
 extern struct resctrl_test l3_noncont_cat_test;
 extern struct resctrl_test l2_noncont_cat_test;
 
diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c
index dbcd5eea9fbc..57a4d0815b67 100644
--- a/tools/testing/selftests/resctrl/resctrl_tests.c
+++ b/tools/testing/selftests/resctrl/resctrl_tests.c
@@ -19,6 +19,7 @@ static struct resctrl_test *resctrl_tests[] = {
 	&mba_test,
 	&cmt_test,
 	&l3_cat_test,
+	&l3_cbm_validate_test,
 	&l3_noncont_cat_test,
 	&l2_noncont_cat_test,
 };
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH v2 2/2] selftests/resctrl: Add L3_BIT_USAGE to check allocation reporting
  2026-08-10  9:51 [PATCH v2 0/2] selftests/resctrl: Increase L3 cache test coverage Richard Cheng
  2026-08-10  9:51 ` [PATCH v2 1/2] selftests/resctrl: Add L3_CBM_VALIDATE to check CBM writes Richard Cheng
@ 2026-08-10  9:51 ` Richard Cheng
  1 sibling, 0 replies; 3+ messages in thread
From: Richard Cheng @ 2026-08-10  9:51 UTC (permalink / raw)
  To: tony.luck, shuah, reinette.chatre
  Cc: Dave.Martin, james.morse, babu.moger, linux-kernel,
	linux-kselftest, fenghuay, newtonl, kristinc, kaihengf, kobak,
	sdonthineni, Richard Cheng

Add L3_BIT_USAGE to verify that info/L3/bit_usage follows the root
group's CBM.

Write full, low, and high valid masks, then check the selected domain.
Require X or S for portions used by SW and H or 0 for portions outside
the allocation.

Signed-off-by: Richard Cheng <icheng@nvidia.com>
---
Changelog:

v1 -> v2:
    - Simplify helper names.
    - Add an explicit character-validity helper
    - Simplify parsing and avoid fixed-length input
    - Move domain lookup into the mask checker
    - Generate masks according to min_cbm_bits
    - Remove unnecessary CBM restoration
    - Move tail comments above assignments
    - Use KSFT_FAIL and reverse-fir-tree ordering
---
 tools/testing/selftests/resctrl/cat_test.c    | 194 ++++++++++++++++++
 tools/testing/selftests/resctrl/resctrl.h     |   1 +
 .../testing/selftests/resctrl/resctrl_tests.c |   1 +
 3 files changed, 196 insertions(+)

diff --git a/tools/testing/selftests/resctrl/cat_test.c b/tools/testing/selftests/resctrl/cat_test.c
index a06c57954740..9205f93fd669 100644
--- a/tools/testing/selftests/resctrl/cat_test.c
+++ b/tools/testing/selftests/resctrl/cat_test.c
@@ -440,6 +440,192 @@ static int cbm_validate_run_test(const struct resctrl_test *test,
 	return 0;
 }
 
+/*
+ * L3_BIT_USAGE - Verify info/L3/bit_usage reflects the allocation.
+ *
+ * bit_usage annotates each cache portion. 'X' and 'S' mean software uses the
+ * portion, while 'H' and '0' mean it does not. With only the root group
+ * present, bit_usage must track the root CBM bit-for-bit.
+ */
+static bool bit_used_by_sw(char c)
+{
+	return c == 'X' || c == 'S';
+}
+
+static bool bit_unused_by_sw(char c)
+{
+	return c == 'H' || c == '0';
+}
+
+static bool bit_usage_valid(char c)
+{
+	return bit_used_by_sw(c) || bit_unused_by_sw(c);
+}
+
+static int bit_usage_for_domain(const char *resource, int domain_id,
+				char *out, size_t out_len)
+{
+	char path[PATH_MAX], *line = NULL, *saveptr;
+	char *usage, *endptr, *id;
+	size_t line_len = 0;
+	long parsed_id;
+	ssize_t bytes;
+	FILE *fp;
+	int ret;
+
+	snprintf(path, sizeof(path), "%s/%s/bit_usage", INFO_PATH, resource);
+	fp = fopen(path, "r");
+	if (!fp) {
+		ksft_perror("Error opening bit_usage");
+		return -errno;
+	}
+
+	bytes = getline(&line, &line_len, fp);
+	fclose(fp);
+	if (bytes < 0) {
+		ksft_print_msg("Error reading bit_usage\n");
+		free(line);
+		return -EIO;
+	}
+
+	ret = -ENOENT;
+	for (id = strtok_r(line, "=;\n", &saveptr); id;
+	     id = strtok_r(NULL, "=;\n", &saveptr)) {
+		usage = strtok_r(NULL, "=;\n", &saveptr);
+		if (!usage)
+			break;
+
+		errno = 0;
+		parsed_id = strtol(id, &endptr, 10);
+		if (errno || *endptr || parsed_id != domain_id)
+			continue;
+
+		ret = snprintf(out, out_len, "%s", usage);
+		if (ret < 0 || (size_t)ret >= out_len)
+			ret = -ENOSPC;
+		else
+			ret = 0;
+		goto out;
+	}
+
+	ksft_print_msg("No bit_usage entry for domain %d\n", domain_id);
+out:
+	free(line);
+	return ret;
+}
+
+static int bit_usage_check_mask(const struct resctrl_test *test, int cpu,
+				unsigned long mask, unsigned int count_of_bits)
+{
+	char usage[sizeof(unsigned long) * 8 + 1];
+	char schemata[64];
+	unsigned int i;
+	int domain_id;
+	int ret;
+
+	snprintf(schemata, sizeof(schemata), "%lx", mask);
+	ret = write_schemata("", schemata, cpu, test->resource);
+	if (ret) {
+		ksft_print_msg("Failed to set CBM 0x%lx\n", mask);
+		return ret;
+	}
+
+	ret = get_domain_id(test->resource, cpu, &domain_id);
+	if (ret < 0)
+		return ret;
+
+	ret = bit_usage_for_domain(test->resource, domain_id, usage,
+				   sizeof(usage));
+	if (ret)
+		return ret;
+
+	if (strlen(usage) != count_of_bits) {
+		ksft_print_msg("bit_usage \"%s\" has %zu chars, expected %u\n",
+			       usage, strlen(usage), count_of_bits);
+		return KSFT_FAIL;
+	}
+
+	for (i = 0; i < count_of_bits; i++) {
+		bool in_cbm;
+		int bit;
+		char c;
+
+		bit = count_of_bits - 1 - i;
+		in_cbm = (mask >> bit) & 1;
+		c = usage[i];
+
+		if (!bit_usage_valid(c)) {
+			ksft_print_msg("Invalid bit_usage character '%c' for CBM 0x%lx\n",
+				       c, mask);
+			return KSFT_FAIL;
+		}
+		if (in_cbm != bit_used_by_sw(c)) {
+			ksft_print_msg("CBM 0x%lx portion %d shows '%c', %s allocation\n",
+				       mask, bit, c, in_cbm ? "in" : "not in");
+			return KSFT_FAIL;
+		}
+	}
+
+	return 0;
+}
+
+static int bit_usage_run_test(const struct resctrl_test *test,
+			      const struct user_params *uparams)
+{
+	unsigned int count_of_bits, min_cbm_bits, partial_bits;
+	unsigned long full_mask, high_mask, masks[3];
+	unsigned int nr_masks = 1;
+	unsigned int i;
+	int ret;
+
+	ret = get_full_cbm(test->resource, &full_mask);
+	if (ret)
+		return ret;
+
+	ret = resource_info_unsigned_get(test->resource, "min_cbm_bits",
+					 &min_cbm_bits);
+	if (ret)
+		return ret;
+
+	count_of_bits = count_bits(full_mask);
+
+	/* Every cache portion. */
+	masks[0] = full_mask;
+
+	if (count_of_bits > min_cbm_bits) {
+		partial_bits = count_of_bits / 2;
+		partial_bits = max(partial_bits, min_cbm_bits);
+
+		/* Lowest valid partial allocation. */
+		masks[nr_masks++] = create_bit_mask(0, partial_bits);
+
+		if (partial_bits) {
+			/* Highest valid partial allocation. */
+			high_mask = create_bit_mask(count_of_bits - partial_bits,
+						    partial_bits);
+			if (high_mask != masks[nr_masks - 1])
+				masks[nr_masks++] = high_mask;
+		}
+	}
+
+	for (i = 0; i < nr_masks; i++) {
+		ret = bit_usage_check_mask(test, uparams->cpu, masks[i],
+					   count_of_bits);
+		if (ret)
+			return ret;
+	}
+
+	ksft_print_msg("Pass: bit_usage reflects the allocation\n");
+
+	return 0;
+}
+
+static bool bit_usage_feature_check(const struct resctrl_test *test)
+{
+	return test_resource_feature_check(test) &&
+	       resource_info_file_exists(test->resource, "bit_usage");
+}
+
 struct resctrl_test l3_cat_test = {
 	.name = "L3_CAT",
 	.group = "CAT",
@@ -457,6 +643,14 @@ struct resctrl_test l3_cbm_validate_test = {
 	.run_test = cbm_validate_run_test,
 };
 
+struct resctrl_test l3_bit_usage_test = {
+	.name = "L3_BIT_USAGE",
+	.group = "CAT",
+	.resource = "L3",
+	.feature_check = bit_usage_feature_check,
+	.run_test = bit_usage_run_test,
+};
+
 struct resctrl_test l3_noncont_cat_test = {
 	.name = "L3_NONCONT_CAT",
 	.group = "CAT",
diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h
index a6fc688ed997..765aa5d5814d 100644
--- a/tools/testing/selftests/resctrl/resctrl.h
+++ b/tools/testing/selftests/resctrl/resctrl.h
@@ -241,6 +241,7 @@ extern struct resctrl_test mba_test;
 extern struct resctrl_test cmt_test;
 extern struct resctrl_test l3_cat_test;
 extern struct resctrl_test l3_cbm_validate_test;
+extern struct resctrl_test l3_bit_usage_test;
 extern struct resctrl_test l3_noncont_cat_test;
 extern struct resctrl_test l2_noncont_cat_test;
 
diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c
index 57a4d0815b67..e6e948d55f38 100644
--- a/tools/testing/selftests/resctrl/resctrl_tests.c
+++ b/tools/testing/selftests/resctrl/resctrl_tests.c
@@ -20,6 +20,7 @@ static struct resctrl_test *resctrl_tests[] = {
 	&cmt_test,
 	&l3_cat_test,
 	&l3_cbm_validate_test,
+	&l3_bit_usage_test,
 	&l3_noncont_cat_test,
 	&l2_noncont_cat_test,
 };
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-08-10  9:51 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-10  9:51 [PATCH v2 0/2] selftests/resctrl: Increase L3 cache test coverage Richard Cheng
2026-08-10  9:51 ` [PATCH v2 1/2] selftests/resctrl: Add L3_CBM_VALIDATE to check CBM writes Richard Cheng
2026-08-10  9:51 ` [PATCH v2 2/2] selftests/resctrl: Add L3_BIT_USAGE to check allocation reporting Richard Cheng

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox