diff options
| author | Mark Brown <broonie@kernel.org> | 2026-05-29 23:14:05 +0100 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-05-29 23:14:05 +0100 |
| commit | 443999b474a41463e49760e4f2ab379614fbb3be (patch) | |
| tree | 6773e51a935531faddacf92c860ffbf9178b8176 /tools | |
| parent | 047aef733de5000d5d4a976c59abd68f0e01f343 (diff) | |
| parent | 5f4974231fb3656c15a82faece9f2303b8c18a14 (diff) | |
| download | linux-next-history-443999b474a41463e49760e4f2ab379614fbb3be.tar.gz | |
Merge branch 'next' of https://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest.git
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/testing/selftests/kselftest.h | 4 | ||||
| -rw-r--r-- | tools/testing/selftests/resctrl/cache.c | 30 | ||||
| -rw-r--r-- | tools/testing/selftests/resctrl/cat_test.c | 41 | ||||
| -rw-r--r-- | tools/testing/selftests/resctrl/cmt_test.c | 36 | ||||
| -rw-r--r-- | tools/testing/selftests/resctrl/fill_buf.c | 4 | ||||
| -rw-r--r-- | tools/testing/selftests/resctrl/mba_test.c | 6 | ||||
| -rw-r--r-- | tools/testing/selftests/resctrl/mbm_test.c | 6 | ||||
| -rw-r--r-- | tools/testing/selftests/resctrl/resctrl.h | 20 | ||||
| -rw-r--r-- | tools/testing/selftests/resctrl/resctrl_val.c | 135 |
9 files changed, 181 insertions, 101 deletions
diff --git a/tools/testing/selftests/kselftest.h b/tools/testing/selftests/kselftest.h index 60838b61a2da5..ae18c491ae533 100644 --- a/tools/testing/selftests/kselftest.h +++ b/tools/testing/selftests/kselftest.h @@ -346,9 +346,9 @@ void ksft_test_result_code(int exit_code, const char *test_name, } /** - * ksft_test_result() - Report test success based on truth of condition + * ksft_test_result_report() - Report test result based on a kselftest exit code * - * @condition: if true, report test success, otherwise failure. + * @result: a kselftest exit code */ #define ksft_test_result_report(result, fmt, ...) do { \ switch (result) { \ diff --git a/tools/testing/selftests/resctrl/cache.c b/tools/testing/selftests/resctrl/cache.c index 1ff1104e65753..df9bea584a2d4 100644 --- a/tools/testing/selftests/resctrl/cache.c +++ b/tools/testing/selftests/resctrl/cache.c @@ -10,7 +10,6 @@ void perf_event_attr_initialize(struct perf_event_attr *pea, __u64 config) memset(pea, 0, sizeof(*pea)); pea->type = PERF_TYPE_HARDWARE; pea->size = sizeof(*pea); - pea->read_format = PERF_FORMAT_GROUP; pea->exclude_kernel = 1; pea->exclude_hv = 1; pea->exclude_idle = 1; @@ -37,19 +36,13 @@ int perf_event_reset_enable(int pe_fd) return 0; } -void perf_event_initialize_read_format(struct perf_event_read *pe_read) -{ - memset(pe_read, 0, sizeof(*pe_read)); - pe_read->nr = 1; -} - int perf_open(struct perf_event_attr *pea, pid_t pid, int cpu_no) { int pe_fd; pe_fd = perf_event_open(pea, pid, cpu_no, -1, PERF_FLAG_FD_CLOEXEC); if (pe_fd == -1) { - ksft_perror("Error opening leader"); + ksft_perror("Unable to set up performance monitoring"); return -1; } @@ -132,9 +125,9 @@ static int print_results_cache(const char *filename, pid_t bm_pid, __u64 llc_val * * Return: =0 on success. <0 on failure. */ -int perf_event_measure(int pe_fd, struct perf_event_read *pe_read, - const char *filename, pid_t bm_pid) +int perf_event_measure(int pe_fd, const char *filename, pid_t bm_pid) { + __u64 value; int ret; /* Stop counters after one span to get miss rate */ @@ -142,13 +135,13 @@ int perf_event_measure(int pe_fd, struct perf_event_read *pe_read, if (ret < 0) return ret; - ret = read(pe_fd, pe_read, sizeof(*pe_read)); + ret = read(pe_fd, &value, sizeof(value)); if (ret == -1) { ksft_perror("Could not get perf value"); return -1; } - return print_results_cache(filename, bm_pid, pe_read->values[0].value); + return print_results_cache(filename, bm_pid, value); } /* @@ -174,6 +167,19 @@ int measure_llc_resctrl(const char *filename, pid_t bm_pid) } /* + * Reduce L2 allocation to minimum when testing L3 cache allocation. + */ +int minimize_l2_occupancy(const struct resctrl_test *test, + const struct user_params *uparams, + const struct resctrl_val_param *param) +{ + if (!strcmp(test->resource, "L3") && resctrl_resource_exists("L2")) + return write_schemata(param->ctrlgrp, "0x1", uparams->cpu, "L2"); + + return 0; +} + +/* * show_cache_info - Show generic cache test information * @no_of_bits: Number of bits * @avg_llc_val: Average of LLC cache result data diff --git a/tools/testing/selftests/resctrl/cat_test.c b/tools/testing/selftests/resctrl/cat_test.c index f00b622c14608..371a2f26dc47b 100644 --- a/tools/testing/selftests/resctrl/cat_test.c +++ b/tools/testing/selftests/resctrl/cat_test.c @@ -14,42 +14,20 @@ #define RESULT_FILE_NAME "result_cat" #define NUM_OF_RUNS 5 -/* - * Minimum difference in LLC misses between a test with n+1 bits CBM to the - * test with n bits is MIN_DIFF_PERCENT_PER_BIT * (n - 1). With e.g. 5 vs 4 - * bits in the CBM mask, the minimum difference must be at least - * MIN_DIFF_PERCENT_PER_BIT * (4 - 1) = 3 percent. - * - * The relationship between number of used CBM bits and difference in LLC - * misses is not expected to be linear. With a small number of bits, the - * margin is smaller than with larger number of bits. For selftest purposes, - * however, linear approach is enough because ultimately only pass/fail - * decision has to be made and distinction between strong and stronger - * signal is irrelevant. - */ -#define MIN_DIFF_PERCENT_PER_BIT 1UL - static int show_results_info(__u64 sum_llc_val, int no_of_bits, unsigned long cache_span, - unsigned long min_diff_percent, unsigned long num_of_runs, bool platform, __s64 *prev_avg_llc_val) { __u64 avg_llc_val = 0; - float avg_diff; int ret = 0; avg_llc_val = sum_llc_val / num_of_runs; if (*prev_avg_llc_val) { - float delta = (__s64)(avg_llc_val - *prev_avg_llc_val); - - avg_diff = delta / *prev_avg_llc_val; - ret = platform && (avg_diff * 100) < (float)min_diff_percent; + ret = platform && (avg_llc_val < *prev_avg_llc_val); - ksft_print_msg("%s Check cache miss rate changed more than %.1f%%\n", - ret ? "Fail:" : "Pass:", (float)min_diff_percent); - - ksft_print_msg("Percent diff=%.1f\n", avg_diff * 100); + ksft_print_msg("%s Check cache miss rate increased\n", + ret ? "Fail:" : "Pass:"); } *prev_avg_llc_val = avg_llc_val; @@ -58,10 +36,10 @@ static int show_results_info(__u64 sum_llc_val, int no_of_bits, return ret; } -/* Remove the highest bit from CBM */ +/* Remove the highest bits from CBM */ static unsigned long next_mask(unsigned long current_mask) { - return current_mask & (current_mask >> 1); + return current_mask & (current_mask >> 2); } static int check_results(struct resctrl_val_param *param, const char *cache_type, @@ -112,7 +90,6 @@ static int check_results(struct resctrl_val_param *param, const char *cache_type ret = show_results_info(sum_llc_perf_miss, bits, alloc_size / 64, - MIN_DIFF_PERCENT_PER_BIT * (bits - 1), runs, get_vendor() == ARCH_INTEL, &prev_avg_llc_val); if (ret) @@ -158,7 +135,6 @@ static int cat_test(const struct resctrl_test *test, struct resctrl_val_param *param, size_t span, unsigned long current_mask) { - struct perf_event_read pe_read; struct perf_event_attr pea; cpu_set_t old_affinity; unsigned char *buf; @@ -181,8 +157,11 @@ static int cat_test(const struct resctrl_test *test, if (ret) goto reset_affinity; + ret = minimize_l2_occupancy(test, uparams, param); + if (ret) + goto reset_affinity; + perf_event_attr_initialize(&pea, PERF_COUNT_HW_CACHE_MISSES); - perf_event_initialize_read_format(&pe_read); pe_fd = perf_open(&pea, bm_pid, uparams->cpu); if (pe_fd < 0) { ret = -1; @@ -215,7 +194,7 @@ static int cat_test(const struct resctrl_test *test, fill_cache_read(buf, span, true); - ret = perf_event_measure(pe_fd, &pe_read, param->filename, bm_pid); + ret = perf_event_measure(pe_fd, param->filename, bm_pid); if (ret) goto free_buf; } diff --git a/tools/testing/selftests/resctrl/cmt_test.c b/tools/testing/selftests/resctrl/cmt_test.c index d09e693dc739c..ccb6fe881a948 100644 --- a/tools/testing/selftests/resctrl/cmt_test.c +++ b/tools/testing/selftests/resctrl/cmt_test.c @@ -19,12 +19,40 @@ #define CON_MON_LCC_OCCUP_PATH \ "%s/%s/mon_data/mon_L3_%02d/llc_occupancy" -static int cmt_init(const struct resctrl_val_param *param, int domain_id) +/* + * Initialize capacity bitmasks (CBMs) of: + * - control group being tested per test parameters, + * - default resource group as inverse of control group being tested to prevent + * other tasks from interfering with test, + * - L2 resource of control group being tested to minimize allocations into + * L2 if possible to better predict L3 occupancy. + */ +static int cmt_init(const struct resctrl_test *test, + const struct user_params *uparams, + const struct resctrl_val_param *param, int domain_id) { + unsigned long full_mask; + char schemata[64]; + int ret; + sprintf(llc_occup_path, CON_MON_LCC_OCCUP_PATH, RESCTRL_PATH, param->ctrlgrp, domain_id); - return 0; + ret = get_full_cbm(test->resource, &full_mask); + if (ret) + return ret; + + snprintf(schemata, sizeof(schemata), "%lx", ~param->mask & full_mask); + ret = write_schemata("", schemata, uparams->cpu, test->resource); + if (ret) + return ret; + + snprintf(schemata, sizeof(schemata), "%lx", param->mask); + ret = write_schemata(param->ctrlgrp, schemata, uparams->cpu, test->resource); + if (ret) + return ret; + + return minimize_l2_occupancy(test, uparams, param); } static int cmt_setup(const struct resctrl_test *test, @@ -153,11 +181,11 @@ static int cmt_run_test(const struct resctrl_test *test, const struct user_param span = cache_portion_size(cache_total_size, param.mask, long_mask); if (uparams->fill_buf) { - fill_buf.buf_size = span; + fill_buf.buf_size = span * 2; fill_buf.memflush = uparams->fill_buf->memflush; param.fill_buf = &fill_buf; } else if (!uparams->benchmark_cmd[0]) { - fill_buf.buf_size = span; + fill_buf.buf_size = span * 2; fill_buf.memflush = true; param.fill_buf = &fill_buf; } diff --git a/tools/testing/selftests/resctrl/fill_buf.c b/tools/testing/selftests/resctrl/fill_buf.c index 19a01a52dc1a3..b9fa7968cd6e1 100644 --- a/tools/testing/selftests/resctrl/fill_buf.c +++ b/tools/testing/selftests/resctrl/fill_buf.c @@ -139,6 +139,6 @@ ssize_t get_fill_buf_size(int cpu_no, const char *cache_type) if (ret) return ret; - return cache_total_size * 2 > MINIMUM_SPAN ? - cache_total_size * 2 : MINIMUM_SPAN; + return cache_total_size * 4 > MINIMUM_SPAN ? + cache_total_size * 4 : MINIMUM_SPAN; } diff --git a/tools/testing/selftests/resctrl/mba_test.c b/tools/testing/selftests/resctrl/mba_test.c index c7e9adc0368f3..39cee98983592 100644 --- a/tools/testing/selftests/resctrl/mba_test.c +++ b/tools/testing/selftests/resctrl/mba_test.c @@ -12,12 +12,14 @@ #define RESULT_FILE_NAME "result_mba" #define NUM_OF_RUNS 5 -#define MAX_DIFF_PERCENT 8 +#define MAX_DIFF_PERCENT 15 #define ALLOCATION_MAX 100 #define ALLOCATION_MIN 10 #define ALLOCATION_STEP 10 -static int mba_init(const struct resctrl_val_param *param, int domain_id) +static int mba_init(const struct resctrl_test *test, + const struct user_params *uparams, + const struct resctrl_val_param *param, int domain_id) { int ret; diff --git a/tools/testing/selftests/resctrl/mbm_test.c b/tools/testing/selftests/resctrl/mbm_test.c index 84d8bc2505392..6dbbc3b760033 100644 --- a/tools/testing/selftests/resctrl/mbm_test.c +++ b/tools/testing/selftests/resctrl/mbm_test.c @@ -11,7 +11,7 @@ #include "resctrl.h" #define RESULT_FILE_NAME "result_mbm" -#define MAX_DIFF_PERCENT 8 +#define MAX_DIFF_PERCENT 15 #define NUM_OF_RUNS 5 static int @@ -83,7 +83,9 @@ static int check_results(size_t span) return ret; } -static int mbm_init(const struct resctrl_val_param *param, int domain_id) +static int mbm_init(const struct resctrl_test *test, + const struct user_params *uparams, + const struct resctrl_val_param *param, int domain_id) { int ret; diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h index afe635b6e48d6..175101022bf3c 100644 --- a/tools/testing/selftests/resctrl/resctrl.h +++ b/tools/testing/selftests/resctrl/resctrl.h @@ -55,7 +55,7 @@ * and MBM respectively, for instance generating "overhead" traffic which * is not counted against any specific RMID. */ -#define THROTTLE_THRESHOLD 750 +#define THROTTLE_THRESHOLD 2500 /* * fill_buf_param: "fill_buf" benchmark parameters @@ -135,7 +135,9 @@ struct resctrl_val_param { char filename[64]; unsigned long mask; int num_of_runs; - int (*init)(const struct resctrl_val_param *param, + int (*init)(const struct resctrl_test *test, + const struct user_params *uparams, + const struct resctrl_val_param *param, int domain_id); int (*setup)(const struct resctrl_test *test, const struct user_params *uparams, @@ -146,13 +148,6 @@ struct resctrl_val_param { struct fill_buf_param *fill_buf; }; -struct perf_event_read { - __u64 nr; /* The number of events */ - struct { - __u64 value; /* The value of the event */ - } values[2]; -}; - /* * Memory location that consumes values compiler must not optimize away. * Volatile ensures writes to this location cannot be optimized away by @@ -208,12 +203,13 @@ unsigned int count_bits(unsigned long n); int snc_kernel_support(void); void perf_event_attr_initialize(struct perf_event_attr *pea, __u64 config); -void perf_event_initialize_read_format(struct perf_event_read *pe_read); int perf_open(struct perf_event_attr *pea, pid_t pid, int cpu_no); int perf_event_reset_enable(int pe_fd); -int perf_event_measure(int pe_fd, struct perf_event_read *pe_read, - const char *filename, pid_t bm_pid); +int perf_event_measure(int pe_fd, const char *filename, pid_t bm_pid); int measure_llc_resctrl(const char *filename, pid_t bm_pid); +int minimize_l2_occupancy(const struct resctrl_test *test, + const struct user_params *uparams, + const struct resctrl_val_param *param); void show_cache_info(int no_of_bits, __u64 avg_llc_val, size_t cache_span, bool lines); /* diff --git a/tools/testing/selftests/resctrl/resctrl_val.c b/tools/testing/selftests/resctrl/resctrl_val.c index 7c08e936572d2..f20d2194c35fb 100644 --- a/tools/testing/selftests/resctrl/resctrl_val.c +++ b/tools/testing/selftests/resctrl/resctrl_val.c @@ -11,10 +11,10 @@ #include "resctrl.h" #define UNCORE_IMC "uncore_imc" -#define READ_FILE_NAME "events/cas_count_read" +#define READ_FILE_NAME "cas_count_read" #define DYN_PMU_PATH "/sys/bus/event_source/devices" #define SCALE 0.00006103515625 -#define MAX_IMCS 20 +#define MAX_IMCS 40 #define MAX_TOKENS 5 #define CON_MBM_LOCAL_BYTES_PATH \ @@ -32,7 +32,6 @@ struct imc_counter_config { __u64 event; __u64 umask; struct perf_event_attr pe; - struct membw_read_format return_value; int fd; }; @@ -74,7 +73,7 @@ static void read_mem_bw_ioctl_perf_event_ioc_disable(int i) * @cas_count_cfg: Config * @count: iMC number */ -static void get_read_event_and_umask(char *cas_count_cfg, int count) +static void get_read_event_and_umask(char *cas_count_cfg, unsigned int count) { char *token[MAX_TOKENS]; int i = 0; @@ -110,45 +109,114 @@ static int open_perf_read_event(int i, int cpu_no) return 0; } -/* Get type and config of an iMC counter's read event. */ -static int read_from_imc_dir(char *imc_dir, int count) +static int parse_imc_read_bw_events(char *imc_dir, unsigned int type, + unsigned int *count) { - char cas_count_cfg[1024], imc_counter_cfg[1024], imc_counter_type[1024]; + char imc_events_dir[PATH_MAX], imc_counter_cfg[PATH_MAX]; + unsigned int orig_count = *count; + char cas_count_cfg[1024]; + struct dirent *ep; + int path_len; + int ret = -1; + int num_cfg; FILE *fp; + DIR *dp; - /* Get type of iMC counter */ - sprintf(imc_counter_type, "%s%s", imc_dir, "type"); - fp = fopen(imc_counter_type, "r"); - if (!fp) { - ksft_perror("Failed to open iMC counter type file"); + path_len = snprintf(imc_events_dir, sizeof(imc_events_dir), "%sevents", + imc_dir); + if (path_len >= sizeof(imc_events_dir)) { + ksft_print_msg("Unable to create path to %sevents\n", imc_dir); + return -1; + } + dp = opendir(imc_events_dir); + if (!dp) { + ksft_perror("Unable to open PMU events directory"); return -1; } - if (fscanf(fp, "%u", &imc_counters_config[count].type) <= 0) { - ksft_perror("Could not get iMC type"); + + while ((ep = readdir(dp))) { + /* + * Parse all event files with READ_FILE_NAME prefix that + * contain the event number and umask. Skip files containing + * "." that contain unused properties of event. + */ + if (!strstr(ep->d_name, READ_FILE_NAME) || + strchr(ep->d_name, '.')) + continue; + + path_len = snprintf(imc_counter_cfg, sizeof(imc_counter_cfg), + "%s/%s", imc_events_dir, ep->d_name); + if (path_len >= sizeof(imc_counter_cfg)) { + ksft_print_msg("Unable to create path to %s/%s\n", + imc_events_dir, ep->d_name); + goto out_close; + } + fp = fopen(imc_counter_cfg, "r"); + if (!fp) { + ksft_perror("Failed to open iMC config file"); + goto out_close; + } + num_cfg = fscanf(fp, "%1023s", cas_count_cfg); fclose(fp); + if (num_cfg <= 0) { + ksft_perror("Could not get iMC cas count read"); + goto out_close; + } + if (*count >= MAX_IMCS) { + ksft_print_msg("Maximum iMC count exceeded\n"); + goto out_close; + } - return -1; + imc_counters_config[*count].type = type; + get_read_event_and_umask(cas_count_cfg, *count); + /* Do not fail after incrementing *count. */ + *count += 1; } - fclose(fp); + if (*count == orig_count) { + ksft_print_msg("Unable to find events in %s\n", imc_events_dir); + goto out_close; + } + ret = 0; +out_close: + closedir(dp); + return ret; +} - /* Get read config */ - sprintf(imc_counter_cfg, "%s%s", imc_dir, READ_FILE_NAME); - fp = fopen(imc_counter_cfg, "r"); - if (!fp) { - ksft_perror("Failed to open iMC config file"); +/* Get type and config of an iMC counter's read event. */ +static int read_from_imc_dir(char *imc_dir, unsigned int *count) +{ + char imc_counter_type[PATH_MAX]; + unsigned int type; + int path_len; + FILE *fp; + int ret; + /* Get type of iMC counter */ + path_len = snprintf(imc_counter_type, sizeof(imc_counter_type), + "%s%s", imc_dir, "type"); + if (path_len >= sizeof(imc_counter_type)) { + ksft_print_msg("Unable to create path to %s%s\n", + imc_dir, "type"); return -1; } - if (fscanf(fp, "%1023s", cas_count_cfg) <= 0) { - ksft_perror("Could not get iMC cas count read"); - fclose(fp); + fp = fopen(imc_counter_type, "r"); + if (!fp) { + ksft_perror("Failed to open iMC counter type file"); return -1; } + ret = fscanf(fp, "%u", &type); fclose(fp); - - get_read_event_and_umask(cas_count_cfg, count); + if (ret <= 0) { + ksft_perror("Could not get iMC type"); + return -1; + } + ret = parse_imc_read_bw_events(imc_dir, type, count); + if (ret) { + ksft_print_msg("Unable to parse bandwidth event and umask\n"); + return ret; + } return 0; } @@ -197,13 +265,12 @@ static int num_of_imcs(void) if (temp[0] >= '0' && temp[0] <= '9') { sprintf(imc_dir, "%s/%s/", DYN_PMU_PATH, ep->d_name); - ret = read_from_imc_dir(imc_dir, count); + ret = read_from_imc_dir(imc_dir, &count); if (ret) { closedir(dp); return ret; } - count++; } } closedir(dp); @@ -312,23 +379,23 @@ static int get_read_mem_bw_imc(float *bw_imc) * Take overflow into consideration before calculating total bandwidth. */ for (imc = 0; imc < imcs; imc++) { + struct membw_read_format measurement; struct imc_counter_config *r = &imc_counters_config[imc]; - if (read(r->fd, &r->return_value, - sizeof(struct membw_read_format)) == -1) { + if (read(r->fd, &measurement, sizeof(measurement)) == -1) { ksft_perror("Couldn't get read bandwidth through iMC"); return -1; } - __u64 r_time_enabled = r->return_value.time_enabled; - __u64 r_time_running = r->return_value.time_running; + __u64 r_time_enabled = measurement.time_enabled; + __u64 r_time_running = measurement.time_running; if (r_time_enabled != r_time_running) of_mul_read = (float)r_time_enabled / (float)r_time_running; - reads += r->return_value.value * of_mul_read * SCALE; + reads += measurement.value * of_mul_read * SCALE; } *bw_imc = reads; @@ -569,7 +636,7 @@ int resctrl_val(const struct resctrl_test *test, goto reset_affinity; if (param->init) { - ret = param->init(param, domain_id); + ret = param->init(test, uparams, param, domain_id); if (ret) goto reset_affinity; } |
