1
2
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
34#define CPERF_CYCLECOUNT_DELAY_US ("cc-delay-us")
35
36struct name_id_map {
37 const char *name;
38 uint32_t id;
39};
40
41static void
42usage(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
73static int
74get_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
88static int
89parse_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
119static int
120parse_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
136static int
137parse_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
153static int
154parse_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
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
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
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
212err_range:
213 free(copy_arg);
214 return -1;
215}
216
217static int
218parse_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
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
280err_list:
281 free(copy_arg);
282 return -1;
283}
284
285static int
286parse_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
304static int
305parse_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
322static int
323parse_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
340static int
341parse_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
360static int
361parse_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
385static int
386parse_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
405static int
406parse_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
420static int
421parse_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
432static int
433parse_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
443static int
444parse_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
473static int
474parse_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
503static int
504parse_level(struct comp_test_data *test_data, const char *arg)
505{
506 int ret;
507
508
509
510
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
535static int
536parse_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
543static int
544parse_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
556typedef int (*option_parser_t)(struct comp_test_data *test_data,
557 const char *arg);
558
559struct long_opt_parser {
560 const char *lgopt_name;
561 option_parser_t parser_fn;
562};
563
564static 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
583static int
584comp_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
614int
615comp_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 exit(EXIT_SUCCESS);
624 break;
625
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
642void
643comp_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
661int
662comp_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}
676