1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2017 Intel Corporation
3 */
4
5 #include <getopt.h>
6 #include <inttypes.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <stdbool.h>
10 #include <stdlib.h>
11
12 #include <rte_eal.h>
13 #include <rte_common.h>
14 #include <rte_string_fns.h>
15 #include <rte_cycles.h>
16 #include <rte_lcore.h>
17
18 #include "main.h"
19
20
21 /* Defines how many testcases can be specified as cmdline args */
22 #define MAX_CMDLINE_TESTCASES 8
23
24 static const char tc_sep = ',';
25
26 /* Declare structure for command line test parameters and options */
27 static struct test_params {
28 struct test_command *test_to_run[MAX_CMDLINE_TESTCASES];
29 unsigned int num_tests;
30 unsigned int num_ops;
31 unsigned int burst_sz;
32 unsigned int num_lcores;
33 double snr;
34 unsigned int iter_max;
35 char test_vector_filename[PATH_MAX];
36 bool init_device;
37 } test_params;
38
39 static struct test_commands_list commands_list =
40 TAILQ_HEAD_INITIALIZER(commands_list);
41
42 void
add_test_command(struct test_command * t)43 add_test_command(struct test_command *t)
44 {
45 TAILQ_INSERT_TAIL(&commands_list, t, next);
46 }
47
48 int
unit_test_suite_runner(struct unit_test_suite * suite)49 unit_test_suite_runner(struct unit_test_suite *suite)
50 {
51 int test_result = TEST_SUCCESS;
52 unsigned int total = 0, skipped = 0, succeeded = 0, failed = 0;
53 uint64_t start, end;
54
55 printf("\n===========================================================\n");
56 printf("Starting Test Suite : %s\n", suite->suite_name);
57
58 start = rte_rdtsc_precise();
59
60 if (suite->setup) {
61 test_result = suite->setup();
62 if (test_result == TEST_FAILED) {
63 printf(" + Test suite setup %s failed!\n",
64 suite->suite_name);
65 printf(" + ------------------------------------------------------- +\n");
66 return 1;
67 }
68 if (test_result == TEST_SKIPPED) {
69 printf(" + Test suite setup %s skipped!\n",
70 suite->suite_name);
71 printf(" + ------------------------------------------------------- +\n");
72 return 0;
73 }
74 }
75
76 while (suite->unit_test_cases[total].testcase) {
77 if (suite->unit_test_cases[total].setup)
78 test_result = suite->unit_test_cases[total].setup();
79
80 if (test_result == TEST_SUCCESS)
81 test_result = suite->unit_test_cases[total].testcase();
82
83 if (suite->unit_test_cases[total].teardown)
84 suite->unit_test_cases[total].teardown();
85
86 if (test_result == TEST_SUCCESS) {
87 succeeded++;
88 printf("TestCase [%2d] : %s passed\n", total,
89 suite->unit_test_cases[total].name);
90 } else if (test_result == TEST_SKIPPED) {
91 skipped++;
92 printf("TestCase [%2d] : %s skipped\n", total,
93 suite->unit_test_cases[total].name);
94 } else {
95 failed++;
96 printf("TestCase [%2d] : %s failed\n", total,
97 suite->unit_test_cases[total].name);
98 }
99
100 total++;
101 }
102
103 /* Run test suite teardown */
104 if (suite->teardown)
105 suite->teardown();
106
107 end = rte_rdtsc_precise();
108
109 printf(" + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +\n");
110 printf(" + Test Suite Summary : %s - %s\n",
111 suite->suite_name, get_vector_filename());
112 printf(" + Tests Total : %2d\n", total);
113 printf(" + Tests Skipped : %2d\n", skipped);
114 printf(" + Tests Passed : %2d\n", succeeded);
115 printf(" + Tests Failed : %2d\n", failed);
116 printf(" + Tests Lasted : %lg ms\n",
117 ((end - start) * 1000) / (double)rte_get_tsc_hz());
118 printf(" + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +\n");
119
120 return (failed > 0) ? 1 : 0;
121 }
122
123 const char *
get_vector_filename(void)124 get_vector_filename(void)
125 {
126 return test_params.test_vector_filename;
127 }
128
129 unsigned int
get_num_ops(void)130 get_num_ops(void)
131 {
132 return test_params.num_ops;
133 }
134
135 unsigned int
get_burst_sz(void)136 get_burst_sz(void)
137 {
138 return test_params.burst_sz;
139 }
140
141 unsigned int
get_num_lcores(void)142 get_num_lcores(void)
143 {
144 return test_params.num_lcores;
145 }
146
147 double
get_snr(void)148 get_snr(void)
149 {
150 return test_params.snr;
151 }
152
153 unsigned int
get_iter_max(void)154 get_iter_max(void)
155 {
156 return test_params.iter_max;
157 }
158
159 bool
get_init_device(void)160 get_init_device(void)
161 {
162 return test_params.init_device;
163 }
164
165 static void
print_usage(const char * prog_name)166 print_usage(const char *prog_name)
167 {
168 struct test_command *t;
169
170 printf("***Usage: %s [EAL params] [-- [-n/--num-ops NUM_OPS]\n"
171 "\t[-b/--burst-size BURST_SIZE]\n"
172 "\t[-v/--test-vector VECTOR_FILE]\n"
173 "\t[-c/--test-cases TEST_CASE[,TEST_CASE,...]]]\n",
174 prog_name);
175
176 printf("Available testcases: ");
177 TAILQ_FOREACH(t, &commands_list, next)
178 printf("%s ", t->command);
179 printf("\n");
180 }
181
182 static int
parse_args(int argc,char ** argv,struct test_params * tp)183 parse_args(int argc, char **argv, struct test_params *tp)
184 {
185 int opt, option_index;
186 unsigned int num_tests = 0;
187 bool test_cases_present = false;
188 bool test_vector_present = false;
189 struct test_command *t;
190 char *tokens[MAX_CMDLINE_TESTCASES];
191 int tc, ret;
192
193 static struct option lgopts[] = {
194 { "num-ops", 1, 0, 'n' },
195 { "burst-size", 1, 0, 'b' },
196 { "test-cases", 1, 0, 'c' },
197 { "test-vector", 1, 0, 'v' },
198 { "lcores", 1, 0, 'l' },
199 { "snr", 1, 0, 's' },
200 { "iter_max", 6, 0, 't' },
201 { "init-device", 0, 0, 'i'},
202 { "help", 0, 0, 'h' },
203 { NULL, 0, 0, 0 }
204 };
205 tp->iter_max = DEFAULT_ITER;
206
207 while ((opt = getopt_long(argc, argv, "hin:b:c:v:l:s:t:", lgopts,
208 &option_index)) != EOF)
209 switch (opt) {
210 case 'n':
211 TEST_ASSERT(strlen(optarg) > 0,
212 "Num of operations is not provided");
213 tp->num_ops = strtol(optarg, NULL, 10);
214 break;
215 case 'b':
216 TEST_ASSERT(strlen(optarg) > 0,
217 "Burst size is not provided");
218 tp->burst_sz = strtol(optarg, NULL, 10);
219 TEST_ASSERT(tp->burst_sz <= MAX_BURST,
220 "Burst size mustn't be greater than %u",
221 MAX_BURST);
222 break;
223 case 'c':
224 TEST_ASSERT(test_cases_present == false,
225 "Test cases provided more than once");
226 test_cases_present = true;
227
228 ret = rte_strsplit(optarg, strlen(optarg),
229 tokens, MAX_CMDLINE_TESTCASES, tc_sep);
230
231 TEST_ASSERT(ret <= MAX_CMDLINE_TESTCASES,
232 "Too many test cases (max=%d)",
233 MAX_CMDLINE_TESTCASES);
234
235 for (tc = 0; tc < ret; ++tc) {
236 /* Find matching test case */
237 TAILQ_FOREACH(t, &commands_list, next)
238 if (!strcmp(tokens[tc], t->command))
239 tp->test_to_run[num_tests] = t;
240
241 TEST_ASSERT(tp->test_to_run[num_tests] != NULL,
242 "Unknown test case: %s",
243 tokens[tc]);
244 ++num_tests;
245 }
246 break;
247 case 'v':
248 TEST_ASSERT(test_vector_present == false,
249 "Test vector provided more than once");
250 test_vector_present = true;
251
252 TEST_ASSERT(strlen(optarg) > 0,
253 "Config file name is null");
254
255 snprintf(tp->test_vector_filename,
256 sizeof(tp->test_vector_filename),
257 "%s", optarg);
258 break;
259 case 's':
260 TEST_ASSERT(strlen(optarg) > 0,
261 "SNR is not provided");
262 tp->snr = strtod(optarg, NULL);
263 break;
264 case 't':
265 TEST_ASSERT(strlen(optarg) > 0,
266 "Iter_max is not provided");
267 tp->iter_max = strtol(optarg, NULL, 10);
268 break;
269 case 'l':
270 TEST_ASSERT(strlen(optarg) > 0,
271 "Num of lcores is not provided");
272 tp->num_lcores = strtol(optarg, NULL, 10);
273 TEST_ASSERT(tp->num_lcores <= RTE_MAX_LCORE,
274 "Num of lcores mustn't be greater than %u",
275 RTE_MAX_LCORE);
276 break;
277 case 'i':
278 /* indicate fpga fec config required */
279 tp->init_device = true;
280 break;
281 case 'h':
282 print_usage(argv[0]);
283 return 0;
284 default:
285 printf("ERROR: Unknown option: -%c\n", opt);
286 return -1;
287 }
288
289 if (tp->num_ops == 0) {
290 printf(
291 "WARNING: Num of operations was not provided or was set 0. Set to default (%u)\n",
292 DEFAULT_OPS);
293 tp->num_ops = DEFAULT_OPS;
294 }
295 if (tp->burst_sz == 0) {
296 printf(
297 "WARNING: Burst size was not provided or was set 0. Set to default (%u)\n",
298 DEFAULT_BURST);
299 tp->burst_sz = DEFAULT_BURST;
300 }
301 if (tp->num_lcores == 0) {
302 printf(
303 "WARNING: Num of lcores was not provided or was set 0. Set to value from RTE config (%u)\n",
304 rte_lcore_count());
305 tp->num_lcores = rte_lcore_count();
306 }
307
308 TEST_ASSERT(tp->burst_sz <= tp->num_ops,
309 "Burst size (%u) mustn't be greater than num ops (%u)",
310 tp->burst_sz, tp->num_ops);
311
312 tp->num_tests = num_tests;
313 return 0;
314 }
315
316 static int
run_all_tests(void)317 run_all_tests(void)
318 {
319 int ret = TEST_SUCCESS;
320 struct test_command *t;
321
322 TAILQ_FOREACH(t, &commands_list, next)
323 ret |= (int) t->callback();
324
325 return ret;
326 }
327
328 static int
run_parsed_tests(struct test_params * tp)329 run_parsed_tests(struct test_params *tp)
330 {
331 int ret = TEST_SUCCESS;
332 unsigned int i;
333
334 for (i = 0; i < tp->num_tests; ++i)
335 ret |= (int) tp->test_to_run[i]->callback();
336
337 return ret;
338 }
339
340 int
main(int argc,char ** argv)341 main(int argc, char **argv)
342 {
343 int ret;
344
345 /* Init EAL */
346 ret = rte_eal_init(argc, argv);
347 if (ret < 0)
348 return 1;
349 argc -= ret;
350 argv += ret;
351
352 /* Parse application arguments (after the EAL ones) */
353 ret = parse_args(argc, argv, &test_params);
354 if (ret < 0) {
355 print_usage(argv[0]);
356 return 1;
357 }
358
359 /* If no argument provided - run all tests */
360 if (test_params.num_tests == 0)
361 return run_all_tests();
362 else
363 return run_parsed_tests(&test_params);
364 }
365