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(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(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(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(msg: "Hardware does not support %s\n" , test->name); |
134 | return; |
135 | } |
136 | |
137 | ksft_print_msg(msg: "Starting %s test ...\n" , test->name); |
138 | |
139 | if (test_prepare()) { |
140 | ksft_exit_fail_msg(msg: "Abnormal failure when preparing for the test\n" ); |
141 | return; |
142 | } |
143 | |
144 | if (!test->feature_check(test)) { |
145 | ksft_test_result_skip(msg: "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: &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(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(s1: token, s2: resctrl_tests[i]->name) || |
209 | (resctrl_tests[i]->group && |
210 | !strcasecmp(s1: token, s2: 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(msg: "Not running as root. Skipping...\n" ); |
257 | |
258 | if (!check_resctrlfs_support()) |
259 | return ksft_exit_skip(msg: "resctrl FS does not exist. Enable X86_CPU_RESCTRL config option.\n" ); |
260 | |
261 | if (umount_resctrlfs()) |
262 | return ksft_exit_skip(msg: "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(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(plan: tests); |
280 | |
281 | for (i = 0; i < ARRAY_SIZE(resctrl_tests); i++) |
282 | run_single_test(test: resctrl_tests[i], uparams: &uparams); |
283 | |
284 | free(span_str); |
285 | ksft_finished(); |
286 | } |
287 | |