1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Resctrl tests 4 * 5 * Copyright (C) 2018 Intel Corporation 6 * 7 * Authors: 8 * Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>, 9 * Fenghua Yu <fenghua.yu@intel.com> 10 */ 11 #include "resctrl.h" 12 13 /* Volatile memory sink to prevent compiler optimizations */ 14 static volatile int sink_target; 15 volatile int *value_sink = &sink_target; 16 17 static struct resctrl_test *resctrl_tests[] = { 18 &mbm_test, 19 &mba_test, 20 &cmt_test, 21 &l3_cat_test, 22 &l3_noncont_cat_test, 23 &l2_noncont_cat_test, 24 }; 25 26 static int detect_vendor(void) 27 { 28 FILE *inf = fopen("/proc/cpuinfo", "r"); 29 int vendor_id = 0; 30 char *s = NULL; 31 char *res; 32 33 if (!inf) 34 return vendor_id; 35 36 res = fgrep(inf, "vendor_id"); 37 38 if (res) 39 s = strchr(res, ':'); 40 41 if (s && !strcmp(s, ": GenuineIntel\n")) 42 vendor_id = ARCH_INTEL; 43 else if (s && !strcmp(s, ": AuthenticAMD\n")) 44 vendor_id = ARCH_AMD; 45 46 fclose(inf); 47 free(res); 48 return vendor_id; 49 } 50 51 int get_vendor(void) 52 { 53 static int vendor = -1; 54 55 if (vendor == -1) 56 vendor = detect_vendor(); 57 if (vendor == 0) 58 ksft_print_msg("Can not get vendor info...\n"); 59 60 return vendor; 61 } 62 63 static void cmd_help(void) 64 { 65 int i; 66 67 printf("usage: resctrl_tests [-h] [-t test list] [-n no_of_bits] [-b benchmark_cmd [option]...]\n"); 68 printf("\t-b benchmark_cmd [option]...: run specified benchmark for MBM, MBA and CMT\n"); 69 printf("\t default benchmark is builtin fill_buf\n"); 70 printf("\t-t test list: run tests/groups specified by the list, "); 71 printf("e.g. -t mbm,mba,cmt,cat\n"); 72 printf("\t\tSupported tests (group):\n"); 73 for (i = 0; i < ARRAY_SIZE(resctrl_tests); i++) { 74 if (resctrl_tests[i]->group) 75 printf("\t\t\t%s (%s)\n", resctrl_tests[i]->name, resctrl_tests[i]->group); 76 else 77 printf("\t\t\t%s\n", resctrl_tests[i]->name); 78 } 79 printf("\t-n no_of_bits: run cache tests using specified no of bits in cache bit mask\n"); 80 printf("\t-p cpu_no: specify CPU number to run the test. 1 is default\n"); 81 printf("\t-h: help\n"); 82 } 83 84 void tests_cleanup(void) 85 { 86 mbm_test_cleanup(); 87 mba_test_cleanup(); 88 cmt_test_cleanup(); 89 cat_test_cleanup(); 90 } 91 92 static int test_prepare(void) 93 { 94 int res; 95 96 res = signal_handler_register(); 97 if (res) { 98 ksft_print_msg("Failed to register signal handler\n"); 99 return res; 100 } 101 102 res = mount_resctrlfs(); 103 if (res) { 104 signal_handler_unregister(); 105 ksft_print_msg("Failed to mount resctrl FS\n"); 106 return res; 107 } 108 return 0; 109 } 110 111 static void test_cleanup(void) 112 { 113 umount_resctrlfs(); 114 signal_handler_unregister(); 115 } 116 117 static bool test_vendor_specific_check(const struct resctrl_test *test) 118 { 119 if (!test->vendor_specific) 120 return true; 121 122 return get_vendor() & test->vendor_specific; 123 } 124 125 static void run_single_test(const struct resctrl_test *test, const struct user_params *uparams) 126 { 127 int ret; 128 129 if (test->disabled) 130 return; 131 132 if (!test_vendor_specific_check(test)) { 133 ksft_test_result_skip("Hardware does not support %s\n", test->name); 134 return; 135 } 136 137 ksft_print_msg("Starting %s test ...\n", test->name); 138 139 if (test_prepare()) { 140 ksft_exit_fail_msg("Abnormal failure when preparing for the test\n"); 141 return; 142 } 143 144 if (!test->feature_check(test)) { 145 ksft_test_result_skip("Hardware does not support %s or %s is disabled\n", 146 test->name, test->name); 147 goto cleanup; 148 } 149 150 ret = test->run_test(test, uparams); 151 ksft_test_result(!ret, "%s: test\n", test->name); 152 153 cleanup: 154 test_cleanup(); 155 } 156 157 static void init_user_params(struct user_params *uparams) 158 { 159 memset(uparams, 0, sizeof(*uparams)); 160 161 uparams->cpu = 1; 162 uparams->bits = 0; 163 } 164 165 int main(int argc, char **argv) 166 { 167 int tests = ARRAY_SIZE(resctrl_tests); 168 bool test_param_seen = false; 169 struct user_params uparams; 170 char *span_str = NULL; 171 int ret, c, i; 172 173 init_user_params(&uparams); 174 175 while ((c = getopt(argc, argv, "ht:b:n:p:")) != -1) { 176 char *token; 177 178 switch (c) { 179 case 'b': 180 /* 181 * First move optind back to the (first) optarg and 182 * then build the benchmark command using the 183 * remaining arguments. 184 */ 185 optind--; 186 if (argc - optind >= BENCHMARK_ARGS) 187 ksft_exit_fail_msg("Too long benchmark command"); 188 189 /* Extract benchmark command from command line. */ 190 for (i = 0; i < argc - optind; i++) 191 uparams.benchmark_cmd[i] = argv[i + optind]; 192 uparams.benchmark_cmd[i] = NULL; 193 194 goto last_arg; 195 case 't': 196 token = strtok(optarg, ","); 197 198 if (!test_param_seen) { 199 for (i = 0; i < ARRAY_SIZE(resctrl_tests); i++) 200 resctrl_tests[i]->disabled = true; 201 tests = 0; 202 test_param_seen = true; 203 } 204 while (token) { 205 bool found = false; 206 207 for (i = 0; i < ARRAY_SIZE(resctrl_tests); i++) { 208 if (!strcasecmp(token, resctrl_tests[i]->name) || 209 (resctrl_tests[i]->group && 210 !strcasecmp(token, resctrl_tests[i]->group))) { 211 if (resctrl_tests[i]->disabled) 212 tests++; 213 resctrl_tests[i]->disabled = false; 214 found = true; 215 } 216 } 217 218 if (!found) { 219 printf("invalid test: %s\n", token); 220 221 return -1; 222 } 223 token = strtok(NULL, ","); 224 } 225 break; 226 case 'p': 227 uparams.cpu = atoi(optarg); 228 break; 229 case 'n': 230 uparams.bits = atoi(optarg); 231 if (uparams.bits <= 0) { 232 printf("Bail out! invalid argument for no_of_bits\n"); 233 return -1; 234 } 235 break; 236 case 'h': 237 cmd_help(); 238 239 return 0; 240 default: 241 printf("invalid argument\n"); 242 243 return -1; 244 } 245 } 246 last_arg: 247 248 ksft_print_header(); 249 250 /* 251 * Typically we need root privileges, because: 252 * 1. We write to resctrl FS 253 * 2. We execute perf commands 254 */ 255 if (geteuid() != 0) 256 return ksft_exit_skip("Not running as root. Skipping...\n"); 257 258 if (!check_resctrlfs_support()) 259 return ksft_exit_skip("resctrl FS does not exist. Enable X86_CPU_RESCTRL config option.\n"); 260 261 if (umount_resctrlfs()) 262 return ksft_exit_skip("resctrl FS unmount failed.\n"); 263 264 filter_dmesg(); 265 266 if (!uparams.benchmark_cmd[0]) { 267 /* If no benchmark is given by "-b" argument, use fill_buf. */ 268 uparams.benchmark_cmd[0] = "fill_buf"; 269 ret = asprintf(&span_str, "%u", DEFAULT_SPAN); 270 if (ret < 0) 271 ksft_exit_fail_msg("Out of memory!\n"); 272 uparams.benchmark_cmd[1] = span_str; 273 uparams.benchmark_cmd[2] = "1"; 274 uparams.benchmark_cmd[3] = "0"; 275 uparams.benchmark_cmd[4] = "false"; 276 uparams.benchmark_cmd[5] = NULL; 277 } 278 279 ksft_set_plan(tests); 280 281 for (i = 0; i < ARRAY_SIZE(resctrl_tests); i++) 282 run_single_test(resctrl_tests[i], &uparams); 283 284 free(span_str); 285 ksft_finished(); 286 } 287