The MBM (Memory Bandwidth Monitoring) and MBA (Memory Bandwidth Allocation) features are not enabled for AMD systems. The reason was lack of perf counters to compare the resctrl test results.
Starting with the commit 25e56847821f ("perf/x86/amd/uncore: Add memory controller support"), AMD now supports the UMC (Unified Memory Controller) perf events. These events can be used to compare the test results.
This series adds the support to detect the UMC events and enable MBM/MBA tests for AMD systems.
v3: Note: Based the series on top of latest kselftests/master 1613e604df0cd359cf2a7fbd9be7a0bcfacfabd0 (tag: v6.10-rc1).
Also applied the patches from the series https://lore.kernel.org/lkml/20240531131142.1716-1-ilpo.jarvinen@linux.intel...
Separated the fix patch. Renamed the imc to just mc to make it generic. Changed the search string "uncore_imc_" and "amd_umc_" Changes related rebase to latest kselftest tree.
v2: Changes. a. Rebased on top of tip/master (Apr 25, 2024) b. Addressed Ilpo comments except the one about close call. It seems more clear to keep READ and WRITE separate. https://lore.kernel.org/lkml/8e4badb7-6cc5-61f1-e041-d902209a90d5@linux.inte... c. Used ksft_perror call when applicable. d. Added vendor check for non contiguous CBM check.
v1: https://lore.kernel.org/lkml/cover.1708637563.git.babu.moger@amd.com/
Babu Moger (4): selftests/resctrl: Rename variables and functions to generic names selftests/resctrl: Pass sysfs controller name of the vendor selftests/resctrl: Add support for MBM and MBA tests on AMD selftests/resctrl: Enable MBA/MBA tests on AMD
tools/testing/selftests/resctrl/mba_test.c | 25 +- tools/testing/selftests/resctrl/mbm_test.c | 23 +- tools/testing/selftests/resctrl/resctrl.h | 2 +- tools/testing/selftests/resctrl/resctrl_val.c | 305 ++++++++++-------- tools/testing/selftests/resctrl/resctrlfs.c | 2 +- 5 files changed, 191 insertions(+), 166 deletions(-)
In an effort to support MBM and MBA tests for AMD, renaming for variable and functions to generic names. For Intel, the memory controller is called Integrated Memory Controllers (IMC). For AMD, it is called Unified Memory Controller (UMC).
Change the names of variables and functions from imc (Integrated memory controller) to mc(Memory Controller). No functional change.
Signed-off-by: Babu Moger babu.moger@amd.com --- v3: More name changes. Mostly replacing imc with mc.
v2: Few more name changes. --- tools/testing/selftests/resctrl/mba_test.c | 24 +- tools/testing/selftests/resctrl/mbm_test.c | 22 +- tools/testing/selftests/resctrl/resctrl.h | 2 +- tools/testing/selftests/resctrl/resctrl_val.c | 225 +++++++++--------- tools/testing/selftests/resctrl/resctrlfs.c | 2 +- 5 files changed, 138 insertions(+), 137 deletions(-)
diff --git a/tools/testing/selftests/resctrl/mba_test.c b/tools/testing/selftests/resctrl/mba_test.c index ab8496a4925b..394bbfd8a93e 100644 --- a/tools/testing/selftests/resctrl/mba_test.c +++ b/tools/testing/selftests/resctrl/mba_test.c @@ -21,7 +21,7 @@ static int mba_init(const struct resctrl_val_param *param, int domain_id) { int ret;
- ret = initialize_mem_bw_imc(); + ret = initialize_mem_bw_mc(); if (ret) return ret;
@@ -70,7 +70,7 @@ static int mba_measure(const struct user_params *uparams, return measure_mem_bw(uparams, param, bm_pid, "reads"); }
-static bool show_mba_info(unsigned long *bw_imc, unsigned long *bw_resc) +static bool show_mba_info(unsigned long *bw_mc, unsigned long *bw_resc) { int allocation, runs; bool ret = false; @@ -79,8 +79,8 @@ static bool show_mba_info(unsigned long *bw_imc, unsigned long *bw_resc) /* Memory bandwidth from 100% down to 10% */ for (allocation = 0; allocation < ALLOCATION_MAX / ALLOCATION_STEP; allocation++) { - unsigned long sum_bw_imc = 0, sum_bw_resc = 0; - long avg_bw_imc, avg_bw_resc; + unsigned long sum_bw_mc = 0, sum_bw_resc = 0; + long avg_bw_mc, avg_bw_resc; int avg_diff_per; float avg_diff;
@@ -90,13 +90,13 @@ static bool show_mba_info(unsigned long *bw_imc, unsigned long *bw_resc) */ for (runs = NUM_OF_RUNS * allocation + 1; runs < NUM_OF_RUNS * allocation + NUM_OF_RUNS ; runs++) { - sum_bw_imc += bw_imc[runs]; + sum_bw_mc += bw_mc[runs]; sum_bw_resc += bw_resc[runs]; }
- avg_bw_imc = sum_bw_imc / (NUM_OF_RUNS - 1); + avg_bw_mc = sum_bw_mc / (NUM_OF_RUNS - 1); avg_bw_resc = sum_bw_resc / (NUM_OF_RUNS - 1); - avg_diff = (float)labs(avg_bw_resc - avg_bw_imc) / avg_bw_imc; + avg_diff = (float)labs(avg_bw_resc - avg_bw_mc) / avg_bw_mc; avg_diff_per = (int)(avg_diff * 100);
ksft_print_msg("%s Check MBA diff within %d%% for schemata %u\n", @@ -106,7 +106,7 @@ static bool show_mba_info(unsigned long *bw_imc, unsigned long *bw_resc) ALLOCATION_MAX - ALLOCATION_STEP * allocation);
ksft_print_msg("avg_diff_per: %d%%\n", avg_diff_per); - ksft_print_msg("avg_bw_imc: %lu\n", avg_bw_imc); + ksft_print_msg("avg_bw_mc: %lu\n", avg_bw_mc); ksft_print_msg("avg_bw_resc: %lu\n", avg_bw_resc); if (avg_diff_per > MAX_DIFF_PERCENT) ret = true; @@ -123,7 +123,7 @@ static bool show_mba_info(unsigned long *bw_imc, unsigned long *bw_resc) static int check_results(void) { char *token_array[8], output[] = RESULT_FILE_NAME, temp[512]; - unsigned long bw_imc[1024], bw_resc[1024]; + unsigned long bw_mc[1024], bw_resc[1024]; int runs; FILE *fp;
@@ -144,8 +144,8 @@ static int check_results(void) token = strtok(NULL, ":\t"); }
- /* Field 3 is perf imc value */ - bw_imc[runs] = strtoul(token_array[3], NULL, 0); + /* Field 3 is perf mc value */ + bw_mc[runs] = strtoul(token_array[3], NULL, 0); /* Field 5 is resctrl value */ bw_resc[runs] = strtoul(token_array[5], NULL, 0); runs++; @@ -153,7 +153,7 @@ static int check_results(void)
fclose(fp);
- return show_mba_info(bw_imc, bw_resc); + return show_mba_info(bw_mc, bw_resc); }
static void mba_test_cleanup(void) diff --git a/tools/testing/selftests/resctrl/mbm_test.c b/tools/testing/selftests/resctrl/mbm_test.c index 6b5a3b52d861..9b6f7f162282 100644 --- a/tools/testing/selftests/resctrl/mbm_test.c +++ b/tools/testing/selftests/resctrl/mbm_test.c @@ -15,10 +15,10 @@ #define NUM_OF_RUNS 5
static int -show_bw_info(unsigned long *bw_imc, unsigned long *bw_resc, size_t span) +show_bw_info(unsigned long *bw_mc, unsigned long *bw_resc, size_t span) { - unsigned long sum_bw_imc = 0, sum_bw_resc = 0; - long avg_bw_imc = 0, avg_bw_resc = 0; + unsigned long sum_bw_mc = 0, sum_bw_resc = 0; + long avg_bw_mc = 0, avg_bw_resc = 0; int runs, ret, avg_diff_per; float avg_diff = 0;
@@ -27,13 +27,13 @@ show_bw_info(unsigned long *bw_imc, unsigned long *bw_resc, size_t span) * transition phase. */ for (runs = 1; runs < NUM_OF_RUNS ; runs++) { - sum_bw_imc += bw_imc[runs]; + sum_bw_mc += bw_mc[runs]; sum_bw_resc += bw_resc[runs]; }
- avg_bw_imc = sum_bw_imc / 4; + avg_bw_mc = sum_bw_mc / 4; avg_bw_resc = sum_bw_resc / 4; - avg_diff = (float)labs(avg_bw_resc - avg_bw_imc) / avg_bw_imc; + avg_diff = (float)labs(avg_bw_resc - avg_bw_mc) / avg_bw_mc; avg_diff_per = (int)(avg_diff * 100);
ret = avg_diff_per > MAX_DIFF_PERCENT; @@ -41,7 +41,7 @@ show_bw_info(unsigned long *bw_imc, unsigned long *bw_resc, size_t span) ret ? "Fail:" : "Pass:", MAX_DIFF_PERCENT); ksft_print_msg("avg_diff_per: %d%%\n", avg_diff_per); ksft_print_msg("Span (MB): %zu\n", span / MB); - ksft_print_msg("avg_bw_imc: %lu\n", avg_bw_imc); + ksft_print_msg("avg_bw_mc: %lu\n", avg_bw_mc); ksft_print_msg("avg_bw_resc: %lu\n", avg_bw_resc);
return ret; @@ -49,7 +49,7 @@ show_bw_info(unsigned long *bw_imc, unsigned long *bw_resc, size_t span)
static int check_results(size_t span) { - unsigned long bw_imc[NUM_OF_RUNS], bw_resc[NUM_OF_RUNS]; + unsigned long bw_mc[NUM_OF_RUNS], bw_resc[NUM_OF_RUNS]; char temp[1024], *token_array[8]; char output[] = RESULT_FILE_NAME; int runs, ret; @@ -75,11 +75,11 @@ static int check_results(size_t span) }
bw_resc[runs] = strtoul(token_array[5], NULL, 0); - bw_imc[runs] = strtoul(token_array[3], NULL, 0); + bw_mc[runs] = strtoul(token_array[3], NULL, 0); runs++; }
- ret = show_bw_info(bw_imc, bw_resc, span); + ret = show_bw_info(bw_mc, bw_resc, span);
fclose(fp);
@@ -90,7 +90,7 @@ static int mbm_init(const struct resctrl_val_param *param, int domain_id) { int ret;
- ret = initialize_mem_bw_imc(); + ret = initialize_mem_bw_mc(); if (ret) return ret;
diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h index 2dda56084588..5f1854986c7b 100644 --- a/tools/testing/selftests/resctrl/resctrl.h +++ b/tools/testing/selftests/resctrl/resctrl.h @@ -143,7 +143,7 @@ unsigned char *alloc_buffer(size_t buf_size, int memflush); void mem_flush(unsigned char *buf, size_t buf_size); void fill_cache_read(unsigned char *buf, size_t buf_size, bool once); int run_fill_buf(size_t buf_size, int memflush, int op, bool once); -int initialize_mem_bw_imc(void); +int initialize_mem_bw_mc(void); int measure_mem_bw(const struct user_params *uparams, struct resctrl_val_param *param, pid_t bm_pid, const char *bw_report); diff --git a/tools/testing/selftests/resctrl/resctrl_val.c b/tools/testing/selftests/resctrl/resctrl_val.c index 35eba2d99d32..2d5e961b3a68 100644 --- a/tools/testing/selftests/resctrl/resctrl_val.c +++ b/tools/testing/selftests/resctrl/resctrl_val.c @@ -15,7 +15,7 @@ #define WRITE_FILE_NAME "events/cas_count_write" #define DYN_PMU_PATH "/sys/bus/event_source/devices" #define SCALE 0.00006103515625 -#define MAX_IMCS 20 +#define MAX_MCS 20 #define MAX_TOKENS 5 #define READ 0 #define WRITE 1 @@ -30,7 +30,7 @@ struct membw_read_format { __u64 id; /* if PERF_FORMAT_ID */ };
-struct imc_counter_config { +struct mc_counter_config { __u32 type; __u64 event; __u64 umask; @@ -40,42 +40,42 @@ struct imc_counter_config { };
static char mbm_total_path[1024]; -static int imcs; -static struct imc_counter_config imc_counters_config[MAX_IMCS][2]; +static int mcs; +static struct mc_counter_config mc_counters_config[MAX_MCS][2]; static const struct resctrl_test *current_test;
void membw_initialize_perf_event_attr(int i, int j) { - memset(&imc_counters_config[i][j].pe, 0, + memset(&mc_counters_config[i][j].pe, 0, sizeof(struct perf_event_attr)); - imc_counters_config[i][j].pe.type = imc_counters_config[i][j].type; - imc_counters_config[i][j].pe.size = sizeof(struct perf_event_attr); - imc_counters_config[i][j].pe.disabled = 1; - imc_counters_config[i][j].pe.inherit = 1; - imc_counters_config[i][j].pe.exclude_guest = 0; - imc_counters_config[i][j].pe.config = - imc_counters_config[i][j].umask << 8 | - imc_counters_config[i][j].event; - imc_counters_config[i][j].pe.sample_type = PERF_SAMPLE_IDENTIFIER; - imc_counters_config[i][j].pe.read_format = + mc_counters_config[i][j].pe.type = mc_counters_config[i][j].type; + mc_counters_config[i][j].pe.size = sizeof(struct perf_event_attr); + mc_counters_config[i][j].pe.disabled = 1; + mc_counters_config[i][j].pe.inherit = 1; + mc_counters_config[i][j].pe.exclude_guest = 0; + mc_counters_config[i][j].pe.config = + mc_counters_config[i][j].umask << 8 | + mc_counters_config[i][j].event; + mc_counters_config[i][j].pe.sample_type = PERF_SAMPLE_IDENTIFIER; + mc_counters_config[i][j].pe.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING; }
void membw_ioctl_perf_event_ioc_reset_enable(int i, int j) { - ioctl(imc_counters_config[i][j].fd, PERF_EVENT_IOC_RESET, 0); - ioctl(imc_counters_config[i][j].fd, PERF_EVENT_IOC_ENABLE, 0); + ioctl(mc_counters_config[i][j].fd, PERF_EVENT_IOC_RESET, 0); + ioctl(mc_counters_config[i][j].fd, PERF_EVENT_IOC_ENABLE, 0); }
void membw_ioctl_perf_event_ioc_disable(int i, int j) { - ioctl(imc_counters_config[i][j].fd, PERF_EVENT_IOC_DISABLE, 0); + ioctl(mc_counters_config[i][j].fd, PERF_EVENT_IOC_DISABLE, 0); }
/* * get_event_and_umask: Parse config into event and umask * @cas_count_cfg: Config - * @count: iMC number + * @count: MC number * @op: Operation (read/write) */ void get_event_and_umask(char *cas_count_cfg, int count, bool op) @@ -94,18 +94,18 @@ void get_event_and_umask(char *cas_count_cfg, int count, bool op) break; if (strcmp(token[i], "event") == 0) { if (op == READ) - imc_counters_config[count][READ].event = + mc_counters_config[count][READ].event = strtol(token[i + 1], NULL, 16); else - imc_counters_config[count][WRITE].event = + mc_counters_config[count][WRITE].event = strtol(token[i + 1], NULL, 16); } if (strcmp(token[i], "umask") == 0) { if (op == READ) - imc_counters_config[count][READ].umask = + mc_counters_config[count][READ].umask = strtol(token[i + 1], NULL, 16); else - imc_counters_config[count][WRITE].umask = + mc_counters_config[count][WRITE].umask = strtol(token[i + 1], NULL, 16); } } @@ -113,13 +113,13 @@ void get_event_and_umask(char *cas_count_cfg, int count, bool op)
static int open_perf_event(int i, int cpu_no, int j) { - imc_counters_config[i][j].fd = - perf_event_open(&imc_counters_config[i][j].pe, -1, cpu_no, -1, + mc_counters_config[i][j].fd = + perf_event_open(&mc_counters_config[i][j].pe, -1, cpu_no, -1, PERF_FLAG_FD_CLOEXEC);
- if (imc_counters_config[i][j].fd == -1) { + if (mc_counters_config[i][j].fd == -1) { fprintf(stderr, "Error opening leader %llx\n", - imc_counters_config[i][j].pe.config); + mc_counters_config[i][j].pe.config);
return -1; } @@ -127,41 +127,41 @@ static int open_perf_event(int i, int cpu_no, int j) return 0; }
-/* Get type and config (read and write) of an iMC counter */ -static int read_from_imc_dir(char *imc_dir, int count) +/* Get type and config (read and write) of an MC counter */ +static int read_from_mc_dir(char *mc_dir, int count) { - char cas_count_cfg[1024], imc_counter_cfg[1024], imc_counter_type[1024]; + char cas_count_cfg[1024], mc_counter_cfg[1024], mc_counter_type[1024]; FILE *fp;
- /* Get type of iMC counter */ - sprintf(imc_counter_type, "%s%s", imc_dir, "type"); - fp = fopen(imc_counter_type, "r"); + /* Get type of MC counter */ + sprintf(mc_counter_type, "%s%s", mc_dir, "type"); + fp = fopen(mc_counter_type, "r"); if (!fp) { - ksft_perror("Failed to open iMC counter type file"); + ksft_perror("Failed to open MC counter type file");
return -1; } - if (fscanf(fp, "%u", &imc_counters_config[count][READ].type) <= 0) { - ksft_perror("Could not get iMC type"); + if (fscanf(fp, "%u", &mc_counters_config[count][READ].type) <= 0) { + ksft_perror("Could not get MC type"); fclose(fp);
return -1; } fclose(fp);
- imc_counters_config[count][WRITE].type = - imc_counters_config[count][READ].type; + mc_counters_config[count][WRITE].type = + mc_counters_config[count][READ].type;
/* Get read config */ - sprintf(imc_counter_cfg, "%s%s", imc_dir, READ_FILE_NAME); - fp = fopen(imc_counter_cfg, "r"); + sprintf(mc_counter_cfg, "%s%s", mc_dir, READ_FILE_NAME); + fp = fopen(mc_counter_cfg, "r"); if (!fp) { - ksft_perror("Failed to open iMC config file"); + ksft_perror("Failed to open MC config file");
return -1; } if (fscanf(fp, "%s", cas_count_cfg) <= 0) { - ksft_perror("Could not get iMC cas count read"); + ksft_perror("Could not get MC cas count read"); fclose(fp);
return -1; @@ -171,15 +171,15 @@ static int read_from_imc_dir(char *imc_dir, int count) get_event_and_umask(cas_count_cfg, count, READ);
/* Get write config */ - sprintf(imc_counter_cfg, "%s%s", imc_dir, WRITE_FILE_NAME); - fp = fopen(imc_counter_cfg, "r"); + sprintf(mc_counter_cfg, "%s%s", mc_dir, WRITE_FILE_NAME); + fp = fopen(mc_counter_cfg, "r"); if (!fp) { - ksft_perror("Failed to open iMC config file"); + ksft_perror("Failed to open MC config file");
return -1; } if (fscanf(fp, "%s", cas_count_cfg) <= 0) { - ksft_perror("Could not get iMC cas count write"); + ksft_perror("Could not get MC cas count write"); fclose(fp);
return -1; @@ -192,17 +192,18 @@ static int read_from_imc_dir(char *imc_dir, int count) }
/* - * A system can have 'n' number of iMC (Integrated Memory Controller) - * counters, get that 'n'. For each iMC counter get it's type and config. + * A system can have 'n' number of iMC (Integrated Memory Controller for + * Intel) counters, get that 'n'. In case of AMD it is called UMC (Unified + * Memory Controller). For each iMC/UMC counter get it's type and config. * Also, each counter has two configs, one for read and the other for write. * A config again has two parts, event and umask. * Enumerate all these details into an array of structures. * * Return: >= 0 on success. < 0 on failure. */ -static int num_of_imcs(void) +static int num_of_mem_controllers(void) { - char imc_dir[512], *temp; + char mc_dir[512], *temp; unsigned int count = 0; struct dirent *ep; int ret; @@ -230,9 +231,9 @@ static int num_of_imcs(void) * first character is a numerical digit or not. */ if (temp[0] >= '0' && temp[0] <= '9') { - sprintf(imc_dir, "%s/%s/", DYN_PMU_PATH, + sprintf(mc_dir, "%s/%s/", DYN_PMU_PATH, ep->d_name); - ret = read_from_imc_dir(imc_dir, count); + ret = read_from_mc_dir(mc_dir, count); if (ret) { closedir(dp);
@@ -243,7 +244,7 @@ static int num_of_imcs(void) } closedir(dp); if (count == 0) { - ksft_print_msg("Unable to find iMC counters\n"); + ksft_print_msg("Unable to find MC counters\n");
return -1; } @@ -256,55 +257,55 @@ static int num_of_imcs(void) return count; }
-int initialize_mem_bw_imc(void) +int initialize_mem_bw_mc(void) { - int imc, j; + int mc, j;
- imcs = num_of_imcs(); - if (imcs <= 0) - return imcs; + mcs = num_of_mem_controllers(); + if (mcs <= 0) + return mcs;
- /* Initialize perf_event_attr structures for all iMC's */ - for (imc = 0; imc < imcs; imc++) { + /* Initialize perf_event_attr structures for all MC's */ + for (mc = 0; mc < mcs; mc++) { for (j = 0; j < 2; j++) - membw_initialize_perf_event_attr(imc, j); + membw_initialize_perf_event_attr(mc, j); }
return 0; }
-static void perf_close_imc_mem_bw(void) +static void perf_close_mc_mem_bw(void) { int mc;
- for (mc = 0; mc < imcs; mc++) { - if (imc_counters_config[mc][READ].fd != -1) - close(imc_counters_config[mc][READ].fd); - if (imc_counters_config[mc][WRITE].fd != -1) - close(imc_counters_config[mc][WRITE].fd); + for (mc = 0; mc < mcs; mc++) { + if (mc_counters_config[mc][READ].fd != -1) + close(mc_counters_config[mc][READ].fd); + if (mc_counters_config[mc][WRITE].fd != -1) + close(mc_counters_config[mc][WRITE].fd); } }
/* - * perf_open_imc_mem_bw - Open perf fds for IMCs + * perf_open_mc_mem_bw - Open perf fds for MCs * @cpu_no: CPU number that the benchmark PID is binded to * * Return: = 0 on success. < 0 on failure. */ -static int perf_open_imc_mem_bw(int cpu_no) +static int perf_open_mc_mem_bw(int cpu_no) { - int imc, ret; + int mc, ret;
- for (imc = 0; imc < imcs; imc++) { - imc_counters_config[imc][READ].fd = -1; - imc_counters_config[imc][WRITE].fd = -1; + for (mc = 0; mc < mcs; mc++) { + mc_counters_config[mc][READ].fd = -1; + mc_counters_config[mc][WRITE].fd = -1; }
- for (imc = 0; imc < imcs; imc++) { - ret = open_perf_event(imc, cpu_no, READ); + for (mc = 0; mc < mcs; mc++) { + ret = open_perf_event(mc, cpu_no, READ); if (ret) goto close_fds; - ret = open_perf_event(imc, cpu_no, WRITE); + ret = open_perf_event(mc, cpu_no, WRITE); if (ret) goto close_fds; } @@ -312,7 +313,7 @@ static int perf_open_imc_mem_bw(int cpu_no) return 0;
close_fds: - perf_close_imc_mem_bw(); + perf_close_mc_mem_bw(); return -1; }
@@ -322,21 +323,21 @@ static int perf_open_imc_mem_bw(int cpu_no) * Runs memory bandwidth test over one second period. Also, handles starting * and stopping of the IMC perf counters around the test. */ -static void do_imc_mem_bw_test(void) +static void do_mc_mem_bw_test(void) { - int imc; + int mc;
- for (imc = 0; imc < imcs; imc++) { - membw_ioctl_perf_event_ioc_reset_enable(imc, READ); - membw_ioctl_perf_event_ioc_reset_enable(imc, WRITE); + for (mc = 0; mc < mcs; mc++) { + membw_ioctl_perf_event_ioc_reset_enable(mc, READ); + membw_ioctl_perf_event_ioc_reset_enable(mc, WRITE); }
sleep(1);
/* Stop counters after a second to get results (both read and write) */ - for (imc = 0; imc < imcs; imc++) { - membw_ioctl_perf_event_ioc_disable(imc, READ); - membw_ioctl_perf_event_ioc_disable(imc, WRITE); + for (mc = 0; mc < mcs; mc++) { + membw_ioctl_perf_event_ioc_disable(mc, READ); + membw_ioctl_perf_event_ioc_disable(mc, WRITE); } }
@@ -349,10 +350,10 @@ static void do_imc_mem_bw_test(void) * * Return: = 0 on success. < 0 on failure. */ -static int get_mem_bw_imc(const char *bw_report, float *bw_imc) +static int get_mem_bw_mc(const char *bw_report, float *bw_mc) { float reads, writes, of_mul_read, of_mul_write; - int imc; + int mc;
/* Start all iMC counters to log values (both read and write) */ reads = 0, writes = 0, of_mul_read = 1, of_mul_write = 1; @@ -361,21 +362,21 @@ static int get_mem_bw_imc(const char *bw_report, float *bw_imc) * Get results which are stored in struct type imc_counter_config * Take overflow into consideration before calculating total bandwidth. */ - for (imc = 0; imc < imcs; imc++) { - struct imc_counter_config *r = - &imc_counters_config[imc][READ]; - struct imc_counter_config *w = - &imc_counters_config[imc][WRITE]; + for (mc = 0; mc < mcs; mc++) { + struct mc_counter_config *r = + &mc_counters_config[mc][READ]; + struct mc_counter_config *w = + &mc_counters_config[mc][WRITE];
if (read(r->fd, &r->return_value, sizeof(struct membw_read_format)) == -1) { - ksft_perror("Couldn't get read bandwidth through iMC"); + ksft_perror("Couldn't get read bandwidth through MC"); goto close_fds; }
if (read(w->fd, &w->return_value, sizeof(struct membw_read_format)) == -1) { - ksft_perror("Couldn't get write bandwidth through iMC"); + ksft_perror("Couldn't get write bandwidth through MC"); goto close_fds; }
@@ -396,23 +397,23 @@ static int get_mem_bw_imc(const char *bw_report, float *bw_imc) writes += w->return_value.value * of_mul_write * SCALE; }
- perf_close_imc_mem_bw(); + perf_close_mc_mem_bw();
if (strcmp(bw_report, "reads") == 0) { - *bw_imc = reads; + *bw_mc = reads; return 0; }
if (strcmp(bw_report, "writes") == 0) { - *bw_imc = writes; + *bw_mc = writes; return 0; }
- *bw_imc = reads + writes; + *bw_mc = reads + writes; return 0;
close_fds: - perf_close_imc_mem_bw(); + perf_close_mc_mem_bw(); return -1; }
@@ -523,19 +524,19 @@ static void parent_exit(pid_t ppid) * print_results_bw: the memory bandwidth results are stored in a file * @filename: file that stores the results * @bm_pid: child pid that runs benchmark - * @bw_imc: perf imc counter value + * @bw_mc: perf mc counter value * @bw_resc: memory bandwidth value * * Return: 0 on success, < 0 on error. */ -static int print_results_bw(char *filename, pid_t bm_pid, float bw_imc, +static int print_results_bw(char *filename, pid_t bm_pid, float bw_mc, unsigned long bw_resc) { - unsigned long diff = fabs(bw_imc - bw_resc); + unsigned long diff = fabs(bw_mc - bw_resc); FILE *fp;
if (strcmp(filename, "stdio") == 0 || strcmp(filename, "stderr") == 0) { - printf("Pid: %d \t Mem_BW_iMC: %f \t ", (int)bm_pid, bw_imc); + printf("Pid: %d \t Mem_BW_MC: %f \t ", (int)bm_pid, bw_mc); printf("Mem_BW_resc: %lu \t Difference: %lu\n", bw_resc, diff); } else { fp = fopen(filename, "a"); @@ -544,8 +545,8 @@ static int print_results_bw(char *filename, pid_t bm_pid, float bw_imc,
return -1; } - if (fprintf(fp, "Pid: %d \t Mem_BW_iMC: %f \t Mem_BW_resc: %lu \t Difference: %lu\n", - (int)bm_pid, bw_imc, bw_resc, diff) <= 0) { + if (fprintf(fp, "Pid: %d \t Mem_BW_MC: %f \t Mem_BW_resc: %lu \t Difference: %lu\n", + (int)bm_pid, bw_mc, bw_resc, diff) <= 0) { ksft_print_msg("Could not log results\n"); fclose(fp);
@@ -570,7 +571,7 @@ int measure_mem_bw(const struct user_params *uparams, { unsigned long bw_resc, bw_resc_start, bw_resc_end; FILE *mem_bw_fp; - float bw_imc; + float bw_mc; int ret;
bw_report = get_bw_report_type(bw_report); @@ -583,12 +584,12 @@ int measure_mem_bw(const struct user_params *uparams,
/* * Measure memory bandwidth from resctrl and from - * another source which is perf imc value or could - * be something else if perf imc event is not available. + * another source which is perf mc value or could + * be something else if perf mc event is not available. * Compare the two values to validate resctrl value. * It takes 1sec to measure the data. */ - ret = perf_open_imc_mem_bw(uparams->cpu); + ret = perf_open_mc_mem_bw(uparams->cpu); if (ret < 0) goto close_fp;
@@ -598,13 +599,13 @@ int measure_mem_bw(const struct user_params *uparams,
rewind(mem_bw_fp);
- do_imc_mem_bw_test(); + do_mc_mem_bw_test();
ret = get_mem_bw_resctrl(mem_bw_fp, &bw_resc_end); if (ret < 0) goto close_fp;
- ret = get_mem_bw_imc(bw_report, &bw_imc); + ret = get_mem_bw_mc(bw_report, &bw_mc); if (ret < 0) goto close_fp;
@@ -612,7 +613,7 @@ int measure_mem_bw(const struct user_params *uparams,
bw_resc = (bw_resc_end - bw_resc_start) / MB;
- return print_results_bw(param->filename, bm_pid, bw_imc, bw_resc); + return print_results_bw(param->filename, bm_pid, bw_mc, bw_resc);
close_fp: fclose(mem_bw_fp); diff --git a/tools/testing/selftests/resctrl/resctrlfs.c b/tools/testing/selftests/resctrl/resctrlfs.c index 891ebfbfbd85..4f37278bc8e5 100644 --- a/tools/testing/selftests/resctrl/resctrlfs.c +++ b/tools/testing/selftests/resctrl/resctrlfs.c @@ -843,7 +843,7 @@ const char *get_bw_report_type(const char *bw_report) if (strcmp(bw_report, "total") == 0) return bw_report;
- fprintf(stderr, "Requested iMC bandwidth report type unavailable\n"); + fprintf(stderr, "Requested MC bandwidth report type unavailable\n");
return NULL; }
Hi Babu,
On 6/5/24 3:45 PM, Babu Moger wrote:
In an effort to support MBM and MBA tests for AMD, renaming for variable and functions to generic names. For Intel, the memory controller is called
Changelog usually starts with some context and then problem to be solved. What the patch does follows that. Maybe just something like:
For Intel, the memory controller is called Integrated Memory Controller (IMC). For AMD, it is called Unified Memory Controller (UMC).
Change the names of variables and functions from imc to mc in preparation for support of MBM and MBA tests for AMD.
No functional change.
Integrated Memory Controllers (IMC). For AMD, it is called Unified Memory Controller (UMC).
Change the names of variables and functions from imc (Integrated memory controller) to mc(Memory Controller). No functional change.
Signed-off-by: Babu Moger babu.moger@amd.com
...
@@ -349,10 +350,10 @@ static void do_imc_mem_bw_test(void)
- Return: = 0 on success. < 0 on failure.
*/ -static int get_mem_bw_imc(const char *bw_report, float *bw_imc) +static int get_mem_bw_mc(const char *bw_report, float *bw_mc)
The name of the function is expected to be changed in the function comments also.
{ float reads, writes, of_mul_read, of_mul_write;
- int imc;
- int mc;
/* Start all iMC counters to log values (both read and write) */
Was this intended to be MC?
reads = 0, writes = 0, of_mul_read = 1, of_mul_write = 1; @@ -361,21 +362,21 @@ static int get_mem_bw_imc(const char *bw_report, float *bw_imc) * Get results which are stored in struct type imc_counter_config * Take overflow into consideration before calculating total bandwidth. */
In below snippet imc_counter_config is renamed to mc_counter_config yet the comment above was not changed to match.
- for (imc = 0; imc < imcs; imc++) {
struct imc_counter_config *r =
&imc_counters_config[imc][READ];
struct imc_counter_config *w =
&imc_counters_config[imc][WRITE];
- for (mc = 0; mc < mcs; mc++) {
struct mc_counter_config *r =
&mc_counters_config[mc][READ];
struct mc_counter_config *w =
&mc_counters_config[mc][WRITE];
I noticed a couple of misses by just looking at this patch. You can use grep to ensure that this patch does what you intend.
Reinette
Hi Reinette,
On 6/14/24 13:37, Reinette Chatre wrote:
Hi Babu,
On 6/5/24 3:45 PM, Babu Moger wrote:
In an effort to support MBM and MBA tests for AMD, renaming for variable and functions to generic names. For Intel, the memory controller is called
Changelog usually starts with some context and then problem to be solved. What the patch does follows that. Maybe just something like:
For Intel, the memory controller is called Integrated Memory Controller (IMC). For AMD, it is called Unified Memory Controller (UMC). Change the names of variables and functions from imc to mc in preparation for support of MBM and MBA tests for AMD. No functional change.
Sure.
Integrated Memory Controllers (IMC). For AMD, it is called Unified Memory Controller (UMC).
Change the names of variables and functions from imc (Integrated memory controller) to mc(Memory Controller). No functional change.
Signed-off-by: Babu Moger babu.moger@amd.com
...
@@ -349,10 +350,10 @@ static void do_imc_mem_bw_test(void) * * Return: = 0 on success. < 0 on failure. */ -static int get_mem_bw_imc(const char *bw_report, float *bw_imc) +static int get_mem_bw_mc(const char *bw_report, float *bw_mc)
The name of the function is expected to be changed in the function comments also.
Ok.
{ float reads, writes, of_mul_read, of_mul_write; - int imc; + int mc; /* Start all iMC counters to log values (both read and write) */
Was this intended to be MC?
Yes.
reads = 0, writes = 0, of_mul_read = 1, of_mul_write = 1; @@ -361,21 +362,21 @@ static int get_mem_bw_imc(const char *bw_report, float *bw_imc) * Get results which are stored in struct type imc_counter_config * Take overflow into consideration before calculating total bandwidth. */
In below snippet imc_counter_config is renamed to mc_counter_config yet the comment above was not changed to match.
Will correct it.
- for (imc = 0; imc < imcs; imc++) { - struct imc_counter_config *r = - &imc_counters_config[imc][READ]; - struct imc_counter_config *w = - &imc_counters_config[imc][WRITE]; + for (mc = 0; mc < mcs; mc++) { + struct mc_counter_config *r = + &mc_counters_config[mc][READ]; + struct mc_counter_config *w = + &mc_counters_config[mc][WRITE];
I noticed a couple of misses by just looking at this patch. You can use grep to ensure that this patch does what you intend.
Sure.-- Thanks Babu Moger
The test detects number of memory controllers by looking at the sysfs file system. Detect the vendor to pass the controller name appropriately. So, that rest of the code will be generic and can be used to support other vendors.
Also change the search to look for the full string "uncore_imc_". Replace the sizeof with strlen.
Signed-off-by: Babu Moger babu.moger@amd.com --- v3: Change the search string to "uncore_imc_".
v2: No changes --- tools/testing/selftests/resctrl/resctrl_val.c | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/tools/testing/selftests/resctrl/resctrl_val.c b/tools/testing/selftests/resctrl/resctrl_val.c index 2d5e961b3a68..23c0e0a1d845 100644 --- a/tools/testing/selftests/resctrl/resctrl_val.c +++ b/tools/testing/selftests/resctrl/resctrl_val.c @@ -10,7 +10,7 @@ */ #include "resctrl.h"
-#define UNCORE_IMC "uncore_imc" +#define UNCORE_IMC "uncore_imc_" #define READ_FILE_NAME "events/cas_count_read" #define WRITE_FILE_NAME "events/cas_count_write" #define DYN_PMU_PATH "/sys/bus/event_source/devices" @@ -206,24 +206,30 @@ static int num_of_mem_controllers(void) char mc_dir[512], *temp; unsigned int count = 0; struct dirent *ep; - int ret; + char *sysfs_name; + int ret, vendor; DIR *dp;
+ vendor = get_vendor(); + if (vendor == ARCH_INTEL) { + sysfs_name = UNCORE_IMC; + } else { + ksft_perror("Unsupported vendor!\n"); + return -1; + } + dp = opendir(DYN_PMU_PATH); if (dp) { while ((ep = readdir(dp))) { - temp = strstr(ep->d_name, UNCORE_IMC); + temp = strstr(ep->d_name, sysfs_name); if (!temp) continue;
/* * imc counters are named as "uncore_imc_<n>", hence - * increment the pointer to point to <n>. Note that - * sizeof(UNCORE_IMC) would count for null character as - * well and hence the last underscore character in - * uncore_imc'_' need not be counted. + * increment the pointer to point to <n>. */ - temp = temp + sizeof(UNCORE_IMC); + temp = temp + strlen(sysfs_name);
/* * Some directories under "DYN_PMU_PATH" could have
Hi Babu,
Subject and changelog mentions how controller name is "passed" but the patch does not seem to "pass" anything new.
On 6/5/24 3:45 PM, Babu Moger wrote:
The test detects number of memory controllers by looking at the sysfs file system. Detect the vendor to pass the controller name appropriately. So, that rest of the code will be generic and can be used to support other vendors.
Also change the search to look for the full string "uncore_imc_". Replace the sizeof with strlen.
Signed-off-by: Babu Moger babu.moger@amd.com
v3: Change the search string to "uncore_imc_".
v2: No changes
tools/testing/selftests/resctrl/resctrl_val.c | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/tools/testing/selftests/resctrl/resctrl_val.c b/tools/testing/selftests/resctrl/resctrl_val.c index 2d5e961b3a68..23c0e0a1d845 100644 --- a/tools/testing/selftests/resctrl/resctrl_val.c +++ b/tools/testing/selftests/resctrl/resctrl_val.c @@ -10,7 +10,7 @@ */ #include "resctrl.h" -#define UNCORE_IMC "uncore_imc" +#define UNCORE_IMC "uncore_imc_" #define READ_FILE_NAME "events/cas_count_read" #define WRITE_FILE_NAME "events/cas_count_write" #define DYN_PMU_PATH "/sys/bus/event_source/devices" @@ -206,24 +206,30 @@ static int num_of_mem_controllers(void) char mc_dir[512], *temp; unsigned int count = 0; struct dirent *ep;
- int ret;
- char *sysfs_name;
- int ret, vendor; DIR *dp;
- vendor = get_vendor();
get_vendor() is already optimized to only need to do actual detection once. I thus do not see a need for a local variable.
- if (vendor == ARCH_INTEL) {
sysfs_name = UNCORE_IMC;
- } else {
ksft_perror("Unsupported vendor!\n");
ksft_perror() also adds a "\n" so adding it here is not necessary. Also please drop the exclamation.
return -1;
- }
- dp = opendir(DYN_PMU_PATH); if (dp) { while ((ep = readdir(dp))) {
temp = strstr(ep->d_name, UNCORE_IMC);
temp = strstr(ep->d_name, sysfs_name); if (!temp) continue;
/* * imc counters are named as "uncore_imc_<n>", hence
* increment the pointer to point to <n>. Note that
* sizeof(UNCORE_IMC) would count for null character as
* well and hence the last underscore character in
* uncore_imc'_' need not be counted.
* increment the pointer to point to <n>. */
temp = temp + sizeof(UNCORE_IMC);
temp = temp + strlen(sysfs_name);
/* * Some directories under "DYN_PMU_PATH" could have
Reinette
Hi Reinette,
On 6/14/24 13:38, Reinette Chatre wrote:
Hi Babu,
Subject and changelog mentions how controller name is "passed" but the patch does not seem to "pass" anything new.
Sure. Will change the subject to this. Also will update the commit message.
selftests/resctrl: Dynamically detect sysfs controller name of the vendor
On 6/5/24 3:45 PM, Babu Moger wrote:
The test detects number of memory controllers by looking at the sysfs file system. Detect the vendor to pass the controller name appropriately. So, that rest of the code will be generic and can be used to support other vendors.
Also change the search to look for the full string "uncore_imc_". Replace the sizeof with strlen.
Signed-off-by: Babu Moger babu.moger@amd.com
v3: Change the search string to "uncore_imc_".
v2: No changes
tools/testing/selftests/resctrl/resctrl_val.c | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/tools/testing/selftests/resctrl/resctrl_val.c b/tools/testing/selftests/resctrl/resctrl_val.c index 2d5e961b3a68..23c0e0a1d845 100644 --- a/tools/testing/selftests/resctrl/resctrl_val.c +++ b/tools/testing/selftests/resctrl/resctrl_val.c @@ -10,7 +10,7 @@ */ #include "resctrl.h" -#define UNCORE_IMC "uncore_imc" +#define UNCORE_IMC "uncore_imc_" #define READ_FILE_NAME "events/cas_count_read" #define WRITE_FILE_NAME "events/cas_count_write" #define DYN_PMU_PATH "/sys/bus/event_source/devices" @@ -206,24 +206,30 @@ static int num_of_mem_controllers(void) char mc_dir[512], *temp; unsigned int count = 0; struct dirent *ep; - int ret; + char *sysfs_name; + int ret, vendor; DIR *dp; + vendor = get_vendor();
get_vendor() is already optimized to only need to do actual detection once. I thus do not see a need for a local variable.
Sure.
+ if (vendor == ARCH_INTEL) { + sysfs_name = UNCORE_IMC; + } else { + ksft_perror("Unsupported vendor!\n");
ksft_perror() also adds a "\n" so adding it here is not necessary. Also please drop the exclamation.
Sure.
+ return -1; + }
dp = opendir(DYN_PMU_PATH); if (dp) { while ((ep = readdir(dp))) { - temp = strstr(ep->d_name, UNCORE_IMC); + temp = strstr(ep->d_name, sysfs_name); if (!temp) continue; /* * imc counters are named as "uncore_imc_<n>", hence - * increment the pointer to point to <n>. Note that - * sizeof(UNCORE_IMC) would count for null character as - * well and hence the last underscore character in - * uncore_imc'_' need not be counted. + * increment the pointer to point to <n>. */ - temp = temp + sizeof(UNCORE_IMC); + temp = temp + strlen(sysfs_name); /* * Some directories under "DYN_PMU_PATH" could have
Reinette
Add support to read UMC (Unified Memory Controller) perf events to compare the numbers with QoS monitor for AMD.
Signed-off-by: Babu Moger babu.moger@amd.com --- v3: Made read_from_mc_dir function generic to both AMD and Intel. Rest are mostly related to rebase.
v2: Replace perror with ksft_perror. --- tools/testing/selftests/resctrl/resctrl_val.c | 80 ++++++++++++------- 1 file changed, 50 insertions(+), 30 deletions(-)
diff --git a/tools/testing/selftests/resctrl/resctrl_val.c b/tools/testing/selftests/resctrl/resctrl_val.c index 23c0e0a1d845..ffacafb535cd 100644 --- a/tools/testing/selftests/resctrl/resctrl_val.c +++ b/tools/testing/selftests/resctrl/resctrl_val.c @@ -11,6 +11,7 @@ #include "resctrl.h"
#define UNCORE_IMC "uncore_imc_" +#define AMD_UMC "amd_umc_" #define READ_FILE_NAME "events/cas_count_read" #define WRITE_FILE_NAME "events/cas_count_write" #define DYN_PMU_PATH "/sys/bus/event_source/devices" @@ -128,7 +129,7 @@ static int open_perf_event(int i, int cpu_no, int j) }
/* Get type and config (read and write) of an MC counter */ -static int read_from_mc_dir(char *mc_dir, int count) +static int read_from_mc_dir(char *mc_dir, int count, int vendor) { char cas_count_cfg[1024], mc_counter_cfg[1024], mc_counter_type[1024]; FILE *fp; @@ -152,41 +153,56 @@ static int read_from_mc_dir(char *mc_dir, int count) mc_counters_config[count][WRITE].type = mc_counters_config[count][READ].type;
- /* Get read config */ - sprintf(mc_counter_cfg, "%s%s", mc_dir, READ_FILE_NAME); - fp = fopen(mc_counter_cfg, "r"); - if (!fp) { - ksft_perror("Failed to open MC config file"); + if (vendor == ARCH_AMD) { + /* + * Setup the event and umasks for UMC events + * Number of CAS commands sent for reads: + * EventCode = 0x0a, umask = 0x1 + * Number of CAS commands sent for writes: + * EventCode = 0x0a, umask = 0x2 + */ + mc_counters_config[count][READ].event = 0xa; + mc_counters_config[count][READ].umask = 0x1;
- return -1; - } - if (fscanf(fp, "%s", cas_count_cfg) <= 0) { - ksft_perror("Could not get MC cas count read"); + mc_counters_config[count][WRITE].event = 0xa; + mc_counters_config[count][WRITE].umask = 0x2; + } else { + /* Get read config */ + sprintf(mc_counter_cfg, "%s%s", mc_dir, READ_FILE_NAME); + fp = fopen(mc_counter_cfg, "r"); + if (!fp) { + ksft_perror("Failed to open MC config file"); + + return -1; + } + if (fscanf(fp, "%s", cas_count_cfg) <= 0) { + ksft_perror("Could not get MC cas count read"); + fclose(fp); + + return -1; + } fclose(fp);
- return -1; - } - fclose(fp); + get_event_and_umask(cas_count_cfg, count, READ);
- get_event_and_umask(cas_count_cfg, count, READ); + /* Get write config */ + sprintf(mc_counter_cfg, "%s%s", mc_dir, WRITE_FILE_NAME); + fp = fopen(mc_counter_cfg, "r"); + if (!fp) { + ksft_perror("Failed to open MC config file");
- /* Get write config */ - sprintf(mc_counter_cfg, "%s%s", mc_dir, WRITE_FILE_NAME); - fp = fopen(mc_counter_cfg, "r"); - if (!fp) { - ksft_perror("Failed to open MC config file"); + return -1; + } + if (fscanf(fp, "%s", cas_count_cfg) <= 0) { + ksft_perror("Could not get MC cas count write"); + fclose(fp);
- return -1; - } - if (fscanf(fp, "%s", cas_count_cfg) <= 0) { - ksft_perror("Could not get MC cas count write"); + return -1; + } fclose(fp);
- return -1; + get_event_and_umask(cas_count_cfg, count, WRITE); } - fclose(fp); - - get_event_and_umask(cas_count_cfg, count, WRITE);
return 0; } @@ -213,6 +229,8 @@ static int num_of_mem_controllers(void) vendor = get_vendor(); if (vendor == ARCH_INTEL) { sysfs_name = UNCORE_IMC; + } else if (vendor == ARCH_AMD) { + sysfs_name = AMD_UMC; } else { ksft_perror("Unsupported vendor!\n"); return -1; @@ -228,6 +246,7 @@ static int num_of_mem_controllers(void) /* * imc counters are named as "uncore_imc_<n>", hence * increment the pointer to point to <n>. + * For AMD, it will be amd_umc_<n>. */ temp = temp + strlen(sysfs_name);
@@ -239,7 +258,7 @@ static int num_of_mem_controllers(void) if (temp[0] >= '0' && temp[0] <= '9') { sprintf(mc_dir, "%s/%s/", DYN_PMU_PATH, ep->d_name); - ret = read_from_mc_dir(mc_dir, count); + ret = read_from_mc_dir(mc_dir, count, vendor); if (ret) { closedir(dp);
@@ -250,8 +269,9 @@ static int num_of_mem_controllers(void) } closedir(dp); if (count == 0) { - ksft_print_msg("Unable to find MC counters\n"); - + ksft_print_msg("Unable to find iMC/UMC counters\n"); + if (vendor == ARCH_AMD) + ksft_print_msg("Try loading amd_uncore module\n"); return -1; } } else {
Hi Babu,
On 6/5/24 3:45 PM, Babu Moger wrote:
Add support to read UMC (Unified Memory Controller) perf events to compare the numbers with QoS monitor for AMD.
Signed-off-by: Babu Moger babu.moger@amd.com
v3: Made read_from_mc_dir function generic to both AMD and Intel. Rest are mostly related to rebase.
v2: Replace perror with ksft_perror.
tools/testing/selftests/resctrl/resctrl_val.c | 80 ++++++++++++------- 1 file changed, 50 insertions(+), 30 deletions(-)
diff --git a/tools/testing/selftests/resctrl/resctrl_val.c b/tools/testing/selftests/resctrl/resctrl_val.c index 23c0e0a1d845..ffacafb535cd 100644 --- a/tools/testing/selftests/resctrl/resctrl_val.c +++ b/tools/testing/selftests/resctrl/resctrl_val.c @@ -11,6 +11,7 @@ #include "resctrl.h" #define UNCORE_IMC "uncore_imc_" +#define AMD_UMC "amd_umc_" #define READ_FILE_NAME "events/cas_count_read" #define WRITE_FILE_NAME "events/cas_count_write" #define DYN_PMU_PATH "/sys/bus/event_source/devices" @@ -128,7 +129,7 @@ static int open_perf_event(int i, int cpu_no, int j) } /* Get type and config (read and write) of an MC counter */ -static int read_from_mc_dir(char *mc_dir, int count) +static int read_from_mc_dir(char *mc_dir, int count, int vendor) { char cas_count_cfg[1024], mc_counter_cfg[1024], mc_counter_type[1024]; FILE *fp; @@ -152,41 +153,56 @@ static int read_from_mc_dir(char *mc_dir, int count) mc_counters_config[count][WRITE].type = mc_counters_config[count][READ].type;
- /* Get read config */
- sprintf(mc_counter_cfg, "%s%s", mc_dir, READ_FILE_NAME);
- fp = fopen(mc_counter_cfg, "r");
- if (!fp) {
ksft_perror("Failed to open MC config file");
- if (vendor == ARCH_AMD) {
/*
* Setup the event and umasks for UMC events
* Number of CAS commands sent for reads:
* EventCode = 0x0a, umask = 0x1
* Number of CAS commands sent for writes:
* EventCode = 0x0a, umask = 0x2
*/
mc_counters_config[count][READ].event = 0xa;
mc_counters_config[count][READ].umask = 0x1;
return -1;
- }
- if (fscanf(fp, "%s", cas_count_cfg) <= 0) {
ksft_perror("Could not get MC cas count read");
mc_counters_config[count][WRITE].event = 0xa;
mc_counters_config[count][WRITE].umask = 0x2;
- } else {
/* Get read config */
sprintf(mc_counter_cfg, "%s%s", mc_dir, READ_FILE_NAME);
fp = fopen(mc_counter_cfg, "r");
if (!fp) {
ksft_perror("Failed to open MC config file");
return -1;
}
if (fscanf(fp, "%s", cas_count_cfg) <= 0) {
ksft_perror("Could not get MC cas count read");
fclose(fp);
return -1;
fclose(fp);}
return -1;
- }
- fclose(fp);
get_event_and_umask(cas_count_cfg, count, READ);
- get_event_and_umask(cas_count_cfg, count, READ);
/* Get write config */
sprintf(mc_counter_cfg, "%s%s", mc_dir, WRITE_FILE_NAME);
fp = fopen(mc_counter_cfg, "r");
if (!fp) {
ksft_perror("Failed to open MC config file");
- /* Get write config */
- sprintf(mc_counter_cfg, "%s%s", mc_dir, WRITE_FILE_NAME);
- fp = fopen(mc_counter_cfg, "r");
- if (!fp) {
ksft_perror("Failed to open MC config file");
return -1;
}
if (fscanf(fp, "%s", cas_count_cfg) <= 0) {
ksft_perror("Could not get MC cas count write");
fclose(fp);
return -1;
- }
- if (fscanf(fp, "%s", cas_count_cfg) <= 0) {
ksft_perror("Could not get MC cas count write");
return -1;
fclose(fp);}
return -1;
}get_event_and_umask(cas_count_cfg, count, WRITE);
- fclose(fp);
- get_event_and_umask(cas_count_cfg, count, WRITE);
return 0; } @@ -213,6 +229,8 @@ static int num_of_mem_controllers(void) vendor = get_vendor(); if (vendor == ARCH_INTEL) { sysfs_name = UNCORE_IMC;
- } else if (vendor == ARCH_AMD) {
} else { ksft_perror("Unsupported vendor!\n"); return -1;sysfs_name = AMD_UMC;
@@ -228,6 +246,7 @@ static int num_of_mem_controllers(void) /* * imc counters are named as "uncore_imc_<n>", hence * increment the pointer to point to <n>.
* For AMD, it will be amd_umc_<n>. */ temp = temp + strlen(sysfs_name);
@@ -239,7 +258,7 @@ static int num_of_mem_controllers(void) if (temp[0] >= '0' && temp[0] <= '9') { sprintf(mc_dir, "%s/%s/", DYN_PMU_PATH, ep->d_name);
ret = read_from_mc_dir(mc_dir, count);
ret = read_from_mc_dir(mc_dir, count, vendor); if (ret) { closedir(dp);
@@ -250,8 +269,9 @@ static int num_of_mem_controllers(void) } closedir(dp); if (count == 0) {
ksft_print_msg("Unable to find MC counters\n");
ksft_print_msg("Unable to find iMC/UMC counters\n");
if (vendor == ARCH_AMD)
} } else {ksft_print_msg("Try loading amd_uncore module\n"); return -1;
Can all the vendor checking be contained in num_of_mem_controllers() instead of scattered through multiple layers? There can be two vendor specific functions to initialize mc_counters_config[][]. Only the type setting code ends up being shared so that can be split into a function that is called by both vendor functions?
Reinette
Hi Reinette,
On 6/14/24 13:39, Reinette Chatre wrote:
Hi Babu,
On 6/5/24 3:45 PM, Babu Moger wrote:
Add support to read UMC (Unified Memory Controller) perf events to compare the numbers with QoS monitor for AMD.
Signed-off-by: Babu Moger babu.moger@amd.com
v3: Made read_from_mc_dir function generic to both AMD and Intel. Rest are mostly related to rebase.
v2: Replace perror with ksft_perror.
tools/testing/selftests/resctrl/resctrl_val.c | 80 ++++++++++++------- 1 file changed, 50 insertions(+), 30 deletions(-)
diff --git a/tools/testing/selftests/resctrl/resctrl_val.c b/tools/testing/selftests/resctrl/resctrl_val.c index 23c0e0a1d845..ffacafb535cd 100644 --- a/tools/testing/selftests/resctrl/resctrl_val.c +++ b/tools/testing/selftests/resctrl/resctrl_val.c @@ -11,6 +11,7 @@ #include "resctrl.h" #define UNCORE_IMC "uncore_imc_" +#define AMD_UMC "amd_umc_" #define READ_FILE_NAME "events/cas_count_read" #define WRITE_FILE_NAME "events/cas_count_write" #define DYN_PMU_PATH "/sys/bus/event_source/devices" @@ -128,7 +129,7 @@ static int open_perf_event(int i, int cpu_no, int j) } /* Get type and config (read and write) of an MC counter */ -static int read_from_mc_dir(char *mc_dir, int count) +static int read_from_mc_dir(char *mc_dir, int count, int vendor) { char cas_count_cfg[1024], mc_counter_cfg[1024], mc_counter_type[1024]; FILE *fp; @@ -152,41 +153,56 @@ static int read_from_mc_dir(char *mc_dir, int count) mc_counters_config[count][WRITE].type = mc_counters_config[count][READ].type; - /* Get read config */ - sprintf(mc_counter_cfg, "%s%s", mc_dir, READ_FILE_NAME); - fp = fopen(mc_counter_cfg, "r"); - if (!fp) { - ksft_perror("Failed to open MC config file"); + if (vendor == ARCH_AMD) { + /* + * Setup the event and umasks for UMC events + * Number of CAS commands sent for reads: + * EventCode = 0x0a, umask = 0x1 + * Number of CAS commands sent for writes: + * EventCode = 0x0a, umask = 0x2 + */ + mc_counters_config[count][READ].event = 0xa; + mc_counters_config[count][READ].umask = 0x1; - return -1; - } - if (fscanf(fp, "%s", cas_count_cfg) <= 0) { - ksft_perror("Could not get MC cas count read"); + mc_counters_config[count][WRITE].event = 0xa; + mc_counters_config[count][WRITE].umask = 0x2; + } else { + /* Get read config */ + sprintf(mc_counter_cfg, "%s%s", mc_dir, READ_FILE_NAME); + fp = fopen(mc_counter_cfg, "r"); + if (!fp) { + ksft_perror("Failed to open MC config file");
+ return -1; + } + if (fscanf(fp, "%s", cas_count_cfg) <= 0) { + ksft_perror("Could not get MC cas count read"); + fclose(fp);
+ return -1; + } fclose(fp); - return -1; - } - fclose(fp); + get_event_and_umask(cas_count_cfg, count, READ); - get_event_and_umask(cas_count_cfg, count, READ); + /* Get write config */ + sprintf(mc_counter_cfg, "%s%s", mc_dir, WRITE_FILE_NAME); + fp = fopen(mc_counter_cfg, "r"); + if (!fp) { + ksft_perror("Failed to open MC config file"); - /* Get write config */ - sprintf(mc_counter_cfg, "%s%s", mc_dir, WRITE_FILE_NAME); - fp = fopen(mc_counter_cfg, "r"); - if (!fp) { - ksft_perror("Failed to open MC config file"); + return -1; + } + if (fscanf(fp, "%s", cas_count_cfg) <= 0) { + ksft_perror("Could not get MC cas count write"); + fclose(fp); - return -1; - } - if (fscanf(fp, "%s", cas_count_cfg) <= 0) { - ksft_perror("Could not get MC cas count write"); + return -1; + } fclose(fp); - return -1; + get_event_and_umask(cas_count_cfg, count, WRITE); } - fclose(fp);
- get_event_and_umask(cas_count_cfg, count, WRITE); return 0; } @@ -213,6 +229,8 @@ static int num_of_mem_controllers(void) vendor = get_vendor(); if (vendor == ARCH_INTEL) { sysfs_name = UNCORE_IMC; + } else if (vendor == ARCH_AMD) { + sysfs_name = AMD_UMC; } else { ksft_perror("Unsupported vendor!\n"); return -1; @@ -228,6 +246,7 @@ static int num_of_mem_controllers(void) /* * imc counters are named as "uncore_imc_<n>", hence * increment the pointer to point to <n>. + * For AMD, it will be amd_umc_<n>. */ temp = temp + strlen(sysfs_name); @@ -239,7 +258,7 @@ static int num_of_mem_controllers(void) if (temp[0] >= '0' && temp[0] <= '9') { sprintf(mc_dir, "%s/%s/", DYN_PMU_PATH, ep->d_name); - ret = read_from_mc_dir(mc_dir, count); + ret = read_from_mc_dir(mc_dir, count, vendor); if (ret) { closedir(dp); @@ -250,8 +269,9 @@ static int num_of_mem_controllers(void) } closedir(dp); if (count == 0) { - ksft_print_msg("Unable to find MC counters\n");
+ ksft_print_msg("Unable to find iMC/UMC counters\n"); + if (vendor == ARCH_AMD) + ksft_print_msg("Try loading amd_uncore module\n"); return -1; } } else {
Can all the vendor checking be contained in num_of_mem_controllers() instead of scattered through multiple layers? There can be two vendor specific functions to initialize mc_counters_config[][]. Only the type setting code ends up being shared so that can be split into a function that is called by both vendor functions?
Yes, We can do that. Will add it in v4.
Enable MBA/MBM tests if UMC (Unified Memory Controller) support is available on the system. Tests will be skipped otherwise.
Signed-off-by: Babu Moger babu.moger@amd.com --- v3: Separated fix as another patch. https://lore.kernel.org/lkml/3a6c9dd9dc6bda6e2582db049bfe853cd836139f.171762...
v2: No changes. --- tools/testing/selftests/resctrl/mba_test.c | 1 - tools/testing/selftests/resctrl/mbm_test.c | 1 - 2 files changed, 2 deletions(-)
diff --git a/tools/testing/selftests/resctrl/mba_test.c b/tools/testing/selftests/resctrl/mba_test.c index 394bbfd8a93e..5702bb1d6a98 100644 --- a/tools/testing/selftests/resctrl/mba_test.c +++ b/tools/testing/selftests/resctrl/mba_test.c @@ -192,7 +192,6 @@ static bool mba_feature_check(const struct resctrl_test *test) struct resctrl_test mba_test = { .name = "MBA", .resource = "MB", - .vendor_specific = ARCH_INTEL, .feature_check = mba_feature_check, .run_test = mba_run_test, .cleanup = mba_test_cleanup, diff --git a/tools/testing/selftests/resctrl/mbm_test.c b/tools/testing/selftests/resctrl/mbm_test.c index 9b6f7f162282..dbdb1b490df8 100644 --- a/tools/testing/selftests/resctrl/mbm_test.c +++ b/tools/testing/selftests/resctrl/mbm_test.c @@ -162,7 +162,6 @@ static bool mbm_feature_check(const struct resctrl_test *test) struct resctrl_test mbm_test = { .name = "MBM", .resource = "MB", - .vendor_specific = ARCH_INTEL, .feature_check = mbm_feature_check, .run_test = mbm_run_test, .cleanup = mbm_test_cleanup,
Hi Babu,
On 6/5/24 3:45 PM, Babu Moger wrote:
Enable MBA/MBM tests if UMC (Unified Memory Controller) support is available on the system. Tests will be skipped otherwise.
Could you please point out where the test is skipped if UMC is not available?
Reinette
Hi Reinette,
On 6/14/24 13:39, Reinette Chatre wrote:
Hi Babu,
On 6/5/24 3:45 PM, Babu Moger wrote:
Enable MBA/MBM tests if UMC (Unified Memory Controller) support is available on the system. Tests will be skipped otherwise.
Could you please point out where the test is skipped if UMC is not available?
My bad. It is not skipped. It will report as failed in UMC is not detected. I will update the commit message.
linux-kselftest-mirror@lists.linaro.org