1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2022 Marvell. 3 */ 4 5 #include <errno.h> 6 #include <getopt.h> 7 #include <math.h> 8 9 #include <rte_memory.h> 10 #include <rte_mldev.h> 11 #include <rte_string_fns.h> 12 13 #include "ml_common.h" 14 #include "ml_test.h" 15 #include "parser.h" 16 17 typedef int (*option_parser_t)(struct ml_options *opt, const char *arg); 18 19 void 20 ml_options_default(struct ml_options *opt) 21 { 22 memset(opt, 0, sizeof(*opt)); 23 strlcpy(opt->test_name, "device_ops", ML_TEST_NAME_MAX_LEN); 24 opt->dev_id = 0; 25 opt->socket_id = SOCKET_ID_ANY; 26 opt->nb_filelist = 0; 27 opt->quantized_io = false; 28 opt->repetitions = 1; 29 opt->burst_size = 1; 30 opt->queue_pairs = 1; 31 opt->queue_size = 1; 32 opt->tolerance = 0.0; 33 opt->stats = false; 34 opt->debug = false; 35 } 36 37 struct long_opt_parser { 38 const char *lgopt_name; 39 option_parser_t parser_fn; 40 }; 41 42 static int 43 ml_parse_test_name(struct ml_options *opt, const char *arg) 44 { 45 strlcpy(opt->test_name, arg, ML_TEST_NAME_MAX_LEN); 46 47 return 0; 48 } 49 50 static int 51 ml_parse_dev_id(struct ml_options *opt, const char *arg) 52 { 53 int ret; 54 55 ret = parser_read_int16(&opt->dev_id, arg); 56 if (ret < 0) 57 ml_err("Invalid option: dev_id = %s\n", arg); 58 59 return ret; 60 } 61 62 static int 63 ml_parse_socket_id(struct ml_options *opt, const char *arg) 64 { 65 int ret; 66 67 ret = parser_read_int32(&opt->socket_id, arg); 68 if (ret < 0) 69 ml_err("Invalid option: socket_id = %s\n", arg); 70 71 return ret; 72 } 73 74 static int 75 ml_parse_models(struct ml_options *opt, const char *arg) 76 { 77 const char *delim = ","; 78 char models[PATH_MAX]; 79 char *token; 80 int ret = 0; 81 82 strlcpy(models, arg, PATH_MAX); 83 84 token = strtok(models, delim); 85 while (token != NULL) { 86 if (opt->nb_filelist >= ML_TEST_MAX_MODELS) { 87 ml_err("Exceeded model count, max = %d\n", ML_TEST_MAX_MODELS); 88 ret = -EINVAL; 89 break; 90 } 91 92 strlcpy(opt->filelist[opt->nb_filelist].model, token, PATH_MAX); 93 opt->nb_filelist++; 94 95 token = strtok(NULL, delim); 96 } 97 98 if (opt->nb_filelist == 0) { 99 ml_err("Models list is empty. Need at least one model for the test"); 100 ret = -EINVAL; 101 } 102 103 return ret; 104 } 105 106 static int 107 ml_parse_filelist(struct ml_options *opt, const char *arg) 108 { 109 const char *delim = ","; 110 char filelist[PATH_MAX]; 111 char *token; 112 113 if (opt->nb_filelist >= ML_TEST_MAX_MODELS) { 114 ml_err("Exceeded filelist count, max = %d\n", ML_TEST_MAX_MODELS); 115 return -1; 116 } 117 118 strlcpy(filelist, arg, PATH_MAX); 119 120 /* model */ 121 token = strtok(filelist, delim); 122 if (token == NULL) { 123 ml_err("Invalid filelist, model not specified = %s\n", arg); 124 return -EINVAL; 125 } 126 strlcpy(opt->filelist[opt->nb_filelist].model, token, PATH_MAX); 127 128 /* input */ 129 token = strtok(NULL, delim); 130 if (token == NULL) { 131 ml_err("Invalid filelist, input not specified = %s\n", arg); 132 return -EINVAL; 133 } 134 strlcpy(opt->filelist[opt->nb_filelist].input, token, PATH_MAX); 135 136 /* output */ 137 token = strtok(NULL, delim); 138 if (token == NULL) { 139 ml_err("Invalid filelist, output not specified = %s\n", arg); 140 return -EINVAL; 141 } 142 strlcpy(opt->filelist[opt->nb_filelist].output, token, PATH_MAX); 143 144 /* reference - optional */ 145 token = strtok(NULL, delim); 146 if (token != NULL) 147 strlcpy(opt->filelist[opt->nb_filelist].reference, token, PATH_MAX); 148 else 149 memset(opt->filelist[opt->nb_filelist].reference, 0, PATH_MAX); 150 151 /* check for extra tokens */ 152 token = strtok(NULL, delim); 153 if (token != NULL) { 154 ml_err("Invalid filelist. Entries > 4\n."); 155 return -EINVAL; 156 } 157 158 opt->nb_filelist++; 159 160 if (opt->nb_filelist == 0) { 161 ml_err("Empty filelist. Need at least one filelist entry for the test.\n"); 162 return -EINVAL; 163 } 164 165 return 0; 166 } 167 168 static int 169 ml_parse_repetitions(struct ml_options *opt, const char *arg) 170 { 171 int ret; 172 173 ret = parser_read_uint64(&opt->repetitions, arg); 174 if (ret != 0) 175 ml_err("Invalid option, repetitions = %s\n", arg); 176 177 return ret; 178 } 179 180 static int 181 ml_parse_burst_size(struct ml_options *opt, const char *arg) 182 { 183 int ret; 184 185 ret = parser_read_uint16(&opt->burst_size, arg); 186 if (ret != 0) 187 ml_err("Invalid option, burst_size = %s\n", arg); 188 189 return ret; 190 } 191 192 static int 193 ml_parse_queue_pairs(struct ml_options *opt, const char *arg) 194 { 195 int ret; 196 197 ret = parser_read_uint16(&opt->queue_pairs, arg); 198 if (ret != 0) 199 ml_err("Invalid option, queue_pairs = %s\n", arg); 200 201 return ret; 202 } 203 204 static int 205 ml_parse_queue_size(struct ml_options *opt, const char *arg) 206 { 207 int ret; 208 209 ret = parser_read_uint16(&opt->queue_size, arg); 210 if (ret != 0) 211 ml_err("Invalid option, queue_size = %s\n", arg); 212 213 return ret; 214 } 215 216 static int 217 ml_parse_tolerance(struct ml_options *opt, const char *arg) 218 { 219 opt->tolerance = fabs(atof(arg)); 220 221 return 0; 222 } 223 224 static void 225 ml_dump_test_options(const char *testname) 226 { 227 if (strcmp(testname, "device_ops") == 0) { 228 printf("\t\t--queue_pairs : number of queue pairs to create\n" 229 "\t\t--queue_size : size of queue-pair\n"); 230 printf("\n"); 231 } 232 233 if (strcmp(testname, "model_ops") == 0) { 234 printf("\t\t--models : comma separated list of models\n" 235 "\t\t--stats : enable reporting device statistics\n"); 236 printf("\n"); 237 } 238 239 if ((strcmp(testname, "inference_ordered") == 0) || 240 (strcmp(testname, "inference_interleave") == 0)) { 241 printf("\t\t--filelist : comma separated list of model, input, output and reference\n" 242 "\t\t--repetitions : number of inference repetitions\n" 243 "\t\t--burst_size : inference burst size\n" 244 "\t\t--queue_pairs : number of queue pairs to create\n" 245 "\t\t--queue_size : size of queue-pair\n" 246 "\t\t--tolerance : maximum tolerance (%%) for output validation\n" 247 "\t\t--stats : enable reporting device and model statistics\n" 248 "\t\t--quantized_io : skip input/output quantization\n"); 249 printf("\n"); 250 } 251 } 252 253 static void 254 print_usage(char *program) 255 { 256 printf("\nusage : %s [EAL options] -- [application options]\n", program); 257 printf("application options:\n"); 258 printf("\t--test : name of the test application to run\n" 259 "\t--dev_id : device id of the ML device\n" 260 "\t--socket_id : socket_id of application resources\n" 261 "\t--debug : enable debug mode\n" 262 "\t--help : print help\n"); 263 printf("\n"); 264 printf("available tests and test specific application options:\n"); 265 ml_test_dump_names(ml_dump_test_options); 266 } 267 268 static struct option lgopts[] = { 269 {ML_TEST, 1, 0, 0}, 270 {ML_DEVICE_ID, 1, 0, 0}, 271 {ML_SOCKET_ID, 1, 0, 0}, 272 {ML_MODELS, 1, 0, 0}, 273 {ML_FILELIST, 1, 0, 0}, 274 {ML_QUANTIZED_IO, 0, 0, 0}, 275 {ML_REPETITIONS, 1, 0, 0}, 276 {ML_BURST_SIZE, 1, 0, 0}, 277 {ML_QUEUE_PAIRS, 1, 0, 0}, 278 {ML_QUEUE_SIZE, 1, 0, 0}, 279 {ML_TOLERANCE, 1, 0, 0}, 280 {ML_STATS, 0, 0, 0}, 281 {ML_DEBUG, 0, 0, 0}, 282 {ML_HELP, 0, 0, 0}, 283 {NULL, 0, 0, 0}}; 284 285 static int 286 ml_opts_parse_long(int opt_idx, struct ml_options *opt) 287 { 288 unsigned int i; 289 290 struct long_opt_parser parsermap[] = { 291 {ML_TEST, ml_parse_test_name}, 292 {ML_DEVICE_ID, ml_parse_dev_id}, 293 {ML_SOCKET_ID, ml_parse_socket_id}, 294 {ML_MODELS, ml_parse_models}, 295 {ML_FILELIST, ml_parse_filelist}, 296 {ML_REPETITIONS, ml_parse_repetitions}, 297 {ML_BURST_SIZE, ml_parse_burst_size}, 298 {ML_QUEUE_PAIRS, ml_parse_queue_pairs}, 299 {ML_QUEUE_SIZE, ml_parse_queue_size}, 300 {ML_TOLERANCE, ml_parse_tolerance}, 301 }; 302 303 for (i = 0; i < RTE_DIM(parsermap); i++) { 304 if (strncmp(lgopts[opt_idx].name, parsermap[i].lgopt_name, 305 strlen(lgopts[opt_idx].name)) == 0) 306 return parsermap[i].parser_fn(opt, optarg); 307 } 308 309 return -EINVAL; 310 } 311 312 int 313 ml_options_parse(struct ml_options *opt, int argc, char **argv) 314 { 315 int opt_idx; 316 int retval; 317 int opts; 318 319 while ((opts = getopt_long(argc, argv, "", lgopts, &opt_idx)) != EOF) { 320 switch (opts) { 321 case 0: /* parse long options */ 322 if (!strcmp(lgopts[opt_idx].name, "quantized_io")) { 323 opt->quantized_io = true; 324 break; 325 } 326 327 if (!strcmp(lgopts[opt_idx].name, "stats")) { 328 opt->stats = true; 329 break; 330 } 331 332 if (!strcmp(lgopts[opt_idx].name, "debug")) { 333 opt->debug = true; 334 break; 335 } 336 337 if (!strcmp(lgopts[opt_idx].name, "help")) { 338 print_usage(argv[0]); 339 exit(EXIT_SUCCESS); 340 } 341 342 retval = ml_opts_parse_long(opt_idx, opt); 343 if (retval != 0) 344 return retval; 345 break; 346 default: 347 return -EINVAL; 348 } 349 } 350 351 return 0; 352 } 353 354 void 355 ml_options_dump(struct ml_options *opt) 356 { 357 struct rte_ml_dev_info dev_info; 358 359 rte_ml_dev_info_get(opt->dev_id, &dev_info); 360 361 ml_dump("driver", "%s", dev_info.driver_name); 362 ml_dump("test", "%s", opt->test_name); 363 ml_dump("dev_id", "%d", opt->dev_id); 364 365 if (opt->socket_id == SOCKET_ID_ANY) 366 ml_dump("socket_id", "%d (SOCKET_ID_ANY)", opt->socket_id); 367 else 368 ml_dump("socket_id", "%d", opt->socket_id); 369 370 ml_dump("debug", "%s", (opt->debug ? "true" : "false")); 371 ml_dump("quantized_io", "%s", (opt->quantized_io ? "true" : "false")); 372 } 373