Resctrl CAT selftests have been limited to mainly testing performance. In order to validate the kernel side behavior better, add a functional test that checks the MSR contents (if MSRs are accessible). As the low-level mapping is architecture specific, this test is currently limited to testing resctrl only on Intel CPUs.
Signed-off-by: Ilpo Järvinen ilpo.jarvinen@linux.intel.com --- tools/testing/selftests/resctrl/cat_test.c | 126 ++++++++++++++++++ tools/testing/selftests/resctrl/msr.c | 55 ++++++++ tools/testing/selftests/resctrl/resctrl.h | 4 + .../testing/selftests/resctrl/resctrl_tests.c | 1 + 4 files changed, 186 insertions(+) create mode 100644 tools/testing/selftests/resctrl/msr.c
diff --git a/tools/testing/selftests/resctrl/cat_test.c b/tools/testing/selftests/resctrl/cat_test.c index 78cb9ac90bb1..fbe1d2f7657f 100644 --- a/tools/testing/selftests/resctrl/cat_test.c +++ b/tools/testing/selftests/resctrl/cat_test.c @@ -9,8 +9,15 @@ * Fenghua Yu fenghua.yu@intel.com */ #include "resctrl.h" + +#include <string.h> #include <unistd.h>
+#define MSR_IA32_PQR_ASSOC 0xc8f +#define MSR_IA32_PQR_ASSOC_COS 0xffffffff00000000ULL + +#define MSR_IA32_L3_CBM_BASE 0xc90 + #define RESULT_FILE_NAME "result_cat" #define NUM_OF_RUNS 5
@@ -452,6 +459,116 @@ static int cat_ctrlgrp_tasks_test(const struct resctrl_test *test, return ret; }
+static int cat_ctrlgrp_check_msr(const struct user_params *uparams, + unsigned long mask) +{ + __u64 msr_val; + __u32 clos; + int ret; + + ret = read_msr(uparams->cpu, MSR_IA32_PQR_ASSOC, &msr_val); + if (ret) + return -1; + + clos = (msr_val & MSR_IA32_PQR_ASSOC_COS) >> (ffsl(MSR_IA32_PQR_ASSOC_COS) - 1); + + ret = read_msr(uparams->cpu, MSR_IA32_L3_CBM_BASE + clos, &msr_val); + if (ret) + return -1; + + if (msr_val != mask) { + ksft_print_msg("Incorrect CBM mask %llx, should be %lx\n", + msr_val, mask); + return -1; + } + + return 0; +} + +static int cat_ctrlgrp_msr_test(const struct resctrl_test *test, + const struct user_params *uparams) +{ + unsigned long mask1 = 0x3, mask2 = 0x6, mask3 = 0x0c; + cpu_set_t old_affinity; + char schemata[64]; + pid_t bm_pid; + int ret; + + bm_pid = getpid(); + + if (!msr_access_supported(uparams->cpu)) { + ksft_test_result_skip("Cannot access MSRs\n"); + return 0; + } + + ret = resctrl_grp_has_task(NULL, bm_pid); + if (ret < 0) + return ret; + if (!ret) { + ksft_print_msg("PID not found in the root group\n"); + return 1; + } + + /* Taskset benchmark to specified CPU */ + ksft_print_msg("Placing task to ctrlgrp 'c1'\n"); + ret = taskset_benchmark(bm_pid, uparams->cpu, &old_affinity); + if (ret) + return ret; + ret = write_bm_pid_to_resctrl(bm_pid, "c1", NULL); + if (ret) + goto reset_affinity; + snprintf(schemata, sizeof(schemata), "%lx", mask1); + ret = write_schemata("c1", schemata, uparams->cpu, test->resource); + if (ret) + goto reset_affinity; + ret = cat_ctrlgrp_check_msr(uparams, mask1); + if (ret) + goto reset_affinity; + + ksft_print_msg("Placing task to ctrlgrp 'c2'\n"); + ret = write_bm_pid_to_resctrl(bm_pid, "c2", NULL); + if (ret) + goto reset_affinity; + snprintf(schemata, sizeof(schemata), "%lx", mask2); + ret = write_schemata("c2", schemata, uparams->cpu, test->resource); + if (ret) + goto reset_affinity; + ret = cat_ctrlgrp_check_msr(uparams, mask2); + if (ret) + goto reset_affinity; + + ksft_print_msg("Adjusting CBM for unrelated ctrlgrp 'c1'\n"); + snprintf(schemata, sizeof(schemata), "%lx", mask3); + ret = write_schemata("c1", schemata, uparams->cpu, test->resource); + if (ret) + goto reset_affinity; + ret = cat_ctrlgrp_check_msr(uparams, mask2); + if (ret) + goto reset_affinity; + + ksft_print_msg("Adjusting CBM for ctrlgrp 'c2'\n"); + snprintf(schemata, sizeof(schemata), "%lx", mask1); + ret = write_schemata("c2", schemata, uparams->cpu, test->resource); + if (ret) + goto reset_affinity; + ret = cat_ctrlgrp_check_msr(uparams, mask1); + if (ret) + goto reset_affinity; + + ksft_print_msg("Placing task to ctrlgrp 'c1'\n"); + ret = write_bm_pid_to_resctrl(bm_pid, "c1", NULL); + if (ret) + goto reset_affinity; + ret = cat_ctrlgrp_check_msr(uparams, mask3); + if (ret) + goto reset_affinity; + +reset_affinity: + taskset_restore(bm_pid, &old_affinity); + + return ret; +} + struct resctrl_test l3_cat_test = { .name = "L3_CAT", .group = "CAT", @@ -484,3 +601,12 @@ struct resctrl_test cat_grp_tasks_test = { .feature_check = test_resource_feature_check, .run_test = cat_ctrlgrp_tasks_test, }; + +struct resctrl_test cat_grp_mask_test = { + .name = "CAT_GROUP_MASK", + .group = "CAT", + .resource = "L3", + .vendor_specific = ARCH_INTEL, + .feature_check = test_resource_feature_check, + .run_test = cat_ctrlgrp_msr_test, +}; diff --git a/tools/testing/selftests/resctrl/msr.c b/tools/testing/selftests/resctrl/msr.c new file mode 100644 index 000000000000..1e8674036c7d --- /dev/null +++ b/tools/testing/selftests/resctrl/msr.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <fcntl.h> +#include <limits.h> +#include <stdbool.h> +#include <stdio.h> +#include <unistd.h> + +#include <linux/types.h> + +#include "resctrl.h" + +#define MSR_PATH "/dev/cpu/%d/msr" + +static int open_msr_file(int cpu) +{ + char msr_path[PATH_MAX]; + + snprintf(msr_path, sizeof(msr_path), MSR_PATH, cpu); + + return open(msr_path, O_RDONLY); +} + +int read_msr(int cpu, __u32 msr, __u64 *val) +{ + ssize_t res; + int fd; + + fd = open_msr_file(cpu); + if (fd < 0) { + ksft_print_msg("Failed to open msr file for CPU %d\n", cpu); + return -1; + } + + res = pread(fd, val, sizeof(*val), msr); + close(fd); + if (res < sizeof(*val)) { + ksft_print_msg("Reading MSR failed\n"); + return -1; + } + + return 0; +} + +bool msr_access_supported(int cpu) +{ + int fd; + + fd = open_msr_file(cpu); + if (fd < 0) + return false; + + close(fd); + return true; +} diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h index d25f83d0a54d..909a101f0e4c 100644 --- a/tools/testing/selftests/resctrl/resctrl.h +++ b/tools/testing/selftests/resctrl/resctrl.h @@ -243,8 +243,12 @@ extern struct resctrl_test mbm_test; extern struct resctrl_test mba_test; extern struct resctrl_test cmt_test; extern struct resctrl_test cat_grp_tasks_test; +extern struct resctrl_test cat_grp_mask_test; extern struct resctrl_test l3_cat_test; extern struct resctrl_test l3_noncont_cat_test; extern struct resctrl_test l2_noncont_cat_test;
+bool msr_access_supported(int cpu); +int read_msr(int cpu, __u32 msr, __u64 *val); + #endif /* RESCTRL_H */ diff --git a/tools/testing/selftests/resctrl/resctrl_tests.c b/tools/testing/selftests/resctrl/resctrl_tests.c index 71b7cd846dc1..08ae48165c7a 100644 --- a/tools/testing/selftests/resctrl/resctrl_tests.c +++ b/tools/testing/selftests/resctrl/resctrl_tests.c @@ -19,6 +19,7 @@ static struct resctrl_test *resctrl_tests[] = { &mba_test, &cmt_test, &cat_grp_tasks_test, + &cat_grp_mask_test, &l3_cat_test, &l3_noncont_cat_test, &l2_noncont_cat_test,