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