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 <[email protected]> --- 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

