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 43 add_test_command(struct test_command *t) 44 { 45 TAILQ_INSERT_TAIL(&commands_list, t, next); 46 } 47 48 int 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\n", suite->suite_name); 111 printf(" + Tests Total : %2d\n", total); 112 printf(" + Tests Skipped : %2d\n", skipped); 113 printf(" + Tests Passed : %2d\n", succeeded); 114 printf(" + Tests Failed : %2d\n", failed); 115 printf(" + Tests Lasted : %lg ms\n", 116 ((end - start) * 1000) / (double)rte_get_tsc_hz()); 117 printf(" + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +\n"); 118 119 return (failed > 0) ? 1 : 0; 120 } 121 122 const char * 123 get_vector_filename(void) 124 { 125 return test_params.test_vector_filename; 126 } 127 128 unsigned int 129 get_num_ops(void) 130 { 131 return test_params.num_ops; 132 } 133 134 unsigned int 135 get_burst_sz(void) 136 { 137 return test_params.burst_sz; 138 } 139 140 unsigned int 141 get_num_lcores(void) 142 { 143 return test_params.num_lcores; 144 } 145 146 double 147 get_snr(void) 148 { 149 return test_params.snr; 150 } 151 152 unsigned int 153 get_iter_max(void) 154 { 155 return test_params.iter_max; 156 } 157 158 bool 159 get_init_device(void) 160 { 161 return test_params.init_device; 162 } 163 164 static void 165 print_usage(const char *prog_name) 166 { 167 struct test_command *t; 168 169 printf("***Usage: %s [EAL params] [-- [-n/--num-ops NUM_OPS]\n" 170 "\t[-b/--burst-size BURST_SIZE]\n" 171 "\t[-v/--test-vector VECTOR_FILE]\n" 172 "\t[-c/--test-cases TEST_CASE[,TEST_CASE,...]]]\n", 173 prog_name); 174 175 printf("Available testcases: "); 176 TAILQ_FOREACH(t, &commands_list, next) 177 printf("%s ", t->command); 178 printf("\n"); 179 } 180 181 static int 182 parse_args(int argc, char **argv, struct test_params *tp) 183 { 184 int opt, option_index; 185 unsigned int num_tests = 0; 186 bool test_cases_present = false; 187 bool test_vector_present = false; 188 struct test_command *t; 189 char *tokens[MAX_CMDLINE_TESTCASES]; 190 int tc, ret; 191 192 static struct option lgopts[] = { 193 { "num-ops", 1, 0, 'n' }, 194 { "burst-size", 1, 0, 'b' }, 195 { "test-cases", 1, 0, 'c' }, 196 { "test-vector", 1, 0, 'v' }, 197 { "lcores", 1, 0, 'l' }, 198 { "snr", 1, 0, 's' }, 199 { "iter_max", 6, 0, 't' }, 200 { "init-device", 0, 0, 'i'}, 201 { "help", 0, 0, 'h' }, 202 { NULL, 0, 0, 0 } 203 }; 204 tp->iter_max = DEFAULT_ITER; 205 206 while ((opt = getopt_long(argc, argv, "hin:b:c:v:l:s:t:", lgopts, 207 &option_index)) != EOF) 208 switch (opt) { 209 case 'n': 210 TEST_ASSERT(strlen(optarg) > 0, 211 "Num of operations is not provided"); 212 tp->num_ops = strtol(optarg, NULL, 10); 213 break; 214 case 'b': 215 TEST_ASSERT(strlen(optarg) > 0, 216 "Burst size is not provided"); 217 tp->burst_sz = strtol(optarg, NULL, 10); 218 TEST_ASSERT(tp->burst_sz <= MAX_BURST, 219 "Burst size mustn't be greater than %u", 220 MAX_BURST); 221 break; 222 case 'c': 223 TEST_ASSERT(test_cases_present == false, 224 "Test cases provided more than once"); 225 test_cases_present = true; 226 227 ret = rte_strsplit(optarg, strlen(optarg), 228 tokens, MAX_CMDLINE_TESTCASES, tc_sep); 229 230 TEST_ASSERT(ret <= MAX_CMDLINE_TESTCASES, 231 "Too many test cases (max=%d)", 232 MAX_CMDLINE_TESTCASES); 233 234 for (tc = 0; tc < ret; ++tc) { 235 /* Find matching test case */ 236 TAILQ_FOREACH(t, &commands_list, next) 237 if (!strcmp(tokens[tc], t->command)) 238 tp->test_to_run[num_tests] = t; 239 240 TEST_ASSERT(tp->test_to_run[num_tests] != NULL, 241 "Unknown test case: %s", 242 tokens[tc]); 243 ++num_tests; 244 } 245 break; 246 case 'v': 247 TEST_ASSERT(test_vector_present == false, 248 "Test vector provided more than once"); 249 test_vector_present = true; 250 251 TEST_ASSERT(strlen(optarg) > 0, 252 "Config file name is null"); 253 254 snprintf(tp->test_vector_filename, 255 sizeof(tp->test_vector_filename), 256 "%s", optarg); 257 break; 258 case 's': 259 TEST_ASSERT(strlen(optarg) > 0, 260 "SNR is not provided"); 261 tp->snr = strtod(optarg, NULL); 262 break; 263 case 't': 264 TEST_ASSERT(strlen(optarg) > 0, 265 "Iter_max is not provided"); 266 tp->iter_max = strtol(optarg, NULL, 10); 267 break; 268 case 'l': 269 TEST_ASSERT(strlen(optarg) > 0, 270 "Num of lcores is not provided"); 271 tp->num_lcores = strtol(optarg, NULL, 10); 272 TEST_ASSERT(tp->num_lcores <= RTE_MAX_LCORE, 273 "Num of lcores mustn't be greater than %u", 274 RTE_MAX_LCORE); 275 break; 276 case 'i': 277 /* indicate fpga fec config required */ 278 tp->init_device = true; 279 break; 280 case 'h': 281 print_usage(argv[0]); 282 return 0; 283 default: 284 printf("ERROR: Unknown option: -%c\n", opt); 285 return -1; 286 } 287 288 if (tp->num_ops == 0) { 289 printf( 290 "WARNING: Num of operations was not provided or was set 0. Set to default (%u)\n", 291 DEFAULT_OPS); 292 tp->num_ops = DEFAULT_OPS; 293 } 294 if (tp->burst_sz == 0) { 295 printf( 296 "WARNING: Burst size was not provided or was set 0. Set to default (%u)\n", 297 DEFAULT_BURST); 298 tp->burst_sz = DEFAULT_BURST; 299 } 300 if (tp->num_lcores == 0) { 301 printf( 302 "WARNING: Num of lcores was not provided or was set 0. Set to value from RTE config (%u)\n", 303 rte_lcore_count()); 304 tp->num_lcores = rte_lcore_count(); 305 } 306 307 TEST_ASSERT(tp->burst_sz <= tp->num_ops, 308 "Burst size (%u) mustn't be greater than num ops (%u)", 309 tp->burst_sz, tp->num_ops); 310 311 tp->num_tests = num_tests; 312 return 0; 313 } 314 315 static int 316 run_all_tests(void) 317 { 318 int ret = TEST_SUCCESS; 319 struct test_command *t; 320 321 TAILQ_FOREACH(t, &commands_list, next) 322 ret |= (int) t->callback(); 323 324 return ret; 325 } 326 327 static int 328 run_parsed_tests(struct test_params *tp) 329 { 330 int ret = TEST_SUCCESS; 331 unsigned int i; 332 333 for (i = 0; i < tp->num_tests; ++i) 334 ret |= (int) tp->test_to_run[i]->callback(); 335 336 return ret; 337 } 338 339 int 340 main(int argc, char **argv) 341 { 342 int ret; 343 344 /* Init EAL */ 345 ret = rte_eal_init(argc, argv); 346 if (ret < 0) 347 return 1; 348 argc -= ret; 349 argv += ret; 350 351 /* Parse application arguments (after the EAL ones) */ 352 ret = parse_args(argc, argv, &test_params); 353 if (ret < 0) { 354 print_usage(argv[0]); 355 return 1; 356 } 357 358 /* If no argument provided - run all tests */ 359 if (test_params.num_tests == 0) 360 return run_all_tests(); 361 else 362 return run_parsed_tests(&test_params); 363 } 364