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