xref: /dpdk/app/test-mldev/ml_options.c (revision 9280ea55ce089be9daedfe9f73085f3c352c75d0)
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
ml_options_default(struct ml_options * opt)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
ml_parse_test_name(struct ml_options * opt,const char * arg)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
ml_parse_dev_id(struct ml_options * opt,const char * arg)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
ml_parse_socket_id(struct ml_options * opt,const char * arg)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
ml_parse_models(struct ml_options * opt,const char * arg)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
ml_parse_filelist(struct ml_options * opt,const char * arg)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
ml_parse_repetitions(struct ml_options * opt,const char * arg)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
ml_parse_burst_size(struct ml_options * opt,const char * arg)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
ml_parse_queue_pairs(struct ml_options * opt,const char * arg)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
ml_parse_queue_size(struct ml_options * opt,const char * arg)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
ml_parse_tolerance(struct ml_options * opt,const char * arg)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
ml_dump_test_options(const char * testname)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
print_usage(char * program)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
ml_opts_parse_long(int opt_idx,struct ml_options * opt)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
ml_options_parse(struct ml_options * opt,int argc,char ** argv)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
ml_options_dump(struct ml_options * opt)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