Hi Ilpo, On 11/20/2023 3:13 AM, Ilpo Järvinen wrote: > CAT test doesn't take shareable bits into account, i.e., the test might > be sharing cache with some devices (e.g., graphics). > > Introduce get_mask_no_shareable() and use it to provision an > environment for CAT test where the allocated LLC is isolated better. > Excluding shareable_bits may create hole(s) into the cbm_mask, thus add > a new helper count_contiguous_bits() to find the longest contiguous set > of CBM bits. > > create_bit_mask() is needed by an upcoming CAT test rewrite so make it > available in resctrl.h right away. > > Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@xxxxxxxxxxxxxxx> > --- > tools/testing/selftests/resctrl/cat_test.c | 12 ++- > tools/testing/selftests/resctrl/resctrl.h | 3 + > tools/testing/selftests/resctrl/resctrlfs.c | 89 +++++++++++++++++++++ > 3 files changed, 100 insertions(+), 4 deletions(-) > > diff --git a/tools/testing/selftests/resctrl/cat_test.c b/tools/testing/selftests/resctrl/cat_test.c > index cfcdb7bd600f..2c8b37c0a179 100644 > --- a/tools/testing/selftests/resctrl/cat_test.c > +++ b/tools/testing/selftests/resctrl/cat_test.c > @@ -89,15 +89,19 @@ void cat_test_cleanup(void) > > int cat_perf_miss_val(int cpu_no, int n, char *cache_type) > { > + unsigned long full_cache_mask, long_mask; > unsigned long l_mask, l_mask_1; > int ret, pipefd[2], sibling_cpu_no; > unsigned long cache_total_size = 0; > - unsigned long long_mask; > int count_of_bits; > char pipe_message; > size_t span; > > - ret = get_full_cbm(cache_type, &long_mask); > + ret = get_full_cbm(cache_type, &full_cache_mask); > + if (ret) > + return ret; > + /* Get the exclusive portion of the cache */ How about: "Get largest contiguous exclusive portion of the cache" ? > + ret = get_mask_no_shareable(cache_type, &long_mask); > if (ret) > return ret; > > @@ -136,7 +140,7 @@ int cat_perf_miss_val(int cpu_no, int n, char *cache_type) > /* Set param values for parent thread which will be allocated bitmask > * with (max_bits - n) bits > */ > - span = cache_portion_size(cache_total_size, l_mask, long_mask); > + span = cache_portion_size(cache_total_size, l_mask, full_cache_mask); > strcpy(param.ctrlgrp, "c2"); > strcpy(param.mongrp, "m2"); > strcpy(param.filename, RESULT_FILE_NAME2); > @@ -158,7 +162,7 @@ int cat_perf_miss_val(int cpu_no, int n, char *cache_type) > param.mask = l_mask_1; > strcpy(param.ctrlgrp, "c1"); > strcpy(param.mongrp, "m1"); > - span = cache_portion_size(cache_total_size, l_mask_1, long_mask); > + span = cache_portion_size(cache_total_size, l_mask_1, full_cache_mask); > strcpy(param.filename, RESULT_FILE_NAME1); > param.num_of_runs = 0; > param.cpu_no = sibling_cpu_no; > diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h > index 57fe42f4eda2..a911b08fa595 100644 > --- a/tools/testing/selftests/resctrl/resctrl.h > +++ b/tools/testing/selftests/resctrl/resctrl.h > @@ -99,7 +99,10 @@ void tests_cleanup(void); > void mbm_test_cleanup(void); > int mba_schemata_change(int cpu_no, const char * const *benchmark_cmd); > void mba_test_cleanup(void); > +unsigned long create_bit_mask(unsigned int start, unsigned int len); > int get_full_cbm(const char *cache_type, unsigned long *mask); > +int get_shareable_mask(const char *cache_type, unsigned long *shareable_mask); Does this need to be exported? > +int get_mask_no_shareable(const char *cache_type, unsigned long *mask); > int get_cache_size(int cpu_no, const char *cache_type, unsigned long *cache_size); > void ctrlc_handler(int signum, siginfo_t *info, void *ptr); > int signal_handler_register(void); > diff --git a/tools/testing/selftests/resctrl/resctrlfs.c b/tools/testing/selftests/resctrl/resctrlfs.c > index 1ea610fa65b1..3a9ed918d657 100644 > --- a/tools/testing/selftests/resctrl/resctrlfs.c > +++ b/tools/testing/selftests/resctrl/resctrlfs.c > @@ -228,6 +228,44 @@ static int get_bit_mask(const char *filename, unsigned long *mask) > return 0; > } > > +/* > + * create_bit_mask- Create bit mask from start,len pair Please add a space after the comma. > + * @start: LSB of the mask > + * @len Number of bits in the mask > + */ > +unsigned long create_bit_mask(unsigned int start, unsigned int len) > +{ > + return ((1UL << len) - 1UL) << start; > +} > + > +/* > + * count_contiguous_bits - Returns the longest train of bits in a bit mask > + * @val A bit mask > + * @start The location of the least-significant bit of the longest train > + * > + * Return: The length of the contiguous bits in the longest train of bits > + */ > +static unsigned int count_contiguous_bits(unsigned long val, unsigned int *start) > +{ > + unsigned long last_val; > + unsigned int count = 0; > + > + while (val) { > + last_val = val; > + val &= (val >> 1); > + count++; > + } > + > + if (start) { > + if (count) > + *start = ffsl(last_val) - 1; > + else > + *start = 0; > + } > + > + return count; > +} > + > /* > * get_full_cbm - Get full Cache Bit Mask (CBM) > * @cache_type: Cache type as "L2" or "L3" > @@ -254,6 +292,57 @@ int get_full_cbm(const char *cache_type, unsigned long *mask) > return 0; > } > > +/* > + * get_shareable_mask - Get shareable mask from shareable_bits > + * @cache_type: Cache type as "L2" or "L3" > + * @shareable_mask: Shareable mask returned as unsigned long > + * > + * Return: = 0 on success, < 0 on failure. > + */ > +int get_shareable_mask(const char *cache_type, unsigned long *shareable_mask) It looks like this can be static. > +{ > + char mask_path[PATH_MAX]; > + > + if (!cache_type) > + return -1; > + > + snprintf(mask_path, sizeof(mask_path), "%s/%s/shareable_bits", > + INFO_PATH, cache_type); > + > + return get_bit_mask(mask_path, shareable_mask); > +} > + > +/* > + * get_mask_no_shareable - Get Cache Bit Mask (CBM) without shareable bits > + * @cache_type: Cache type as "L2" or "L3" > + * @mask: The largest exclusive portion of the cache out of the > + * full CBM, returned as unsigned long > + * > + * Parts of a cache may be shared with other devices such as GPU. This function > + * calculates the largest exclusive portion of the cache where no other devices > + * besides CPU have access to the cache portion. > + * > + * Return: = 0 on success, < 0 on failure. > + */ > +int get_mask_no_shareable(const char *cache_type, unsigned long *mask) > +{ > + unsigned long full_mask, shareable_mask; > + unsigned int start, len; > + > + if (get_full_cbm(cache_type, &full_mask) < 0) > + return -1; > + if (get_shareable_mask(cache_type, &shareable_mask) < 0) > + return -1; > + > + len = count_contiguous_bits(full_mask & ~shareable_mask, &start); > + if (!len) > + return -1; > + > + *mask = create_bit_mask(start, len); > + > + return 0; > +} > + > /* > * get_core_sibling - Get sibling core id from the same socket for given CPU > * @cpu_no: CPU number Reinette