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 - %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 * 124 get_vector_filename(void) 125 { 126 return test_params.test_vector_filename; 127 } 128 129 unsigned int 130 get_num_ops(void) 131 { 132 return test_params.num_ops; 133 } 134 135 unsigned int 136 get_burst_sz(void) 137 { 138 return test_params.burst_sz; 139 } 140 141 unsigned int 142 get_num_lcores(void) 143 { 144 return test_params.num_lcores; 145 } 146 147 double 148 get_snr(void) 149 { 150 return test_params.snr; 151 } 152 153 unsigned int 154 get_iter_max(void) 155 { 156 return test_params.iter_max; 157 } 158 159 bool 160 get_init_device(void) 161 { 162 return test_params.init_device; 163 } 164 165 static void 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 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 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 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 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