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