[RFC patch 7/9] selftests/resctrl: Add support for HiSilicon memory bandwidth measurement

Yifan Wu wuyifan50 at huawei.com
Tue Mar 3 20:03:32 PST 2026


This commit adds support for HiSilicon memory bandwidth measurement by
introducing vendor-specific implementations:

1. Counter Discovery for HiSilicon: A new function num_of_hisi_ddrc()
is implemented. It discovers the HiSilicon DDRC PMUs in the PMU path,
dynamically creating and linking counter structures into the global list
for each one found.

2. Support for config Perf Event Attribute: To adapt HiSilicon's perf
event configuration, struct imc_counter_config is augmented with a
__u64 config field, and get_read_event_and_umask() is updated to parse a
"config" token from the event files. The perf_event_attr configuration
logic now uses this config value if available, falling back to the
event/umask logic for Intel.

3. Resctrl Domain ID Discovery for MB: A new vendor-specific logic is
added to get_domain_id() in resctrlfs.c. On HiSilicon platforms, when the
resource is "MB", the domain ID is discovered by reading the NUMA Node
ID from the CPU's topology path (/sys/devices/system/cpu/cpuX/topology/),
as MPAM's Memory Bandwidth resource is scoped to NUMA domains.

4. Bandwidth Calculation Adjustment: The measure_read_mem_bw() function
is modified to handle the fundamental difference in reporting between
vendors: Intel's resctrl reports a cumulative historical delta value,
which must be converted to a rate division by MB. HiSilicon MPAM reports
a real-time value, which is used directly.

These changes collectively enable the selftests to accurately measure
memory bandwidth on HiSilicon platforms that implement MPAM.

Signed-off-by: Yifan Wu <wuyifan50 at huawei.com>
---
 tools/testing/selftests/resctrl/resctrl_val.c | 67 ++++++++++++++++++-
 tools/testing/selftests/resctrl/resctrlfs.c   | 20 ++++++
 2 files changed, 85 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/resctrl/resctrl_val.c b/tools/testing/selftests/resctrl/resctrl_val.c
index 75a3d359f16b..2c3df653e6ce 100644
--- a/tools/testing/selftests/resctrl/resctrl_val.c
+++ b/tools/testing/selftests/resctrl/resctrl_val.c
@@ -15,6 +15,8 @@
 
 #define CON_MBM_LOCAL_BYTES_PATH		\
 	"%s/%s/mon_data/mon_L3_%02d/mbm_local_bytes"
+#define CON_MBM_TOTAL_BYTES_PATH		\
+	"%s/%s/mon_data/mon_MB_%02d/mbm_total_bytes"
 
 struct membw_read_format {
 	__u64 value;         /* The value of the event */
@@ -27,6 +29,7 @@ struct imc_counter_config {
 	__u32 type;
 	__u64 event;
 	__u64 umask;
+	__u64 config;
 	struct perf_event_attr pe;
 	struct membw_read_format return_value;
 	int fd;
@@ -39,9 +42,11 @@ struct membw_read_config {
 	const char *event;
 	double scale;
 	int (*num_of)(void);
+	const char *mbm_path;
 };
 
 static int num_of_imcs(void);
+static int num_of_hisi_ddrc(void);
 
 static struct membw_read_config membw_read_configs[] = {
 	{
@@ -50,6 +55,15 @@ static struct membw_read_config membw_read_configs[] = {
 		.event = "events/cas_count_read",
 		.scale = 64.0 / MB,
 		.num_of = num_of_imcs,
+		.mbm_path = CON_MBM_LOCAL_BYTES_PATH
+	},
+	{
+		.vendor_id = ARCH_HISILICON,
+		.name = "hisi_sccl%d_ddrc%d_%d",
+		.event = "events/flux_rd",
+		.scale = 32.0 / MB,
+		.num_of = num_of_hisi_ddrc,
+		.mbm_path = CON_MBM_TOTAL_BYTES_PATH
 	},
 	{
 		.vendor_id = NULL
@@ -71,6 +85,7 @@ static void read_mem_bw_initialize_perf_event_attr(struct imc_counter_config *im
 	imc_counters_config->pe.inherit = 1;
 	imc_counters_config->pe.exclude_guest = 0;
 	imc_counters_config->pe.config =
+		imc_counters_config->config ? :
 		imc_counters_config->umask << 8 |
 		imc_counters_config->event;
 	imc_counters_config->pe.sample_type = PERF_SAMPLE_IDENTIFIER;
@@ -114,6 +129,8 @@ static void get_read_event_and_umask(char *cas_count_cfg, struct imc_counter_con
 			imc_counters_config->event = strtol(token[i + 1], NULL, 16);
 		if (strcmp(token[i], "umask") == 0)
 			imc_counters_config->umask = strtol(token[i + 1], NULL, 16);
+		if (strcmp(token[i], "config") == 0)
+			imc_counters_config->config = strtol(token[i + 1], NULL, 16);
 	}
 }
 
@@ -248,6 +265,49 @@ static int num_of_imcs(void)
 	return count;
 }
 
+static int num_of_hisi_ddrc(void)
+{
+	char hisi_ddrc_dir[512], *temp;
+	unsigned int count = 0;
+	struct dirent *ep;
+	int ret;
+	DIR *dp;
+	struct imc_counter_config *imc_counters_config;
+
+	dp = opendir(DYN_PMU_PATH);
+	if (dp) {
+		while ((ep = readdir(dp))) {
+			if (!strstr(ep->d_name, "hisi") || !strstr(ep->d_name, "ddrc"))
+				continue;
+
+			imc_counters_config = malloc(sizeof(struct imc_counter_config));
+			sprintf(hisi_ddrc_dir, "%s/%s/", DYN_PMU_PATH,
+				ep->d_name);
+			ret = read_from_imc_dir(hisi_ddrc_dir, imc_counters_config);
+			if (ret) {
+				free(imc_counters_config);
+				closedir(dp);
+
+				return ret;
+			}
+			list_add(&imc_counters_config->imc_list, &imc_counters_configs);
+			count++;
+		}
+		closedir(dp);
+		if (count == 0) {
+			ksft_print_msg("Unable to find PMU counters\n");
+
+			return -1;
+		}
+	} else {
+		ksft_perror("Unable to open PMU directory");
+
+		return -1;
+	}
+
+	return count;
+}
+
 int initialize_read_mem_bw_imc(void)
 {
 	struct imc_counter_config *imc_counters_config;
@@ -382,7 +442,7 @@ static int get_read_mem_bw_imc(float *bw_imc)
 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,
+	sprintf(mbm_total_path, current_config->mbm_path, RESCTRL_PATH,
 		param->ctrlgrp, domain_id);
 }
 
@@ -579,7 +639,10 @@ int measure_read_mem_bw(const struct user_params *uparams,
 	perf_close_imc_read_mem_bw();
 	fclose(mem_bw_fp);
 
-	bw_resc = (bw_resc_end - bw_resc_start) / MB;
+	if (get_vendor() == ARCH_HISILICON)
+		bw_resc = bw_resc_end;
+	else
+		bw_resc = (bw_resc_end - bw_resc_start) / MB;
 
 	return print_results_bw(param->filename, bm_pid, bw_imc, bw_resc);
 
diff --git a/tools/testing/selftests/resctrl/resctrlfs.c b/tools/testing/selftests/resctrl/resctrlfs.c
index b9c1bfb6cc02..01b775cfe849 100644
--- a/tools/testing/selftests/resctrl/resctrlfs.c
+++ b/tools/testing/selftests/resctrl/resctrlfs.c
@@ -139,6 +139,26 @@ int get_domain_id(const char *resource, int cpu_no, int *domain_id)
 	if (cache_num < 0)
 		return cache_num;
 
+	/* On HiSilicon's platform, the "MB" resource domain is associated with the NUMA Node. */
+	if (get_vendor() == ARCH_HISILICON && !strncmp(resource, "MB", sizeof("MB"))) {
+		struct dirent *ep;
+		DIR *dp;
+
+		sprintf(phys_pkg_path, "%s%d/", PHYS_ID_PATH, cpu_no);
+		dp = opendir(phys_pkg_path);
+		if (dp) {
+			while ((ep = readdir(dp))) {
+				if (!strstr(ep->d_name, "node"))
+					continue;
+				if (sscanf(ep->d_name, "node%d\n", domain_id) == 1)
+					return 0;
+			}
+			closedir(dp);
+		}
+		ksft_perror("Could not get domain ID");
+		return -1;
+	}
+
 	sprintf(phys_pkg_path, "%s%d/cache/index%d/id", PHYS_ID_PATH, cpu_no, cache_num);
 
 	fp = fopen(phys_pkg_path, "r");
-- 
2.33.0




More information about the linux-arm-kernel mailing list