dpdk/app/test-compress-perf/comp_perf_options_parse.c
<<
>>
Prefs
   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
  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        /* 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
 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        /* 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
 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         * 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
 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                /* 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
 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