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 #define BENCHMARK_ARGS		64
14 #define BENCHMARK_ARG_SIZE	64
15 
16 bool is_amd;
17 
18 void detect_amd(void)
19 {
20 	FILE *inf = fopen("/proc/cpuinfo", "r");
21 	char *res;
22 
23 	if (!inf)
24 		return;
25 
26 	res = fgrep(inf, "vendor_id");
27 
28 	if (res) {
29 		char *s = strchr(res, ':');
30 
31 		is_amd = s && !strcmp(s, ": AuthenticAMD\n");
32 		free(res);
33 	}
34 	fclose(inf);
35 }
36 
37 static void cmd_help(void)
38 {
39 	printf("usage: resctrl_tests [-h] [-b \"benchmark_cmd [options]\"] [-t test list] [-n no_of_bits]\n");
40 	printf("\t-b benchmark_cmd [options]: run specified benchmark for MBM, MBA and CMT\n");
41 	printf("\t   default benchmark is builtin fill_buf\n");
42 	printf("\t-t test list: run tests specified in the test list, ");
43 	printf("e.g. -t mbm, mba, cmt, cat\n");
44 	printf("\t-n no_of_bits: run cache tests using specified no of bits in cache bit mask\n");
45 	printf("\t-p cpu_no: specify CPU number to run the test. 1 is default\n");
46 	printf("\t-h: help\n");
47 }
48 
49 void tests_cleanup(void)
50 {
51 	mbm_test_cleanup();
52 	mba_test_cleanup();
53 	cmt_test_cleanup();
54 	cat_test_cleanup();
55 }
56 
57 static void run_mbm_test(bool has_ben, char **benchmark_cmd, int span,
58 			 int cpu_no, char *bw_report)
59 {
60 	int res;
61 
62 	ksft_print_msg("Starting MBM BW change ...\n");
63 
64 	if (!validate_resctrl_feature_request(MBM_STR)) {
65 		ksft_test_result_skip("Hardware does not support MBM or MBM is disabled\n");
66 		return;
67 	}
68 
69 	if (!has_ben)
70 		sprintf(benchmark_cmd[5], "%s", MBA_STR);
71 	res = mbm_bw_change(span, cpu_no, bw_report, benchmark_cmd);
72 	ksft_test_result(!res, "MBM: bw change\n");
73 	mbm_test_cleanup();
74 }
75 
76 static void run_mba_test(bool has_ben, char **benchmark_cmd, int span,
77 			 int cpu_no, char *bw_report)
78 {
79 	int res;
80 
81 	ksft_print_msg("Starting MBA Schemata change ...\n");
82 
83 	if (!validate_resctrl_feature_request(MBA_STR)) {
84 		ksft_test_result_skip("Hardware does not support MBA or MBA is disabled\n");
85 		return;
86 	}
87 
88 	if (!has_ben)
89 		sprintf(benchmark_cmd[1], "%d", span);
90 	res = mba_schemata_change(cpu_no, bw_report, benchmark_cmd);
91 	ksft_test_result(!res, "MBA: schemata change\n");
92 	mba_test_cleanup();
93 }
94 
95 static void run_cmt_test(bool has_ben, char **benchmark_cmd, int cpu_no)
96 {
97 	int res;
98 
99 	ksft_print_msg("Starting CMT test ...\n");
100 	if (!validate_resctrl_feature_request(CMT_STR)) {
101 		ksft_test_result_skip("Hardware does not support CMT or CMT is disabled\n");
102 		return;
103 	}
104 
105 	if (!has_ben)
106 		sprintf(benchmark_cmd[5], "%s", CMT_STR);
107 	res = cmt_resctrl_val(cpu_no, 5, benchmark_cmd);
108 	ksft_test_result(!res, "CMT: test\n");
109 	cmt_test_cleanup();
110 }
111 
112 static void run_cat_test(int cpu_no, int no_of_bits)
113 {
114 	int res;
115 
116 	ksft_print_msg("Starting CAT test ...\n");
117 
118 	if (!validate_resctrl_feature_request(CAT_STR)) {
119 		ksft_test_result_skip("Hardware does not support CAT or CAT is disabled\n");
120 		return;
121 	}
122 
123 	res = cat_perf_miss_val(cpu_no, no_of_bits, "L3");
124 	ksft_test_result(!res, "CAT: test\n");
125 	cat_test_cleanup();
126 }
127 
128 int main(int argc, char **argv)
129 {
130 	bool has_ben = false, mbm_test = true, mba_test = true, cmt_test = true;
131 	int c, cpu_no = 1, span = 250, argc_new = argc, i, no_of_bits = 0;
132 	char *benchmark_cmd[BENCHMARK_ARGS], bw_report[64], bm_type[64];
133 	char benchmark_cmd_area[BENCHMARK_ARGS][BENCHMARK_ARG_SIZE];
134 	int ben_ind, ben_count, tests = 0;
135 	bool cat_test = true;
136 
137 	for (i = 0; i < argc; i++) {
138 		if (strcmp(argv[i], "-b") == 0) {
139 			ben_ind = i + 1;
140 			ben_count = argc - ben_ind;
141 			argc_new = ben_ind - 1;
142 			has_ben = true;
143 			break;
144 		}
145 	}
146 
147 	while ((c = getopt(argc_new, argv, "ht:b:n:p:")) != -1) {
148 		char *token;
149 
150 		switch (c) {
151 		case 't':
152 			token = strtok(optarg, ",");
153 
154 			mbm_test = false;
155 			mba_test = false;
156 			cmt_test = false;
157 			cat_test = false;
158 			while (token) {
159 				if (!strncmp(token, MBM_STR, sizeof(MBM_STR))) {
160 					mbm_test = true;
161 					tests++;
162 				} else if (!strncmp(token, MBA_STR, sizeof(MBA_STR))) {
163 					mba_test = true;
164 					tests++;
165 				} else if (!strncmp(token, CMT_STR, sizeof(CMT_STR))) {
166 					cmt_test = true;
167 					tests++;
168 				} else if (!strncmp(token, CAT_STR, sizeof(CAT_STR))) {
169 					cat_test = true;
170 					tests++;
171 				} else {
172 					printf("invalid argument\n");
173 
174 					return -1;
175 				}
176 				token = strtok(NULL, ":\t");
177 			}
178 			break;
179 		case 'p':
180 			cpu_no = atoi(optarg);
181 			break;
182 		case 'n':
183 			no_of_bits = atoi(optarg);
184 			if (no_of_bits <= 0) {
185 				printf("Bail out! invalid argument for no_of_bits\n");
186 				return -1;
187 			}
188 			break;
189 		case 'h':
190 			cmd_help();
191 
192 			return 0;
193 		default:
194 			printf("invalid argument\n");
195 
196 			return -1;
197 		}
198 	}
199 
200 	ksft_print_header();
201 
202 	/*
203 	 * Typically we need root privileges, because:
204 	 * 1. We write to resctrl FS
205 	 * 2. We execute perf commands
206 	 */
207 	if (geteuid() != 0)
208 		return ksft_exit_fail_msg("Not running as root, abort testing.\n");
209 
210 	/* Detect AMD vendor */
211 	detect_amd();
212 
213 	if (has_ben) {
214 		/* Extract benchmark command from command line. */
215 		for (i = ben_ind; i < argc; i++) {
216 			benchmark_cmd[i - ben_ind] = benchmark_cmd_area[i];
217 			sprintf(benchmark_cmd[i - ben_ind], "%s", argv[i]);
218 		}
219 		benchmark_cmd[ben_count] = NULL;
220 	} else {
221 		/* If no benchmark is given by "-b" argument, use fill_buf. */
222 		for (i = 0; i < 6; i++)
223 			benchmark_cmd[i] = benchmark_cmd_area[i];
224 
225 		strcpy(benchmark_cmd[0], "fill_buf");
226 		sprintf(benchmark_cmd[1], "%d", span);
227 		strcpy(benchmark_cmd[2], "1");
228 		strcpy(benchmark_cmd[3], "1");
229 		strcpy(benchmark_cmd[4], "0");
230 		strcpy(benchmark_cmd[5], "");
231 		benchmark_cmd[6] = NULL;
232 	}
233 
234 	sprintf(bw_report, "reads");
235 	sprintf(bm_type, "fill_buf");
236 
237 	if (!check_resctrlfs_support())
238 		return ksft_exit_fail_msg("resctrl FS does not exist\n");
239 
240 	filter_dmesg();
241 
242 	ksft_set_plan(tests ? : 4);
243 
244 	if (!is_amd && mbm_test)
245 		run_mbm_test(has_ben, benchmark_cmd, span, cpu_no, bw_report);
246 
247 	if (!is_amd && mba_test)
248 		run_mba_test(has_ben, benchmark_cmd, span, cpu_no, bw_report);
249 
250 	if (cmt_test)
251 		run_cmt_test(has_ben, benchmark_cmd, cpu_no);
252 
253 	if (cat_test)
254 		run_cat_test(cpu_no, no_of_bits);
255 
256 	umount_resctrlfs();
257 
258 	return ksft_exit_pass();
259 }
260