2020-01-16 13:32:40 -08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/*
|
|
|
|
* Memory Bandwidth Allocation (MBA) test
|
|
|
|
*
|
|
|
|
* Copyright (C) 2018 Intel Corporation
|
|
|
|
*
|
|
|
|
* Authors:
|
|
|
|
* Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
|
|
|
|
* Fenghua Yu <fenghua.yu@intel.com>
|
|
|
|
*/
|
|
|
|
#include "resctrl.h"
|
|
|
|
|
|
|
|
#define RESULT_FILE_NAME "result_mba"
|
|
|
|
#define NUM_OF_RUNS 5
|
2023-10-02 12:48:13 +03:00
|
|
|
#define MAX_DIFF_PERCENT 8
|
2020-01-16 13:32:40 -08:00
|
|
|
#define ALLOCATION_MAX 100
|
|
|
|
#define ALLOCATION_MIN 10
|
|
|
|
#define ALLOCATION_STEP 10
|
|
|
|
|
2024-06-10 18:14:51 +03:00
|
|
|
static int mba_init(const struct resctrl_val_param *param, int domain_id)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2024-10-24 14:18:46 -07:00
|
|
|
ret = initialize_read_mem_bw_imc();
|
2024-06-10 18:14:51 +03:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
initialize_mem_bw_resctrl(param, domain_id);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-01-16 13:32:40 -08:00
|
|
|
/*
|
|
|
|
* Change schemata percentage from 100 to 10%. Write schemata to specified
|
|
|
|
* con_mon grp, mon_grp in resctrl FS.
|
|
|
|
* For each allocation, run 5 times in order to get average values.
|
|
|
|
*/
|
2023-12-15 17:05:12 +02:00
|
|
|
static int mba_setup(const struct resctrl_test *test,
|
|
|
|
const struct user_params *uparams,
|
|
|
|
struct resctrl_val_param *p)
|
2020-01-16 13:32:40 -08:00
|
|
|
{
|
2024-10-24 14:18:43 -07:00
|
|
|
static unsigned int allocation = ALLOCATION_MIN;
|
|
|
|
static int runs_per_allocation;
|
2020-01-16 13:32:40 -08:00
|
|
|
char allocation_str[64];
|
2023-02-15 15:06:00 +02:00
|
|
|
int ret;
|
2020-01-16 13:32:40 -08:00
|
|
|
|
|
|
|
if (runs_per_allocation >= NUM_OF_RUNS)
|
|
|
|
runs_per_allocation = 0;
|
|
|
|
|
|
|
|
/* Only set up schemata once every NUM_OF_RUNS of allocations */
|
|
|
|
if (runs_per_allocation++ != 0)
|
|
|
|
return 0;
|
|
|
|
|
2024-10-24 14:18:43 -07:00
|
|
|
if (allocation > ALLOCATION_MAX)
|
2023-02-15 15:05:59 +02:00
|
|
|
return END_OF_TESTS;
|
2020-01-16 13:32:40 -08:00
|
|
|
|
|
|
|
sprintf(allocation_str, "%d", allocation);
|
|
|
|
|
2023-12-15 17:05:12 +02:00
|
|
|
ret = write_schemata(p->ctrlgrp, allocation_str, uparams->cpu, test->resource);
|
2023-02-15 15:06:00 +02:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2024-10-24 14:18:43 -07:00
|
|
|
allocation += ALLOCATION_STEP;
|
2020-01-16 13:32:40 -08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2024-06-10 18:14:50 +03:00
|
|
|
static int mba_measure(const struct user_params *uparams,
|
|
|
|
struct resctrl_val_param *param, pid_t bm_pid)
|
|
|
|
{
|
2024-10-24 14:18:46 -07:00
|
|
|
return measure_read_mem_bw(uparams, param, bm_pid);
|
2024-06-10 18:14:50 +03:00
|
|
|
}
|
|
|
|
|
2023-04-13 16:22:55 +09:00
|
|
|
static bool show_mba_info(unsigned long *bw_imc, unsigned long *bw_resc)
|
2020-01-16 13:32:40 -08:00
|
|
|
{
|
2024-10-24 14:18:43 -07:00
|
|
|
unsigned int allocation;
|
2023-04-13 16:22:55 +09:00
|
|
|
bool ret = false;
|
2024-10-24 14:18:43 -07:00
|
|
|
int runs;
|
2020-01-16 13:32:40 -08:00
|
|
|
|
2021-03-17 02:22:42 +00:00
|
|
|
ksft_print_msg("Results are displayed in (MB)\n");
|
2020-01-16 13:32:40 -08:00
|
|
|
/* 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;
|
2024-05-08 13:41:01 -07:00
|
|
|
long avg_bw_imc, avg_bw_resc;
|
2021-03-17 02:22:48 +00:00
|
|
|
int avg_diff_per;
|
|
|
|
float avg_diff;
|
2020-01-16 13:32:40 -08:00
|
|
|
|
2024-10-24 14:18:51 -07:00
|
|
|
for (runs = NUM_OF_RUNS * allocation;
|
2020-01-16 13:32:40 -08:00
|
|
|
runs < NUM_OF_RUNS * allocation + NUM_OF_RUNS ; runs++) {
|
|
|
|
sum_bw_imc += bw_imc[runs];
|
|
|
|
sum_bw_resc += bw_resc[runs];
|
|
|
|
}
|
|
|
|
|
2024-10-24 14:18:51 -07:00
|
|
|
avg_bw_imc = sum_bw_imc / NUM_OF_RUNS;
|
|
|
|
avg_bw_resc = sum_bw_resc / NUM_OF_RUNS;
|
2024-10-24 14:18:50 -07:00
|
|
|
if (avg_bw_imc < THROTTLE_THRESHOLD || avg_bw_resc < THROTTLE_THRESHOLD) {
|
|
|
|
ksft_print_msg("Bandwidth below threshold (%d MiB). Dropping results from MBA schemata %u.\n",
|
|
|
|
THROTTLE_THRESHOLD,
|
|
|
|
ALLOCATION_MIN + ALLOCATION_STEP * allocation);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-03-17 02:22:48 +00:00
|
|
|
avg_diff = (float)labs(avg_bw_resc - avg_bw_imc) / avg_bw_imc;
|
|
|
|
avg_diff_per = (int)(avg_diff * 100);
|
2020-01-16 13:32:40 -08:00
|
|
|
|
2021-04-07 19:57:28 +00:00
|
|
|
ksft_print_msg("%s Check MBA diff within %d%% for schemata %u\n",
|
2021-03-17 02:22:48 +00:00
|
|
|
avg_diff_per > MAX_DIFF_PERCENT ?
|
|
|
|
"Fail:" : "Pass:",
|
|
|
|
MAX_DIFF_PERCENT,
|
2024-10-24 14:18:43 -07:00
|
|
|
ALLOCATION_MIN + ALLOCATION_STEP * allocation);
|
2021-03-17 02:22:48 +00:00
|
|
|
|
|
|
|
ksft_print_msg("avg_diff_per: %d%%\n", avg_diff_per);
|
2021-03-17 02:22:42 +00:00
|
|
|
ksft_print_msg("avg_bw_imc: %lu\n", avg_bw_imc);
|
|
|
|
ksft_print_msg("avg_bw_resc: %lu\n", avg_bw_resc);
|
2021-03-17 02:22:48 +00:00
|
|
|
if (avg_diff_per > MAX_DIFF_PERCENT)
|
2023-04-13 16:22:55 +09:00
|
|
|
ret = true;
|
2020-01-16 13:32:40 -08:00
|
|
|
}
|
|
|
|
|
2021-04-07 19:57:28 +00:00
|
|
|
ksft_print_msg("%s Check schemata change using MBA\n",
|
2023-04-13 16:22:55 +09:00
|
|
|
ret ? "Fail:" : "Pass:");
|
|
|
|
if (ret)
|
2021-04-07 19:57:28 +00:00
|
|
|
ksft_print_msg("At least one test failed\n");
|
2023-04-13 16:22:55 +09:00
|
|
|
|
|
|
|
return ret;
|
2020-01-16 13:32:40 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int check_results(void)
|
|
|
|
{
|
2024-10-24 14:18:52 -07:00
|
|
|
unsigned long bw_resc[NUM_OF_RUNS * ALLOCATION_MAX / ALLOCATION_STEP];
|
|
|
|
unsigned long bw_imc[NUM_OF_RUNS * ALLOCATION_MAX / ALLOCATION_STEP];
|
2020-01-16 13:32:40 -08:00
|
|
|
char *token_array[8], output[] = RESULT_FILE_NAME, temp[512];
|
|
|
|
int runs;
|
|
|
|
FILE *fp;
|
|
|
|
|
|
|
|
fp = fopen(output, "r");
|
|
|
|
if (!fp) {
|
2023-12-15 17:04:47 +02:00
|
|
|
ksft_perror(output);
|
2020-01-16 13:32:40 -08:00
|
|
|
|
2023-12-15 17:04:48 +02:00
|
|
|
return -1;
|
2020-01-16 13:32:40 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
runs = 0;
|
|
|
|
while (fgets(temp, sizeof(temp), fp)) {
|
|
|
|
char *token = strtok(temp, ":\t");
|
|
|
|
int fields = 0;
|
|
|
|
|
|
|
|
while (token) {
|
|
|
|
token_array[fields++] = token;
|
|
|
|
token = strtok(NULL, ":\t");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Field 3 is perf imc value */
|
|
|
|
bw_imc[runs] = strtoul(token_array[3], NULL, 0);
|
|
|
|
/* Field 5 is resctrl value */
|
|
|
|
bw_resc[runs] = strtoul(token_array[5], NULL, 0);
|
|
|
|
runs++;
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
|
2023-04-13 16:22:55 +09:00
|
|
|
return show_mba_info(bw_imc, bw_resc);
|
2020-01-16 13:32:40 -08:00
|
|
|
}
|
|
|
|
|
2024-02-27 08:21:43 +01:00
|
|
|
static void mba_test_cleanup(void)
|
2020-01-16 13:32:40 -08:00
|
|
|
{
|
|
|
|
remove(RESULT_FILE_NAME);
|
|
|
|
}
|
|
|
|
|
2023-12-15 17:05:11 +02:00
|
|
|
static int mba_run_test(const struct resctrl_test *test, const struct user_params *uparams)
|
2020-01-16 13:32:40 -08:00
|
|
|
{
|
|
|
|
struct resctrl_val_param param = {
|
|
|
|
.ctrlgrp = "c1",
|
|
|
|
.filename = RESULT_FILE_NAME,
|
2024-06-10 18:14:51 +03:00
|
|
|
.init = mba_init,
|
2024-06-10 18:14:50 +03:00
|
|
|
.setup = mba_setup,
|
|
|
|
.measure = mba_measure,
|
2020-01-16 13:32:40 -08:00
|
|
|
};
|
selftests/resctrl: Make benchmark parameter passing robust
The benchmark used during the CMT, MBM, and MBA tests can be provided by
the user via (-b) parameter, if not provided the default "fill_buf"
benchmark is used. The user is additionally able to override
any of the "fill_buf" default parameters when running the tests with
"-b fill_buf <fill_buf parameters>".
The "fill_buf" parameters are managed as an array of strings. Using an
array of strings is complex because it requires transformations to/from
strings at every producer and consumer. This is made worse for the
individual tests where the default benchmark parameters values may not
be appropriate and additional data wrangling is required. For example,
the CMT test duplicates the entire array of strings in order to replace
one of the parameters.
More issues appear when combining the usage of an array of strings with
the use case of user overriding default parameters by specifying
"-b fill_buf <parameters>". This use case is fragile with opportunities
to trigger a SIGSEGV because of opportunities for NULL pointers to exist
in the array of strings. For example, by running below (thus by specifying
"fill_buf" should be used but all parameters are NULL):
$ sudo resctrl_tests -t mbm -b fill_buf
Replace the "array of strings" parameters used for "fill_buf" with
new struct fill_buf_param that contains the "fill_buf" parameters that
can be used directly without transformations to/from strings. Two
instances of struct fill_buf_param may exist at any point in time:
* If the user provides new parameters to "fill_buf", the
user parameter structure (struct user_params) will point to a
fully initialized and immutable struct fill_buf_param
containing the user provided parameters.
* If "fill_buf" is the benchmark that should be used by a test,
then the test parameter structure (struct resctrl_val_param)
will point to a fully initialized struct fill_buf_param. The
latter may contain (a) the user provided parameters verbatim,
(b) user provided parameters adjusted to be appropriate for
the test, or (c) the default parameters for "fill_buf" that
is appropriate for the test if the user did not provide
"fill_buf" parameters nor an alternate benchmark.
The existing behavior of CMT test is to use test defined value for the
buffer size even if the user provides another value via command line.
This behavior is maintained since the test requires that the buffer size
matches the size of the cache allocated, and the amount of cache
allocated can instead be changed by the user with the "-n" command line
parameter.
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
2024-10-24 14:18:47 -07:00
|
|
|
struct fill_buf_param fill_buf = {};
|
2020-01-16 13:32:40 -08:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
remove(RESULT_FILE_NAME);
|
|
|
|
|
selftests/resctrl: Make benchmark parameter passing robust
The benchmark used during the CMT, MBM, and MBA tests can be provided by
the user via (-b) parameter, if not provided the default "fill_buf"
benchmark is used. The user is additionally able to override
any of the "fill_buf" default parameters when running the tests with
"-b fill_buf <fill_buf parameters>".
The "fill_buf" parameters are managed as an array of strings. Using an
array of strings is complex because it requires transformations to/from
strings at every producer and consumer. This is made worse for the
individual tests where the default benchmark parameters values may not
be appropriate and additional data wrangling is required. For example,
the CMT test duplicates the entire array of strings in order to replace
one of the parameters.
More issues appear when combining the usage of an array of strings with
the use case of user overriding default parameters by specifying
"-b fill_buf <parameters>". This use case is fragile with opportunities
to trigger a SIGSEGV because of opportunities for NULL pointers to exist
in the array of strings. For example, by running below (thus by specifying
"fill_buf" should be used but all parameters are NULL):
$ sudo resctrl_tests -t mbm -b fill_buf
Replace the "array of strings" parameters used for "fill_buf" with
new struct fill_buf_param that contains the "fill_buf" parameters that
can be used directly without transformations to/from strings. Two
instances of struct fill_buf_param may exist at any point in time:
* If the user provides new parameters to "fill_buf", the
user parameter structure (struct user_params) will point to a
fully initialized and immutable struct fill_buf_param
containing the user provided parameters.
* If "fill_buf" is the benchmark that should be used by a test,
then the test parameter structure (struct resctrl_val_param)
will point to a fully initialized struct fill_buf_param. The
latter may contain (a) the user provided parameters verbatim,
(b) user provided parameters adjusted to be appropriate for
the test, or (c) the default parameters for "fill_buf" that
is appropriate for the test if the user did not provide
"fill_buf" parameters nor an alternate benchmark.
The existing behavior of CMT test is to use test defined value for the
buffer size even if the user provides another value via command line.
This behavior is maintained since the test requires that the buffer size
matches the size of the cache allocated, and the amount of cache
allocated can instead be changed by the user with the "-n" command line
parameter.
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
2024-10-24 14:18:47 -07:00
|
|
|
if (uparams->fill_buf) {
|
|
|
|
fill_buf.buf_size = uparams->fill_buf->buf_size;
|
|
|
|
fill_buf.memflush = uparams->fill_buf->memflush;
|
|
|
|
param.fill_buf = &fill_buf;
|
|
|
|
} else if (!uparams->benchmark_cmd[0]) {
|
2024-10-24 14:18:49 -07:00
|
|
|
ssize_t buf_size;
|
|
|
|
|
|
|
|
buf_size = get_fill_buf_size(uparams->cpu, "L3");
|
|
|
|
if (buf_size < 0)
|
|
|
|
return buf_size;
|
|
|
|
fill_buf.buf_size = buf_size;
|
selftests/resctrl: Make benchmark parameter passing robust
The benchmark used during the CMT, MBM, and MBA tests can be provided by
the user via (-b) parameter, if not provided the default "fill_buf"
benchmark is used. The user is additionally able to override
any of the "fill_buf" default parameters when running the tests with
"-b fill_buf <fill_buf parameters>".
The "fill_buf" parameters are managed as an array of strings. Using an
array of strings is complex because it requires transformations to/from
strings at every producer and consumer. This is made worse for the
individual tests where the default benchmark parameters values may not
be appropriate and additional data wrangling is required. For example,
the CMT test duplicates the entire array of strings in order to replace
one of the parameters.
More issues appear when combining the usage of an array of strings with
the use case of user overriding default parameters by specifying
"-b fill_buf <parameters>". This use case is fragile with opportunities
to trigger a SIGSEGV because of opportunities for NULL pointers to exist
in the array of strings. For example, by running below (thus by specifying
"fill_buf" should be used but all parameters are NULL):
$ sudo resctrl_tests -t mbm -b fill_buf
Replace the "array of strings" parameters used for "fill_buf" with
new struct fill_buf_param that contains the "fill_buf" parameters that
can be used directly without transformations to/from strings. Two
instances of struct fill_buf_param may exist at any point in time:
* If the user provides new parameters to "fill_buf", the
user parameter structure (struct user_params) will point to a
fully initialized and immutable struct fill_buf_param
containing the user provided parameters.
* If "fill_buf" is the benchmark that should be used by a test,
then the test parameter structure (struct resctrl_val_param)
will point to a fully initialized struct fill_buf_param. The
latter may contain (a) the user provided parameters verbatim,
(b) user provided parameters adjusted to be appropriate for
the test, or (c) the default parameters for "fill_buf" that
is appropriate for the test if the user did not provide
"fill_buf" parameters nor an alternate benchmark.
The existing behavior of CMT test is to use test defined value for the
buffer size even if the user provides another value via command line.
This behavior is maintained since the test requires that the buffer size
matches the size of the cache allocated, and the amount of cache
allocated can instead be changed by the user with the "-n" command line
parameter.
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
2024-10-24 14:18:47 -07:00
|
|
|
fill_buf.memflush = true;
|
|
|
|
param.fill_buf = &fill_buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = resctrl_val(test, uparams, ¶m);
|
2020-01-16 13:32:40 -08:00
|
|
|
if (ret)
|
2024-02-27 08:21:43 +01:00
|
|
|
return ret;
|
2020-01-16 13:32:40 -08:00
|
|
|
|
|
|
|
ret = check_results();
|
2024-12-16 16:18:54 +01:00
|
|
|
if (ret && (get_vendor() == ARCH_INTEL) && !snc_kernel_support())
|
|
|
|
ksft_print_msg("Kernel doesn't support Sub-NUMA Clustering but it is enabled on the system.\n");
|
2020-01-16 13:32:40 -08:00
|
|
|
|
2023-04-13 16:22:59 +09:00
|
|
|
return ret;
|
2020-01-16 13:32:40 -08:00
|
|
|
}
|
2023-12-15 17:05:11 +02:00
|
|
|
|
|
|
|
static bool mba_feature_check(const struct resctrl_test *test)
|
|
|
|
{
|
|
|
|
return test_resource_feature_check(test) &&
|
2024-02-16 09:35:28 +01:00
|
|
|
resctrl_mon_feature_exists("L3_MON", "mbm_local_bytes");
|
2023-12-15 17:05:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
struct resctrl_test mba_test = {
|
|
|
|
.name = "MBA",
|
|
|
|
.resource = "MB",
|
|
|
|
.vendor_specific = ARCH_INTEL,
|
|
|
|
.feature_check = mba_feature_check,
|
|
|
|
.run_test = mba_run_test,
|
2024-02-27 08:21:41 +01:00
|
|
|
.cleanup = mba_test_cleanup,
|
2023-12-15 17:05:11 +02:00
|
|
|
};
|