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