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 < MIN_COMPRESSED_BUF_SIZE) { 330 RTE_LOG(ERR, USER1, "Segment size must be higher than %d\n", 331 MIN_COMPRESSED_BUF_SIZE - 1); 332 return -1; 333 } 334 335 if (test_data->seg_sz > MAX_SEG_SIZE) { 336 RTE_LOG(ERR, USER1, "Segment size must be lower than %d\n", 337 MAX_SEG_SIZE + 1); 338 return -1; 339 } 340 341 return 0; 342 } 343 344 static int 345 parse_max_num_sgl_segs(struct comp_test_data *test_data, const char *arg) 346 { 347 int ret = parse_uint16_t(&test_data->max_sgl_segs, arg); 348 349 if (ret) { 350 RTE_LOG(ERR, USER1, 351 "Failed to parse max number of segments per mbuf chain\n"); 352 return -1; 353 } 354 355 if (test_data->max_sgl_segs == 0) { 356 RTE_LOG(ERR, USER1, "Max number of segments per mbuf chain " 357 "must be higher than 0\n"); 358 return -1; 359 } 360 361 return 0; 362 } 363 364 static int 365 parse_window_sz(struct comp_test_data *test_data, const char *arg) 366 { 367 uint16_t tmp; 368 int ret = parse_uint16_t(&tmp, arg); 369 370 if (ret) { 371 RTE_LOG(ERR, USER1, "Failed to parse window size\n"); 372 return -1; 373 } 374 test_data->window_sz = (int)tmp; 375 376 return 0; 377 } 378 379 static int 380 parse_driver_name(struct comp_test_data *test_data, const char *arg) 381 { 382 if (strlen(arg) > (sizeof(test_data->driver_name) - 1)) 383 return -1; 384 385 strlcpy(test_data->driver_name, arg, 386 sizeof(test_data->driver_name)); 387 388 return 0; 389 } 390 391 static int 392 parse_test_file(struct comp_test_data *test_data, const char *arg) 393 { 394 if (strlen(arg) > (sizeof(test_data->input_file) - 1)) 395 return -1; 396 397 strlcpy(test_data->input_file, arg, sizeof(test_data->input_file)); 398 399 return 0; 400 } 401 402 static int 403 parse_op_type(struct comp_test_data *test_data, const char *arg) 404 { 405 struct name_id_map optype_namemap[] = { 406 { 407 "comp", 408 COMPRESS_ONLY 409 }, 410 { 411 "decomp", 412 DECOMPRESS_ONLY 413 }, 414 { 415 "comp_and_decomp", 416 COMPRESS_DECOMPRESS 417 } 418 }; 419 420 int id = get_str_key_id_mapping(optype_namemap, 421 RTE_DIM(optype_namemap), arg); 422 if (id < 0) { 423 RTE_LOG(ERR, USER1, "Invalid operation type specified\n"); 424 return -1; 425 } 426 427 test_data->test_op = (enum comp_operation)id; 428 429 return 0; 430 } 431 432 static int 433 parse_huffman_enc(struct comp_test_data *test_data, const char *arg) 434 { 435 struct name_id_map huffman_namemap[] = { 436 { 437 "default", 438 RTE_COMP_HUFFMAN_DEFAULT 439 }, 440 { 441 "fixed", 442 RTE_COMP_HUFFMAN_FIXED 443 }, 444 { 445 "dynamic", 446 RTE_COMP_HUFFMAN_DYNAMIC 447 } 448 }; 449 450 int id = get_str_key_id_mapping(huffman_namemap, 451 RTE_DIM(huffman_namemap), arg); 452 if (id < 0) { 453 RTE_LOG(ERR, USER1, "Invalid Huffmane encoding specified\n"); 454 return -1; 455 } 456 457 test_data->huffman_enc = (enum rte_comp_huffman)id; 458 459 return 0; 460 } 461 462 static int 463 parse_level(struct comp_test_data *test_data, const char *arg) 464 { 465 int ret; 466 467 /* 468 * Try parsing the argument as a range, if it fails, 469 * arse it as a list 470 */ 471 if (parse_range(arg, &test_data->level.min, &test_data->level.max, 472 &test_data->level.inc) < 0) { 473 ret = parse_list(arg, test_data->level.list, 474 &test_data->level.min, 475 &test_data->level.max); 476 if (ret < 0) { 477 RTE_LOG(ERR, USER1, 478 "Failed to parse compression level/s\n"); 479 return -1; 480 } 481 test_data->level.count = ret; 482 483 if (test_data->level.max > RTE_COMP_LEVEL_MAX) { 484 RTE_LOG(ERR, USER1, "Level cannot be higher than %u\n", 485 RTE_COMP_LEVEL_MAX); 486 return -1; 487 } 488 } 489 490 return 0; 491 } 492 493 typedef int (*option_parser_t)(struct comp_test_data *test_data, 494 const char *arg); 495 496 struct long_opt_parser { 497 const char *lgopt_name; 498 option_parser_t parser_fn; 499 500 }; 501 502 static struct option lgopts[] = { 503 504 { CPERF_DRIVER_NAME, required_argument, 0, 0 }, 505 { CPERF_TEST_FILE, required_argument, 0, 0 }, 506 { CPERF_SEG_SIZE, required_argument, 0, 0 }, 507 { CPERF_BURST_SIZE, required_argument, 0, 0 }, 508 { CPERF_EXTENDED_SIZE, required_argument, 0, 0 }, 509 { CPERF_POOL_SIZE, required_argument, 0, 0 }, 510 { CPERF_MAX_SGL_SEGS, required_argument, 0, 0}, 511 { CPERF_NUM_ITER, required_argument, 0, 0 }, 512 { CPERF_OPTYPE, required_argument, 0, 0 }, 513 { CPERF_HUFFMAN_ENC, required_argument, 0, 0 }, 514 { CPERF_LEVEL, required_argument, 0, 0 }, 515 { CPERF_WINDOW_SIZE, required_argument, 0, 0 }, 516 { NULL, 0, 0, 0 } 517 }; 518 static int 519 comp_perf_opts_parse_long(int opt_idx, struct comp_test_data *test_data) 520 { 521 struct long_opt_parser parsermap[] = { 522 { CPERF_DRIVER_NAME, parse_driver_name }, 523 { CPERF_TEST_FILE, parse_test_file }, 524 { CPERF_SEG_SIZE, parse_seg_sz }, 525 { CPERF_BURST_SIZE, parse_burst_sz }, 526 { CPERF_EXTENDED_SIZE, parse_extended_input_sz }, 527 { CPERF_POOL_SIZE, parse_pool_sz }, 528 { CPERF_MAX_SGL_SEGS, parse_max_num_sgl_segs }, 529 { CPERF_NUM_ITER, parse_num_iter }, 530 { CPERF_OPTYPE, parse_op_type }, 531 { CPERF_HUFFMAN_ENC, parse_huffman_enc }, 532 { CPERF_LEVEL, parse_level }, 533 { CPERF_WINDOW_SIZE, parse_window_sz }, 534 }; 535 unsigned int i; 536 537 for (i = 0; i < RTE_DIM(parsermap); i++) { 538 if (strncmp(lgopts[opt_idx].name, parsermap[i].lgopt_name, 539 strlen(lgopts[opt_idx].name)) == 0) 540 return parsermap[i].parser_fn(test_data, optarg); 541 } 542 543 return -EINVAL; 544 } 545 546 int 547 comp_perf_options_parse(struct comp_test_data *test_data, int argc, char **argv) 548 { 549 int opt, retval, opt_idx; 550 551 while ((opt = getopt_long(argc, argv, "h", lgopts, &opt_idx)) != EOF) { 552 switch (opt) { 553 case 'h': 554 usage(argv[0]); 555 rte_exit(EXIT_SUCCESS, "Displayed help\n"); 556 break; 557 /* long options */ 558 case 0: 559 retval = comp_perf_opts_parse_long(opt_idx, test_data); 560 if (retval != 0) 561 return retval; 562 563 break; 564 565 default: 566 usage(argv[0]); 567 return -EINVAL; 568 } 569 } 570 571 return 0; 572 } 573 574 void 575 comp_perf_options_default(struct comp_test_data *test_data) 576 { 577 test_data->cdev_id = -1; 578 test_data->seg_sz = 2048; 579 test_data->burst_sz = 32; 580 test_data->pool_sz = 8192; 581 test_data->max_sgl_segs = 16; 582 test_data->num_iter = 10000; 583 test_data->huffman_enc = RTE_COMP_HUFFMAN_DYNAMIC; 584 test_data->test_op = COMPRESS_DECOMPRESS; 585 test_data->window_sz = -1; 586 test_data->level.min = 1; 587 test_data->level.max = 9; 588 test_data->level.inc = 1; 589 } 590 591 int 592 comp_perf_options_check(struct comp_test_data *test_data) 593 { 594 if (test_data->driver_name[0] == '\0') { 595 RTE_LOG(ERR, USER1, "Driver name has to be set\n"); 596 return -1; 597 } 598 599 if (test_data->input_file[0] == '\0') { 600 RTE_LOG(ERR, USER1, "Input file name has to be set\n"); 601 return -1; 602 } 603 604 return 0; 605 } 606