47b59f3603
After commit f7d5bcd35d42 ("selftests: kselftest: Mark functions that unconditionally call exit() as __noreturn"), ksft_exit_...() functions are marked as __noreturn, which means the return type should not be 'int' but 'void' because they are not returning anything (and never were since exit() has always been called). To facilitate updating the return type of these functions, remove 'return' before the calls to ksft_exit_skip(), as __noreturn prevents the compiler from warning that a caller of ksft_exit_skip() does not return a value because the program will terminate upon calling these functions. Reviewed-by: Muhammad Usama Anjum <usama.anjum@collabora.com> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Nathan Chancellor <nathan@kernel.org> Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
281 lines
6.2 KiB
C
281 lines
6.2 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Resctrl tests
|
|
*
|
|
* Copyright (C) 2018 Intel Corporation
|
|
*
|
|
* Authors:
|
|
* Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
|
|
* Fenghua Yu <fenghua.yu@intel.com>
|
|
*/
|
|
#include "resctrl.h"
|
|
|
|
/* Volatile memory sink to prevent compiler optimizations */
|
|
static volatile int sink_target;
|
|
volatile int *value_sink = &sink_target;
|
|
|
|
static struct resctrl_test *resctrl_tests[] = {
|
|
&mbm_test,
|
|
&mba_test,
|
|
&cmt_test,
|
|
&l3_cat_test,
|
|
&l3_noncont_cat_test,
|
|
&l2_noncont_cat_test,
|
|
};
|
|
|
|
static int detect_vendor(void)
|
|
{
|
|
FILE *inf = fopen("/proc/cpuinfo", "r");
|
|
int vendor_id = 0;
|
|
char *s = NULL;
|
|
char *res;
|
|
|
|
if (!inf)
|
|
return vendor_id;
|
|
|
|
res = fgrep(inf, "vendor_id");
|
|
|
|
if (res)
|
|
s = strchr(res, ':');
|
|
|
|
if (s && !strcmp(s, ": GenuineIntel\n"))
|
|
vendor_id = ARCH_INTEL;
|
|
else if (s && !strcmp(s, ": AuthenticAMD\n"))
|
|
vendor_id = ARCH_AMD;
|
|
|
|
fclose(inf);
|
|
free(res);
|
|
return vendor_id;
|
|
}
|
|
|
|
int get_vendor(void)
|
|
{
|
|
static int vendor = -1;
|
|
|
|
if (vendor == -1)
|
|
vendor = detect_vendor();
|
|
if (vendor == 0)
|
|
ksft_print_msg("Can not get vendor info...\n");
|
|
|
|
return vendor;
|
|
}
|
|
|
|
static void cmd_help(void)
|
|
{
|
|
int i;
|
|
|
|
printf("usage: resctrl_tests [-h] [-t test list] [-n no_of_bits] [-b benchmark_cmd [option]...]\n");
|
|
printf("\t-b benchmark_cmd [option]...: run specified benchmark for MBM, MBA and CMT\n");
|
|
printf("\t default benchmark is builtin fill_buf\n");
|
|
printf("\t-t test list: run tests/groups specified by the list, ");
|
|
printf("e.g. -t mbm,mba,cmt,cat\n");
|
|
printf("\t\tSupported tests (group):\n");
|
|
for (i = 0; i < ARRAY_SIZE(resctrl_tests); i++) {
|
|
if (resctrl_tests[i]->group)
|
|
printf("\t\t\t%s (%s)\n", resctrl_tests[i]->name, resctrl_tests[i]->group);
|
|
else
|
|
printf("\t\t\t%s\n", resctrl_tests[i]->name);
|
|
}
|
|
printf("\t-n no_of_bits: run cache tests using specified no of bits in cache bit mask\n");
|
|
printf("\t-p cpu_no: specify CPU number to run the test. 1 is default\n");
|
|
printf("\t-h: help\n");
|
|
}
|
|
|
|
static int test_prepare(const struct resctrl_test *test)
|
|
{
|
|
int res;
|
|
|
|
res = signal_handler_register(test);
|
|
if (res) {
|
|
ksft_print_msg("Failed to register signal handler\n");
|
|
return res;
|
|
}
|
|
|
|
res = mount_resctrlfs();
|
|
if (res) {
|
|
signal_handler_unregister();
|
|
ksft_print_msg("Failed to mount resctrl FS\n");
|
|
return res;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void test_cleanup(const struct resctrl_test *test)
|
|
{
|
|
if (test->cleanup)
|
|
test->cleanup();
|
|
umount_resctrlfs();
|
|
signal_handler_unregister();
|
|
}
|
|
|
|
static bool test_vendor_specific_check(const struct resctrl_test *test)
|
|
{
|
|
if (!test->vendor_specific)
|
|
return true;
|
|
|
|
return get_vendor() & test->vendor_specific;
|
|
}
|
|
|
|
static void run_single_test(const struct resctrl_test *test, const struct user_params *uparams)
|
|
{
|
|
int ret;
|
|
|
|
if (test->disabled)
|
|
return;
|
|
|
|
if (!test_vendor_specific_check(test)) {
|
|
ksft_test_result_skip("Hardware does not support %s\n", test->name);
|
|
return;
|
|
}
|
|
|
|
ksft_print_msg("Starting %s test ...\n", test->name);
|
|
|
|
if (test_prepare(test)) {
|
|
ksft_exit_fail_msg("Abnormal failure when preparing for the test\n");
|
|
return;
|
|
}
|
|
|
|
if (!test->feature_check(test)) {
|
|
ksft_test_result_skip("Hardware does not support %s or %s is disabled\n",
|
|
test->name, test->name);
|
|
goto cleanup;
|
|
}
|
|
|
|
ret = test->run_test(test, uparams);
|
|
ksft_test_result(!ret, "%s: test\n", test->name);
|
|
|
|
cleanup:
|
|
test_cleanup(test);
|
|
}
|
|
|
|
static void init_user_params(struct user_params *uparams)
|
|
{
|
|
memset(uparams, 0, sizeof(*uparams));
|
|
|
|
uparams->cpu = 1;
|
|
uparams->bits = 0;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int tests = ARRAY_SIZE(resctrl_tests);
|
|
bool test_param_seen = false;
|
|
struct user_params uparams;
|
|
char *span_str = NULL;
|
|
int ret, c, i;
|
|
|
|
init_user_params(&uparams);
|
|
|
|
while ((c = getopt(argc, argv, "ht:b:n:p:")) != -1) {
|
|
char *token;
|
|
|
|
switch (c) {
|
|
case 'b':
|
|
/*
|
|
* First move optind back to the (first) optarg and
|
|
* then build the benchmark command using the
|
|
* remaining arguments.
|
|
*/
|
|
optind--;
|
|
if (argc - optind >= BENCHMARK_ARGS)
|
|
ksft_exit_fail_msg("Too long benchmark command");
|
|
|
|
/* Extract benchmark command from command line. */
|
|
for (i = 0; i < argc - optind; i++)
|
|
uparams.benchmark_cmd[i] = argv[i + optind];
|
|
uparams.benchmark_cmd[i] = NULL;
|
|
|
|
goto last_arg;
|
|
case 't':
|
|
token = strtok(optarg, ",");
|
|
|
|
if (!test_param_seen) {
|
|
for (i = 0; i < ARRAY_SIZE(resctrl_tests); i++)
|
|
resctrl_tests[i]->disabled = true;
|
|
tests = 0;
|
|
test_param_seen = true;
|
|
}
|
|
while (token) {
|
|
bool found = false;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(resctrl_tests); i++) {
|
|
if (!strcasecmp(token, resctrl_tests[i]->name) ||
|
|
(resctrl_tests[i]->group &&
|
|
!strcasecmp(token, resctrl_tests[i]->group))) {
|
|
if (resctrl_tests[i]->disabled)
|
|
tests++;
|
|
resctrl_tests[i]->disabled = false;
|
|
found = true;
|
|
}
|
|
}
|
|
|
|
if (!found) {
|
|
printf("invalid test: %s\n", token);
|
|
|
|
return -1;
|
|
}
|
|
token = strtok(NULL, ",");
|
|
}
|
|
break;
|
|
case 'p':
|
|
uparams.cpu = atoi(optarg);
|
|
break;
|
|
case 'n':
|
|
uparams.bits = atoi(optarg);
|
|
if (uparams.bits <= 0) {
|
|
printf("Bail out! invalid argument for no_of_bits\n");
|
|
return -1;
|
|
}
|
|
break;
|
|
case 'h':
|
|
cmd_help();
|
|
|
|
return 0;
|
|
default:
|
|
printf("invalid argument\n");
|
|
|
|
return -1;
|
|
}
|
|
}
|
|
last_arg:
|
|
|
|
ksft_print_header();
|
|
|
|
/*
|
|
* Typically we need root privileges, because:
|
|
* 1. We write to resctrl FS
|
|
* 2. We execute perf commands
|
|
*/
|
|
if (geteuid() != 0)
|
|
ksft_exit_skip("Not running as root. Skipping...\n");
|
|
|
|
if (!check_resctrlfs_support())
|
|
ksft_exit_skip("resctrl FS does not exist. Enable X86_CPU_RESCTRL config option.\n");
|
|
|
|
if (umount_resctrlfs())
|
|
ksft_exit_skip("resctrl FS unmount failed.\n");
|
|
|
|
filter_dmesg();
|
|
|
|
if (!uparams.benchmark_cmd[0]) {
|
|
/* If no benchmark is given by "-b" argument, use fill_buf. */
|
|
uparams.benchmark_cmd[0] = "fill_buf";
|
|
ret = asprintf(&span_str, "%u", DEFAULT_SPAN);
|
|
if (ret < 0)
|
|
ksft_exit_fail_msg("Out of memory!\n");
|
|
uparams.benchmark_cmd[1] = span_str;
|
|
uparams.benchmark_cmd[2] = "1";
|
|
uparams.benchmark_cmd[3] = "0";
|
|
uparams.benchmark_cmd[4] = "false";
|
|
uparams.benchmark_cmd[5] = NULL;
|
|
}
|
|
|
|
ksft_set_plan(tests);
|
|
|
|
for (i = 0; i < ARRAY_SIZE(resctrl_tests); i++)
|
|
run_single_test(resctrl_tests[i], &uparams);
|
|
|
|
free(span_str);
|
|
ksft_finished();
|
|
}
|