d2b208de35bd9c45f9ffe98a3cdba0eff387d7a4
[dpdk.git] / app / test-compress-perf / comp_perf_options_parse.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Intel Corporation
3  */
4
5 #include <getopt.h>
6 #include <stdint.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <inttypes.h>
10 #include <stdlib.h>
11 #include <errno.h>
12
13 #include <rte_string_fns.h>
14 #include <rte_comp.h>
15
16 #include "comp_perf_options.h"
17
18 #define CPERF_DRIVER_NAME       ("driver-name")
19 #define CPERF_TEST_FILE         ("input-file")
20 #define CPERF_SEG_SIZE          ("seg-sz")
21 #define CPERF_BURST_SIZE        ("burst-sz")
22 #define CPERF_EXTENDED_SIZE     ("extended-input-sz")
23 #define CPERF_POOL_SIZE         ("pool-sz")
24 #define CPERF_MAX_SGL_SEGS      ("max-num-sgl-segs")
25 #define CPERF_NUM_ITER          ("num-iter")
26 #define CPERF_OPTYPE            ("operation")
27 #define CPERF_HUFFMAN_ENC       ("huffman-enc")
28 #define CPERF_LEVEL             ("compress-level")
29 #define CPERF_WINDOW_SIZE       ("window-sz")
30
31 struct name_id_map {
32         const char *name;
33         uint32_t id;
34 };
35
36 static void
37 usage(char *progname)
38 {
39         printf("%s [EAL options] --\n"
40                 " --driver-name NAME: compress driver to use\n"
41                 " --input-file NAME: file to compress and decompress\n"
42                 " --extended-input-sz N: extend file data up to this size (default: no extension)\n"
43                 " --seg-sz N: size of segment to store the data (default: 2048)\n"
44                 " --burst-sz N: compress operation burst size\n"
45                 " --pool-sz N: mempool size for compress operations/mbufs\n"
46                 "               (default: 8192)\n"
47                 " --max-num-sgl-segs N: maximum number of segments for each mbuf\n"
48                 "               (default: 16)\n"
49                 " --num-iter N: number of times the file will be\n"
50                 "               compressed/decompressed (default: 10000)\n"
51                 " --operation [comp/decomp/comp_and_decomp]: perform test on\n"
52                 "               compression, decompression or both operations\n"
53                 " --huffman-enc [fixed/dynamic/default]: Huffman encoding\n"
54                 "               (default: dynamic)\n"
55                 " --compress-level N: compression level, which could be a single value, list or range\n"
56                 "               (default: range between 1 and 9)\n"
57                 " --window-sz N: base two log value of compression window size\n"
58                 "               (e.g.: 15 => 32k, default: max supported by PMD)\n"
59                 " -h: prints this help\n",
60                 progname);
61 }
62
63 static int
64 get_str_key_id_mapping(struct name_id_map *map, unsigned int map_len,
65                 const char *str_key)
66 {
67         unsigned int i;
68
69         for (i = 0; i < map_len; i++) {
70
71                 if (strcmp(str_key, map[i].name) == 0)
72                         return map[i].id;
73         }
74
75         return -1;
76 }
77
78 static int
79 parse_uint32_t(uint32_t *value, const char *arg)
80 {
81         char *end = NULL;
82         unsigned long n = strtoul(arg, &end, 10);
83
84         if ((optarg[0] == '\0') || (end == NULL) || (*end != '\0'))
85                 return -1;
86
87         if (n > UINT32_MAX)
88                 return -ERANGE;
89
90         *value = (uint32_t) n;
91
92         return 0;
93 }
94
95 static int
96 parse_uint16_t(uint16_t *value, const char *arg)
97 {
98         uint32_t val = 0;
99         int ret = parse_uint32_t(&val, arg);
100
101         if (ret < 0)
102                 return ret;
103
104         if (val > UINT16_MAX)
105                 return -ERANGE;
106
107         *value = (uint16_t) val;
108
109         return 0;
110 }
111
112 static int
113 parse_range(const char *arg, uint8_t *min, uint8_t *max, uint8_t *inc)
114 {
115         char *token;
116         uint8_t number;
117
118         char *copy_arg = strdup(arg);
119
120         if (copy_arg == NULL)
121                 return -1;
122
123         errno = 0;
124         token = strtok(copy_arg, ":");
125
126         /* Parse minimum value */
127         if (token != NULL) {
128                 number = strtoul(token, NULL, 10);
129
130                 if (errno == EINVAL || errno == ERANGE)
131                         goto err_range;
132
133                 *min = number;
134         } else
135                 goto err_range;
136
137         token = strtok(NULL, ":");
138
139         /* Parse increment value */
140         if (token != NULL) {
141                 number = strtoul(token, NULL, 10);
142
143                 if (errno == EINVAL || errno == ERANGE ||
144                                 number == 0)
145                         goto err_range;
146
147                 *inc = number;
148         } else
149                 goto err_range;
150
151         token = strtok(NULL, ":");
152
153         /* Parse maximum value */
154         if (token != NULL) {
155                 number = strtoul(token, NULL, 10);
156
157                 if (errno == EINVAL || errno == ERANGE ||
158                                 number < *min)
159                         goto err_range;
160
161                 *max = number;
162         } else
163                 goto err_range;
164
165         if (strtok(NULL, ":") != NULL)
166                 goto err_range;
167
168         free(copy_arg);
169         return 0;
170
171 err_range:
172         free(copy_arg);
173         return -1;
174 }
175
176 static int
177 parse_list(const char *arg, uint8_t *list, uint8_t *min, uint8_t *max)
178 {
179         char *token;
180         uint32_t number;
181         uint8_t count = 0;
182         uint32_t temp_min;
183         uint32_t temp_max;
184
185         char *copy_arg = strdup(arg);
186
187         if (copy_arg == NULL)
188                 return -1;
189
190         errno = 0;
191         token = strtok(copy_arg, ",");
192
193         /* Parse first value */
194         if (token != NULL) {
195                 number = strtoul(token, NULL, 10);
196
197                 if (errno == EINVAL || errno == ERANGE)
198                         goto err_list;
199
200                 list[count++] = number;
201                 temp_min = number;
202                 temp_max = number;
203         } else
204                 goto err_list;
205
206         token = strtok(NULL, ",");
207
208         while (token != NULL) {
209                 if (count == MAX_LIST) {
210                         RTE_LOG(WARNING, USER1,
211                                 "Using only the first %u sizes\n",
212                                         MAX_LIST);
213                         break;
214                 }
215
216                 number = strtoul(token, NULL, 10);
217
218                 if (errno == EINVAL || errno == ERANGE)
219                         goto err_list;
220
221                 list[count++] = number;
222
223                 if (number < temp_min)
224                         temp_min = number;
225                 if (number > temp_max)
226                         temp_max = number;
227
228                 token = strtok(NULL, ",");
229         }
230
231         if (min)
232                 *min = temp_min;
233         if (max)
234                 *max = temp_max;
235
236         free(copy_arg);
237         return count;
238
239 err_list:
240         free(copy_arg);
241         return -1;
242 }
243
244 static int
245 parse_num_iter(struct comp_test_data *test_data, const char *arg)
246 {
247         int ret = parse_uint32_t(&test_data->num_iter, arg);
248
249         if (ret) {
250                 RTE_LOG(ERR, USER1, "Failed to parse total iteration count\n");
251                 return -1;
252         }
253
254         if (test_data->num_iter == 0) {
255                 RTE_LOG(ERR, USER1,
256                                 "Total number of iterations must be higher than 0\n");
257                 return -1;
258         }
259
260         return ret;
261 }
262
263 static int
264 parse_pool_sz(struct comp_test_data *test_data, const char *arg)
265 {
266         int ret = parse_uint32_t(&test_data->pool_sz, arg);
267
268         if (ret) {
269                 RTE_LOG(ERR, USER1, "Failed to parse pool size");
270                 return -1;
271         }
272
273         if (test_data->pool_sz == 0) {
274                 RTE_LOG(ERR, USER1, "Pool size must be higher than 0\n");
275                 return -1;
276         }
277
278         return ret;
279 }
280
281 static int
282 parse_burst_sz(struct comp_test_data *test_data, const char *arg)
283 {
284         int ret = parse_uint16_t(&test_data->burst_sz, arg);
285
286         if (ret) {
287                 RTE_LOG(ERR, USER1, "Failed to parse burst size/s\n");
288                 return -1;
289         }
290
291         if (test_data->burst_sz == 0) {
292                 RTE_LOG(ERR, USER1, "Burst size must be higher than 0\n");
293                 return -1;
294         }
295
296         return 0;
297 }
298
299 static int
300 parse_extended_input_sz(struct comp_test_data *test_data, const char *arg)
301 {
302         uint32_t tmp;
303         int ret = parse_uint32_t(&tmp, arg);
304
305         if (ret) {
306                 RTE_LOG(ERR, USER1, "Failed to parse extended input size\n");
307                 return -1;
308         }
309         test_data->input_data_sz = tmp;
310
311         if (tmp == 0) {
312                 RTE_LOG(ERR, USER1,
313                         "Extended file size must be higher than 0\n");
314                 return -1;
315         }
316         return 0;
317 }
318
319 static int
320 parse_seg_sz(struct comp_test_data *test_data, const char *arg)
321 {
322         int ret = parse_uint16_t(&test_data->seg_sz, arg);
323
324         if (ret) {
325                 RTE_LOG(ERR, USER1, "Failed to parse segment size\n");
326                 return -1;
327         }
328
329         if (test_data->seg_sz == 0) {
330                 RTE_LOG(ERR, USER1, "Segment size must be higher than 0\n");
331                 return -1;
332         }
333
334         return 0;
335 }
336
337 static int
338 parse_max_num_sgl_segs(struct comp_test_data *test_data, const char *arg)
339 {
340         int ret = parse_uint16_t(&test_data->max_sgl_segs, arg);
341
342         if (ret) {
343                 RTE_LOG(ERR, USER1,
344                         "Failed to parse max number of segments per mbuf chain\n");
345                 return -1;
346         }
347
348         if (test_data->max_sgl_segs == 0) {
349                 RTE_LOG(ERR, USER1, "Max number of segments per mbuf chain "
350                         "must be higher than 0\n");
351                 return -1;
352         }
353
354         return 0;
355 }
356
357 static int
358 parse_window_sz(struct comp_test_data *test_data, const char *arg)
359 {
360         int ret = parse_uint16_t((uint16_t *)&test_data->window_sz, arg);
361
362         if (ret) {
363                 RTE_LOG(ERR, USER1, "Failed to parse window size\n");
364                 return -1;
365         }
366
367         return 0;
368 }
369
370 static int
371 parse_driver_name(struct comp_test_data *test_data, const char *arg)
372 {
373         if (strlen(arg) > (sizeof(test_data->driver_name) - 1))
374                 return -1;
375
376         strlcpy(test_data->driver_name, arg,
377                         sizeof(test_data->driver_name));
378
379         return 0;
380 }
381
382 static int
383 parse_test_file(struct comp_test_data *test_data, const char *arg)
384 {
385         if (strlen(arg) > (sizeof(test_data->input_file) - 1))
386                 return -1;
387
388         strlcpy(test_data->input_file, arg, sizeof(test_data->input_file));
389
390         return 0;
391 }
392
393 static int
394 parse_op_type(struct comp_test_data *test_data, const char *arg)
395 {
396         struct name_id_map optype_namemap[] = {
397                 {
398                         "comp",
399                         COMPRESS_ONLY
400                 },
401                 {
402                         "decomp",
403                         DECOMPRESS_ONLY
404                 },
405                 {
406                         "comp_and_decomp",
407                         COMPRESS_DECOMPRESS
408                 }
409         };
410
411         int id = get_str_key_id_mapping(optype_namemap,
412                         RTE_DIM(optype_namemap), arg);
413         if (id < 0) {
414                 RTE_LOG(ERR, USER1, "Invalid operation type specified\n");
415                 return -1;
416         }
417
418         test_data->test_op = (enum comp_operation)id;
419
420         return 0;
421 }
422
423 static int
424 parse_huffman_enc(struct comp_test_data *test_data, const char *arg)
425 {
426         struct name_id_map huffman_namemap[] = {
427                 {
428                         "default",
429                         RTE_COMP_HUFFMAN_DEFAULT
430                 },
431                 {
432                         "fixed",
433                         RTE_COMP_HUFFMAN_FIXED
434                 },
435                 {
436                         "dynamic",
437                         RTE_COMP_HUFFMAN_DYNAMIC
438                 }
439         };
440
441         int id = get_str_key_id_mapping(huffman_namemap,
442                         RTE_DIM(huffman_namemap), arg);
443         if (id < 0) {
444                 RTE_LOG(ERR, USER1, "Invalid Huffmane encoding specified\n");
445                 return -1;
446         }
447
448         test_data->huffman_enc = (enum rte_comp_huffman)id;
449
450         return 0;
451 }
452
453 static int
454 parse_level(struct comp_test_data *test_data, const char *arg)
455 {
456         int ret;
457
458         /*
459          * Try parsing the argument as a range, if it fails,
460          * arse it as a list
461          */
462         if (parse_range(arg, &test_data->level.min, &test_data->level.max,
463                         &test_data->level.inc) < 0) {
464                 ret = parse_list(arg, test_data->level.list,
465                                         &test_data->level.min,
466                                         &test_data->level.max);
467                 if (ret < 0) {
468                         RTE_LOG(ERR, USER1,
469                                 "Failed to parse compression level/s\n");
470                         return -1;
471                 }
472                 test_data->level.count = ret;
473
474                 if (test_data->level.max > RTE_COMP_LEVEL_MAX) {
475                         RTE_LOG(ERR, USER1, "Level cannot be higher than %u\n",
476                                         RTE_COMP_LEVEL_MAX);
477                         return -1;
478                 }
479         }
480
481         return 0;
482 }
483
484 typedef int (*option_parser_t)(struct comp_test_data *test_data,
485                 const char *arg);
486
487 struct long_opt_parser {
488         const char *lgopt_name;
489         option_parser_t parser_fn;
490
491 };
492
493 static struct option lgopts[] = {
494
495         { CPERF_DRIVER_NAME, required_argument, 0, 0 },
496         { CPERF_TEST_FILE, required_argument, 0, 0 },
497         { CPERF_SEG_SIZE, required_argument, 0, 0 },
498         { CPERF_BURST_SIZE, required_argument, 0, 0 },
499         { CPERF_EXTENDED_SIZE, required_argument, 0, 0 },
500         { CPERF_POOL_SIZE, required_argument, 0, 0 },
501         { CPERF_MAX_SGL_SEGS, required_argument, 0, 0},
502         { CPERF_NUM_ITER, required_argument, 0, 0 },
503         { CPERF_OPTYPE, required_argument, 0, 0 },
504         { CPERF_HUFFMAN_ENC, required_argument, 0, 0 },
505         { CPERF_LEVEL, required_argument, 0, 0 },
506         { CPERF_WINDOW_SIZE, required_argument, 0, 0 },
507         { NULL, 0, 0, 0 }
508 };
509 static int
510 comp_perf_opts_parse_long(int opt_idx, struct comp_test_data *test_data)
511 {
512         struct long_opt_parser parsermap[] = {
513                 { CPERF_DRIVER_NAME,    parse_driver_name },
514                 { CPERF_TEST_FILE,      parse_test_file },
515                 { CPERF_SEG_SIZE,       parse_seg_sz },
516                 { CPERF_BURST_SIZE,     parse_burst_sz },
517                 { CPERF_EXTENDED_SIZE,  parse_extended_input_sz },
518                 { CPERF_POOL_SIZE,      parse_pool_sz },
519                 { CPERF_MAX_SGL_SEGS,   parse_max_num_sgl_segs },
520                 { CPERF_NUM_ITER,       parse_num_iter },
521                 { CPERF_OPTYPE,         parse_op_type },
522                 { CPERF_HUFFMAN_ENC,    parse_huffman_enc },
523                 { CPERF_LEVEL,          parse_level },
524                 { CPERF_WINDOW_SIZE,    parse_window_sz },
525         };
526         unsigned int i;
527
528         for (i = 0; i < RTE_DIM(parsermap); i++) {
529                 if (strncmp(lgopts[opt_idx].name, parsermap[i].lgopt_name,
530                                 strlen(lgopts[opt_idx].name)) == 0)
531                         return parsermap[i].parser_fn(test_data, optarg);
532         }
533
534         return -EINVAL;
535 }
536
537 int
538 comp_perf_options_parse(struct comp_test_data *test_data, int argc, char **argv)
539 {
540         int opt, retval, opt_idx;
541
542         while ((opt = getopt_long(argc, argv, "h", lgopts, &opt_idx)) != EOF) {
543                 switch (opt) {
544                 case 'h':
545                         usage(argv[0]);
546                         rte_exit(EXIT_SUCCESS, "Displayed help\n");
547                         break;
548                 /* long options */
549                 case 0:
550                         retval = comp_perf_opts_parse_long(opt_idx, test_data);
551                         if (retval != 0)
552                                 return retval;
553
554                         break;
555
556                 default:
557                         usage(argv[0]);
558                         return -EINVAL;
559                 }
560         }
561
562         return 0;
563 }
564
565 void
566 comp_perf_options_default(struct comp_test_data *test_data)
567 {
568         test_data->cdev_id = -1;
569         test_data->seg_sz = 2048;
570         test_data->burst_sz = 32;
571         test_data->pool_sz = 8192;
572         test_data->max_sgl_segs = 16;
573         test_data->num_iter = 10000;
574         test_data->huffman_enc = RTE_COMP_HUFFMAN_DYNAMIC;
575         test_data->test_op = COMPRESS_DECOMPRESS;
576         test_data->window_sz = -1;
577         test_data->level.min = 1;
578         test_data->level.max = 9;
579         test_data->level.inc = 1;
580 }
581
582 int
583 comp_perf_options_check(struct comp_test_data *test_data)
584 {
585         if (test_data->driver_name[0] == '\0') {
586                 RTE_LOG(ERR, USER1, "Driver name has to be set\n");
587                 return -1;
588         }
589
590         if (test_data->input_file[0] == '\0') {
591                 RTE_LOG(ERR, USER1, "Input file name has to be set\n");
592                 return -1;
593         }
594
595         return 0;
596 }