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