]> Git Repo - J-linux.git/blob - tools/testing/selftests/resctrl/resctrl_tests.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / tools / testing / selftests / resctrl / resctrl_tests.c
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         &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 static int test_prepare(const struct resctrl_test *test)
85 {
86         int res;
87
88         res = signal_handler_register(test);
89         if (res) {
90                 ksft_print_msg("Failed to register signal handler\n");
91                 return res;
92         }
93
94         res = mount_resctrlfs();
95         if (res) {
96                 signal_handler_unregister();
97                 ksft_print_msg("Failed to mount resctrl FS\n");
98                 return res;
99         }
100         return 0;
101 }
102
103 static void test_cleanup(const struct resctrl_test *test)
104 {
105         if (test->cleanup)
106                 test->cleanup();
107         umount_resctrlfs();
108         signal_handler_unregister();
109 }
110
111 static bool test_vendor_specific_check(const struct resctrl_test *test)
112 {
113         if (!test->vendor_specific)
114                 return true;
115
116         return get_vendor() & test->vendor_specific;
117 }
118
119 static void run_single_test(const struct resctrl_test *test, const struct user_params *uparams)
120 {
121         int ret;
122
123         if (test->disabled)
124                 return;
125
126         if (!test_vendor_specific_check(test)) {
127                 ksft_test_result_skip("Hardware does not support %s\n", test->name);
128                 return;
129         }
130
131         ksft_print_msg("Starting %s test ...\n", test->name);
132
133         if (test_prepare(test)) {
134                 ksft_exit_fail_msg("Abnormal failure when preparing for the test\n");
135                 return;
136         }
137
138         if (!test->feature_check(test)) {
139                 ksft_test_result_skip("Hardware does not support %s or %s is disabled\n",
140                                       test->name, test->name);
141                 goto cleanup;
142         }
143
144         ret = test->run_test(test, uparams);
145         ksft_test_result(!ret, "%s: test\n", test->name);
146
147 cleanup:
148         test_cleanup(test);
149 }
150
151 /*
152  * Allocate and initialize a struct fill_buf_param with user provided
153  * (via "-b fill_buf <fill_buf parameters>") parameters.
154  *
155  * Use defaults (that may not be appropriate for all tests) for any
156  * fill_buf parameters omitted by the user.
157  *
158  * Historically it may have been possible for user space to provide
159  * additional parameters, "operation" ("read" vs "write") in
160  * benchmark_cmd[3] and "once" (run "once" or until terminated) in
161  * benchmark_cmd[4]. Changing these parameters have never been
162  * supported with the default of "read" operation and running until
163  * terminated built into the tests. Any unsupported values for
164  * (original) "fill_buf" parameters are treated as failure.
165  *
166  * Return: On failure, forcibly exits the test on any parsing failure,
167  *         returns NULL if no parsing needed (user did not actually provide
168  *         "-b fill_buf").
169  *         On success, returns pointer to newly allocated and fully
170  *         initialized struct fill_buf_param that caller must free.
171  */
172 static struct fill_buf_param *alloc_fill_buf_param(struct user_params *uparams)
173 {
174         struct fill_buf_param *fill_param = NULL;
175         char *endptr = NULL;
176
177         if (!uparams->benchmark_cmd[0] || strcmp(uparams->benchmark_cmd[0], "fill_buf"))
178                 return NULL;
179
180         fill_param = malloc(sizeof(*fill_param));
181         if (!fill_param)
182                 ksft_exit_skip("Unable to allocate memory for fill_buf parameters.\n");
183
184         if (uparams->benchmark_cmd[1] && *uparams->benchmark_cmd[1] != '\0') {
185                 errno = 0;
186                 fill_param->buf_size = strtoul(uparams->benchmark_cmd[1], &endptr, 10);
187                 if (errno || *endptr != '\0') {
188                         free(fill_param);
189                         ksft_exit_skip("Unable to parse benchmark buffer size.\n");
190                 }
191         } else {
192                 fill_param->buf_size = MINIMUM_SPAN;
193         }
194
195         if (uparams->benchmark_cmd[2] && *uparams->benchmark_cmd[2] != '\0') {
196                 errno = 0;
197                 fill_param->memflush = strtol(uparams->benchmark_cmd[2], &endptr, 10) != 0;
198                 if (errno || *endptr != '\0') {
199                         free(fill_param);
200                         ksft_exit_skip("Unable to parse benchmark memflush parameter.\n");
201                 }
202         } else {
203                 fill_param->memflush = true;
204         }
205
206         if (uparams->benchmark_cmd[3] && *uparams->benchmark_cmd[3] != '\0') {
207                 if (strcmp(uparams->benchmark_cmd[3], "0")) {
208                         free(fill_param);
209                         ksft_exit_skip("Only read operations supported.\n");
210                 }
211         }
212
213         if (uparams->benchmark_cmd[4] && *uparams->benchmark_cmd[4] != '\0') {
214                 if (strcmp(uparams->benchmark_cmd[4], "false")) {
215                         free(fill_param);
216                         ksft_exit_skip("fill_buf is required to run until termination.\n");
217                 }
218         }
219
220         return fill_param;
221 }
222
223 static void init_user_params(struct user_params *uparams)
224 {
225         memset(uparams, 0, sizeof(*uparams));
226
227         uparams->cpu = 1;
228         uparams->bits = 0;
229 }
230
231 int main(int argc, char **argv)
232 {
233         struct fill_buf_param *fill_param = NULL;
234         int tests = ARRAY_SIZE(resctrl_tests);
235         bool test_param_seen = false;
236         struct user_params uparams;
237         int c, i;
238
239         init_user_params(&uparams);
240
241         while ((c = getopt(argc, argv, "ht:b:n:p:")) != -1) {
242                 char *token;
243
244                 switch (c) {
245                 case 'b':
246                         /*
247                          * First move optind back to the (first) optarg and
248                          * then build the benchmark command using the
249                          * remaining arguments.
250                          */
251                         optind--;
252                         if (argc - optind >= BENCHMARK_ARGS)
253                                 ksft_exit_fail_msg("Too long benchmark command");
254
255                         /* Extract benchmark command from command line. */
256                         for (i = 0; i < argc - optind; i++)
257                                 uparams.benchmark_cmd[i] = argv[i + optind];
258                         uparams.benchmark_cmd[i] = NULL;
259
260                         goto last_arg;
261                 case 't':
262                         token = strtok(optarg, ",");
263
264                         if (!test_param_seen) {
265                                 for (i = 0; i < ARRAY_SIZE(resctrl_tests); i++)
266                                         resctrl_tests[i]->disabled = true;
267                                 tests = 0;
268                                 test_param_seen = true;
269                         }
270                         while (token) {
271                                 bool found = false;
272
273                                 for (i = 0; i < ARRAY_SIZE(resctrl_tests); i++) {
274                                         if (!strcasecmp(token, resctrl_tests[i]->name) ||
275                                             (resctrl_tests[i]->group &&
276                                              !strcasecmp(token, resctrl_tests[i]->group))) {
277                                                 if (resctrl_tests[i]->disabled)
278                                                         tests++;
279                                                 resctrl_tests[i]->disabled = false;
280                                                 found = true;
281                                         }
282                                 }
283
284                                 if (!found) {
285                                         printf("invalid test: %s\n", token);
286
287                                         return -1;
288                                 }
289                                 token = strtok(NULL, ",");
290                         }
291                         break;
292                 case 'p':
293                         uparams.cpu = atoi(optarg);
294                         break;
295                 case 'n':
296                         uparams.bits = atoi(optarg);
297                         if (uparams.bits <= 0) {
298                                 printf("Bail out! invalid argument for no_of_bits\n");
299                                 return -1;
300                         }
301                         break;
302                 case 'h':
303                         cmd_help();
304
305                         return 0;
306                 default:
307                         printf("invalid argument\n");
308
309                         return -1;
310                 }
311         }
312 last_arg:
313
314         fill_param = alloc_fill_buf_param(&uparams);
315         if (fill_param)
316                 uparams.fill_buf = fill_param;
317
318         ksft_print_header();
319
320         /*
321          * Typically we need root privileges, because:
322          * 1. We write to resctrl FS
323          * 2. We execute perf commands
324          */
325         if (geteuid() != 0)
326                 ksft_exit_skip("Not running as root. Skipping...\n");
327
328         if (!check_resctrlfs_support())
329                 ksft_exit_skip("resctrl FS does not exist. Enable X86_CPU_RESCTRL config option.\n");
330
331         if (umount_resctrlfs())
332                 ksft_exit_skip("resctrl FS unmount failed.\n");
333
334         filter_dmesg();
335
336         ksft_set_plan(tests);
337
338         for (i = 0; i < ARRAY_SIZE(resctrl_tests); i++)
339                 run_single_test(resctrl_tests[i], &uparams);
340
341         free(fill_param);
342         ksft_finished();
343 }
This page took 0.046266 seconds and 4 git commands to generate.