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 3/5] selftests/resctrl: Support the MPAM memory bandwidth monitoring layout
Date: Wed, 22 Jul 2026 10:13:01 +0800	[thread overview]
Message-ID: <20260722021303.9471-4-icheng@nvidia.com> (raw)
In-Reply-To: <20260722021303.9471-1-icheng@nvidia.com>

Arm MPAM systems running resctrl expose memory bandwidth differently
from x86:

 - MB control/monitor domains are keyed by NUMA node id, which need
   not match the L3 cache id (on a Grace/Vera system L3 ids are {1,2}
   while MB domains are {0,1,2,10,...}).
 - Monitoring lives in a separate MB_MON resource that provides only
   mbm_total_bytes; there is no local/total split and no L3_MON
   bandwidth event.
 - In "mbm_event" (ABMC) assignment mode a hardware counter must be
   explicitly assigned to a group+domain+event before the bandwidth
   file returns a value (it reads "Unassigned" otherwise), and
   removing a group does not release its counter, so it must be
   unassigned explicitly or it leaks.

Teach the test framework this layout:

 - get_domain_id() resolves MB domains via the CPU's NUMA node when
   the MB_MON resource exists. x86 (no MB_MON) is unaffected.
 - initialize_mem_bw_resctrl() falls back to
   mon_MB_<domain>/mbm_total_bytes when mbm_local_bytes is absent,
   and assigns an ABMC counter when the group's mbm_MB_assignments
   file is present. Note the assignment parser requires a trailing
   newline; without it the write fails with EINVAL.
 - mem_bw_ref_cleanup() unassigns the counter again.
 - The MBA feature check accepts MB_MON's mbm_total_bytes as the
   monitoring source.

Comparing a reference PMU total (read+write) with mbm_total_bytes is
a like-for-like comparison; the iMC path keeps comparing read
bandwidth with mbm_local_bytes as before.

No effect yet on any vendor: the MBA test is still gated to Intel.

Signed-off-by: Richard Cheng <icheng@nvidia.com>
---
 tools/testing/selftests/resctrl/mba_test.c    |  3 +-
 tools/testing/selftests/resctrl/resctrl_val.c | 69 +++++++++++++++++--
 tools/testing/selftests/resctrl/resctrlfs.c   | 45 +++++++++++-
 3 files changed, 111 insertions(+), 6 deletions(-)

diff --git a/tools/testing/selftests/resctrl/mba_test.c b/tools/testing/selftests/resctrl/mba_test.c
index 8b891d3e6650..6c85107c32ee 100644
--- a/tools/testing/selftests/resctrl/mba_test.c
+++ b/tools/testing/selftests/resctrl/mba_test.c
@@ -211,7 +211,8 @@ static int mba_run_test(const struct resctrl_test *test, const struct user_param
 static bool mba_feature_check(const struct resctrl_test *test)
 {
 	return test_resource_feature_check(test) &&
-	       resctrl_mon_feature_exists("L3_MON", "mbm_local_bytes") &&
+	       (resctrl_mon_feature_exists("L3_MON", "mbm_local_bytes") ||
+		resctrl_mon_feature_exists("MB_MON", "mbm_total_bytes")) &&
 	       mem_bw_ref_available();
 }
 
diff --git a/tools/testing/selftests/resctrl/resctrl_val.c b/tools/testing/selftests/resctrl/resctrl_val.c
index a2b919bd4839..0c3079d31340 100644
--- a/tools/testing/selftests/resctrl/resctrl_val.c
+++ b/tools/testing/selftests/resctrl/resctrl_val.c
@@ -20,6 +20,21 @@
 #define CON_MBM_LOCAL_BYTES_PATH		\
 	"%s/%s/mon_data/mon_L3_%02d/mbm_local_bytes"
 
+/*
+ * MPAM exposes only total (read+write) bandwidth, under MB_MON, and per the
+ * NUMA-node-keyed MB domain rather than the L3 cache id.
+ */
+#define CON_MBM_TOTAL_BYTES_PATH		\
+	"%s/%s/mon_data/mon_MB_%02d/mbm_total_bytes"
+
+/*
+ * In MPAM "mbm_event" (ABMC) counter-assignment mode a hardware counter must
+ * be explicitly assigned to a group+domain+event before the bandwidth file
+ * reads a value; otherwise it returns "Unassigned".
+ */
+#define MBM_MB_ASSIGN_PATH			\
+	"%s/%s/mbm_MB_assignments"
+
 struct membw_read_format {
 	__u64 value;         /* The value of the event */
 	__u64 time_enabled;  /* if PERF_FORMAT_TOTAL_TIME_ENABLED */
@@ -58,6 +73,10 @@ static struct mem_bw_counter bw_counters[MAX_BW_COUNTERS];
 static const struct resctrl_test *current_test;
 static const struct mem_bw_backend *mem_bw_backend;
 
+/* MPAM ABMC counter assignment state, see initialize_mem_bw_resctrl(). */
+static char mbm_assign_path[1024];
+static int mbm_assign_domain = -1;
+
 static void read_mem_bw_initialize_perf_event_attr(int i)
 {
 	memset(&bw_counters[i].pe, 0,
@@ -452,21 +471,63 @@ static int get_mem_bw_ref(float *bw_ref)
  * initialize_mem_bw_resctrl:	Appropriately populate "mbm_total_path"
  * @param:	Parameters passed to resctrl_val()
  * @domain_id:	Domain ID (cache ID; for MB, L3 cache ID)
+ *
+ * x86 resctrl reports per-RMID local bandwidth under L3_MON. MPAM exposes only
+ * total (read+write) bandwidth under MB_MON, indexed by the NUMA-node-keyed MB
+ * domain, and in "mbm_event" (ABMC) mode a hardware counter must be assigned to
+ * the group+domain before the file reads a value.
  */
 void initialize_mem_bw_resctrl(const struct resctrl_val_param *param,
 			       int domain_id)
 {
-	sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
-		param->ctrlgrp, domain_id);
+	const char *grp = param->ctrlgrp ? param->ctrlgrp : "";
+
+	if (resctrl_mon_feature_exists("L3_MON", "mbm_local_bytes")) {
+		sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
+			grp, domain_id);
+		return;
+	}
+
+	/* MPAM: total bandwidth under MB_MON. */
+	sprintf(mbm_total_path, CON_MBM_TOTAL_BYTES_PATH, RESCTRL_PATH,
+		grp, domain_id);
+
+	/* Assign an ABMC counter for this group+domain if in mbm_event mode. */
+	snprintf(mbm_assign_path, sizeof(mbm_assign_path), MBM_MB_ASSIGN_PATH,
+		 RESCTRL_PATH, grp);
+	if (access(mbm_assign_path, W_OK) == 0) {
+		FILE *fp = fopen(mbm_assign_path, "w");
+
+		if (fp) {
+			/* The assignment parser requires a trailing newline. */
+			fprintf(fp, "mbm_total_bytes:%d=e\n", domain_id);
+			fclose(fp);
+			mbm_assign_domain = domain_id;
+		}
+	} else {
+		/* Not in counter-assignment mode (or no MB_MON); nothing to do. */
+		mbm_assign_path[0] = '\0';
+	}
 }
 
 /*
- * mem_bw_ref_cleanup - Reset the selected reference-bandwidth backend
+ * mem_bw_ref_cleanup - Release an assigned ABMC counter and reset backend state
  *
- * Safe to call when no backend was selected.
+ * Group removal does not reclaim assigned MPAM counters, so the test must
+ * unassign explicitly. Safe to call when nothing was assigned.
  */
 void mem_bw_ref_cleanup(void)
 {
+	if (mbm_assign_domain >= 0 && mbm_assign_path[0]) {
+		FILE *fp = fopen(mbm_assign_path, "w");
+
+		if (fp) {
+			fprintf(fp, "mbm_total_bytes:%d=_\n", mbm_assign_domain);
+			fclose(fp);
+		}
+	}
+	mbm_assign_domain = -1;
+	mbm_assign_path[0] = '\0';
 	mem_bw_backend = NULL;
 }
 
diff --git a/tools/testing/selftests/resctrl/resctrlfs.c b/tools/testing/selftests/resctrl/resctrlfs.c
index b9c1bfb6cc02..893f6748c68c 100644
--- a/tools/testing/selftests/resctrl/resctrlfs.c
+++ b/tools/testing/selftests/resctrl/resctrlfs.c
@@ -121,11 +121,40 @@ static int get_resource_cache_level(const char *resource)
 	return get_cache_level(resource);
 }
 
+/*
+ * cpu_to_numa_node - NUMA node a logical CPU belongs to
+ * @cpu_no:	CPU number
+ *
+ * Reads the "node<N>" symlink in the CPU's sysfs directory.
+ *
+ * Return: NUMA node id (>= 0) on success, < 0 on failure.
+ */
+static int cpu_to_numa_node(int cpu_no)
+{
+	char cpu_dir[1024];
+	struct dirent *ep;
+	int node = -1;
+	DIR *dp;
+
+	snprintf(cpu_dir, sizeof(cpu_dir), "%s%d", PHYS_ID_PATH, cpu_no);
+	dp = opendir(cpu_dir);
+	if (!dp)
+		return -1;
+	while ((ep = readdir(dp))) {
+		if (!strncmp(ep->d_name, "node", 4) && isdigit(ep->d_name[4])) {
+			node = atoi(ep->d_name + 4);
+			break;
+		}
+	}
+	closedir(dp);
+	return node;
+}
+
 /*
  * get_domain_id - Get resctrl domain ID for a specified CPU
  * @resource:	resource name
  * @cpu_no:	CPU number
- * @domain_id:	domain ID (cache ID; for MB, L3 cache ID)
+ * @domain_id:	domain ID (cache ID; for MB, L3 cache ID, or NUMA node on MPAM)
  *
  * Return: >= 0 on success, < 0 on failure.
  */
@@ -135,6 +164,20 @@ int get_domain_id(const char *resource, int cpu_no, int *domain_id)
 	int cache_num;
 	FILE *fp;
 
+	/*
+	 * On MPAM the MB monitoring/allocation domains are keyed by NUMA node
+	 * (surfaced via a separate MB_MON group) and need not match the L3 cache
+	 * id used on x86, so resolve the MB domain from the CPU's NUMA node.
+	 */
+	if (!strcmp(resource, "MB") && resctrl_resource_exists("MB_MON")) {
+		int node = cpu_to_numa_node(cpu_no);
+
+		if (node >= 0) {
+			*domain_id = node;
+			return 0;
+		}
+	}
+
 	cache_num = get_resource_cache_level(resource);
 	if (cache_num < 0)
 		return cache_num;
-- 
2.43.0


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

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-22  2:12 [PATCH 0/5] selftests/resctrl: Run the MBA test on arm64 MPAM via the NVIDIA SCF PMU Richard Cheng
2026-07-22  2:12 ` [PATCH 1/5] selftests/resctrl: Make memory bandwidth measurement vendor-neutral Richard Cheng
2026-07-22  2:13 ` [PATCH 2/5] selftests/resctrl: Abstract reference bandwidth counters behind a backend Richard Cheng
2026-07-22  2:13 ` Richard Cheng [this message]
2026-07-22  2:13 ` [PATCH 4/5] selftests/resctrl: Gate the MBA test on features, not CPU vendor Richard Cheng
2026-07-22  2:13 ` [PATCH 5/5] selftests/resctrl: Add NVIDIA SCF reference bandwidth backend Richard Cheng

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=20260722021303.9471-4-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.