dpdk/app/test-compress-perf/main.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright(c) 2018 Intel Corporation
   3 */
   4
   5#include <signal.h>
   6#include <sys/types.h>
   7#include <unistd.h>
   8
   9#include <rte_malloc.h>
  10#include <rte_eal.h>
  11#include <rte_log.h>
  12#include <rte_compressdev.h>
  13
  14#include "comp_perf.h"
  15#include "comp_perf_options.h"
  16#include "comp_perf_test_common.h"
  17#include "comp_perf_test_cyclecount.h"
  18#include "comp_perf_test_throughput.h"
  19#include "comp_perf_test_verify.h"
  20
  21#define NUM_MAX_XFORMS 16
  22#define NUM_MAX_INFLIGHT_OPS 512
  23
  24__extension__
  25const char *comp_perf_test_type_strs[] = {
  26        [CPERF_TEST_TYPE_THROUGHPUT] = "throughput",
  27        [CPERF_TEST_TYPE_VERIFY] = "verify",
  28        [CPERF_TEST_TYPE_PMDCC] = "pmd-cyclecount"
  29};
  30
  31__extension__
  32static const struct cperf_test cperf_testmap[] = {
  33        [CPERF_TEST_TYPE_THROUGHPUT] = {
  34                        cperf_throughput_test_constructor,
  35                        cperf_throughput_test_runner,
  36                        cperf_throughput_test_destructor
  37
  38        },
  39        [CPERF_TEST_TYPE_VERIFY] = {
  40                        cperf_verify_test_constructor,
  41                        cperf_verify_test_runner,
  42                        cperf_verify_test_destructor
  43        },
  44
  45        [CPERF_TEST_TYPE_PMDCC] = {
  46                        cperf_cyclecount_test_constructor,
  47                        cperf_cyclecount_test_runner,
  48                        cperf_cyclecount_test_destructor
  49        }
  50};
  51
  52static struct comp_test_data *test_data;
  53
  54static int
  55comp_perf_check_capabilities(struct comp_test_data *test_data, uint8_t cdev_id)
  56{
  57        const struct rte_compressdev_capabilities *cap;
  58
  59        cap = rte_compressdev_capability_get(cdev_id,
  60                                             RTE_COMP_ALGO_DEFLATE);
  61
  62        if (cap == NULL) {
  63                RTE_LOG(ERR, USER1,
  64                        "Compress device does not support DEFLATE\n");
  65                return -1;
  66        }
  67
  68        uint64_t comp_flags = cap->comp_feature_flags;
  69
  70        /* Huffman enconding */
  71        if (test_data->huffman_enc == RTE_COMP_HUFFMAN_FIXED &&
  72                        (comp_flags & RTE_COMP_FF_HUFFMAN_FIXED) == 0) {
  73                RTE_LOG(ERR, USER1,
  74                        "Compress device does not supported Fixed Huffman\n");
  75                return -1;
  76        }
  77
  78        if (test_data->huffman_enc == RTE_COMP_HUFFMAN_DYNAMIC &&
  79                        (comp_flags & RTE_COMP_FF_HUFFMAN_DYNAMIC) == 0) {
  80                RTE_LOG(ERR, USER1,
  81                        "Compress device does not supported Dynamic Huffman\n");
  82                return -1;
  83        }
  84
  85        /* Window size */
  86        if (test_data->window_sz != -1) {
  87                if (param_range_check(test_data->window_sz, &cap->window_size)
  88                                < 0) {
  89                        RTE_LOG(ERR, USER1,
  90                                "Compress device does not support "
  91                                "this window size\n");
  92                        return -1;
  93                }
  94        } else
  95                /* Set window size to PMD maximum if none was specified */
  96                test_data->window_sz = cap->window_size.max;
  97
  98        /* Check if chained mbufs is supported */
  99        if (test_data->max_sgl_segs > 1  &&
 100                        (comp_flags & RTE_COMP_FF_OOP_SGL_IN_SGL_OUT) == 0) {
 101                RTE_LOG(INFO, USER1, "Compress device does not support "
 102                                "chained mbufs. Max SGL segments set to 1\n");
 103                test_data->max_sgl_segs = 1;
 104        }
 105
 106        /* Level 0 support */
 107        if (test_data->level_lst.min == 0 &&
 108                        (comp_flags & RTE_COMP_FF_NONCOMPRESSED_BLOCKS) == 0) {
 109                RTE_LOG(ERR, USER1, "Compress device does not support "
 110                                "level 0 (no compression)\n");
 111                return -1;
 112        }
 113
 114        return 0;
 115}
 116
 117static int
 118comp_perf_initialize_compressdev(struct comp_test_data *test_data,
 119                                 uint8_t *enabled_cdevs)
 120{
 121        uint8_t enabled_cdev_count, nb_lcores, cdev_id;
 122        unsigned int i, j;
 123        int ret;
 124
 125        enabled_cdev_count = rte_compressdev_devices_get(test_data->driver_name,
 126                        enabled_cdevs, RTE_COMPRESS_MAX_DEVS);
 127        if (enabled_cdev_count == 0) {
 128                RTE_LOG(ERR, USER1, "No compress devices type %s available,"
 129                                    " please check the list of specified devices in EAL section\n",
 130                                test_data->driver_name);
 131                return -EINVAL;
 132        }
 133
 134        nb_lcores = rte_lcore_count() - 1;
 135        /*
 136         * Use fewer devices,
 137         * if there are more available than cores.
 138         */
 139        if (enabled_cdev_count > nb_lcores) {
 140                if (nb_lcores == 0) {
 141                        RTE_LOG(ERR, USER1, "Cannot run with 0 cores! Increase the number of cores\n");
 142                        return -EINVAL;
 143                }
 144                enabled_cdev_count = nb_lcores;
 145                RTE_LOG(INFO, USER1,
 146                        "There's more available devices than cores!"
 147                        " The number of devices has been aligned to %d cores\n",
 148                        nb_lcores);
 149        }
 150
 151        /*
 152         * Calculate number of needed queue pairs, based on the amount
 153         * of available number of logical cores and compression devices.
 154         * For instance, if there are 4 cores and 2 compression devices,
 155         * 2 queue pairs will be set up per device.
 156         * One queue pair per one core.
 157         * if e.g.: there're 3 cores and 2 compression devices,
 158         * 2 queue pairs will be set up per device but one queue pair
 159         * will left unused in the last one device
 160         */
 161        test_data->nb_qps = (nb_lcores % enabled_cdev_count) ?
 162                                (nb_lcores / enabled_cdev_count) + 1 :
 163                                nb_lcores / enabled_cdev_count;
 164
 165        for (i = 0; i < enabled_cdev_count &&
 166                        i < RTE_COMPRESS_MAX_DEVS; i++,
 167                                        nb_lcores -= test_data->nb_qps) {
 168                cdev_id = enabled_cdevs[i];
 169
 170                struct rte_compressdev_info cdev_info;
 171                uint8_t socket_id = rte_compressdev_socket_id(cdev_id);
 172
 173                rte_compressdev_info_get(cdev_id, &cdev_info);
 174                if (cdev_info.max_nb_queue_pairs &&
 175                        test_data->nb_qps > cdev_info.max_nb_queue_pairs) {
 176                        RTE_LOG(ERR, USER1,
 177                                "Number of needed queue pairs is higher "
 178                                "than the maximum number of queue pairs "
 179                                "per device.\n");
 180                        RTE_LOG(ERR, USER1,
 181                                "Lower the number of cores or increase "
 182                                "the number of crypto devices\n");
 183                        return -EINVAL;
 184                }
 185
 186                if (comp_perf_check_capabilities(test_data, cdev_id) < 0)
 187                        return -EINVAL;
 188
 189                /* Configure compressdev */
 190                struct rte_compressdev_config config = {
 191                        .socket_id = socket_id,
 192                        .nb_queue_pairs = nb_lcores > test_data->nb_qps
 193                                        ? test_data->nb_qps : nb_lcores,
 194                        .max_nb_priv_xforms = NUM_MAX_XFORMS,
 195                        .max_nb_streams = 0
 196                };
 197
 198                if (rte_compressdev_configure(cdev_id, &config) < 0) {
 199                        RTE_LOG(ERR, USER1, "Device configuration failed\n");
 200                        return -EINVAL;
 201                }
 202
 203                for (j = 0; j < test_data->nb_qps; j++) {
 204                        ret = rte_compressdev_queue_pair_setup(cdev_id, j,
 205                                        NUM_MAX_INFLIGHT_OPS, socket_id);
 206                        if (ret < 0) {
 207                                RTE_LOG(ERR, USER1,
 208                              "Failed to setup queue pair %u on compressdev %u",
 209                                        j, cdev_id);
 210                                return -EINVAL;
 211                        }
 212                }
 213
 214                ret = rte_compressdev_start(cdev_id);
 215                if (ret < 0) {
 216                        RTE_LOG(ERR, USER1,
 217                                "Failed to start device %u: error %d\n",
 218                                cdev_id, ret);
 219                        return -EPERM;
 220                }
 221        }
 222
 223        return enabled_cdev_count;
 224}
 225
 226static int
 227comp_perf_dump_input_data(struct comp_test_data *test_data)
 228{
 229        FILE *f = fopen(test_data->input_file, "r");
 230        int ret = -1;
 231
 232        if (f == NULL) {
 233                RTE_LOG(ERR, USER1, "Input file could not be opened\n");
 234                return -1;
 235        }
 236
 237        if (fseek(f, 0, SEEK_END) != 0) {
 238                RTE_LOG(ERR, USER1, "Size of input could not be calculated\n");
 239                goto end;
 240        }
 241        size_t actual_file_sz = ftell(f);
 242        /* If extended input data size has not been set,
 243         * input data size = file size
 244         */
 245
 246        if (test_data->input_data_sz == 0)
 247                test_data->input_data_sz = actual_file_sz;
 248
 249        if (test_data->input_data_sz <= 0 || actual_file_sz <= 0 ||
 250                        fseek(f, 0, SEEK_SET) != 0) {
 251                RTE_LOG(ERR, USER1, "Size of input could not be calculated\n");
 252                goto end;
 253        }
 254
 255        test_data->input_data = rte_zmalloc_socket(NULL,
 256                                test_data->input_data_sz, 0, rte_socket_id());
 257
 258        if (test_data->input_data == NULL) {
 259                RTE_LOG(ERR, USER1, "Memory to hold the data from the input "
 260                                "file could not be allocated\n");
 261                goto end;
 262        }
 263
 264        size_t remaining_data = test_data->input_data_sz;
 265        uint8_t *data = test_data->input_data;
 266
 267        while (remaining_data > 0) {
 268                size_t data_to_read = RTE_MIN(remaining_data, actual_file_sz);
 269
 270                if (fread(data, data_to_read, 1, f) != 1) {
 271                        RTE_LOG(ERR, USER1, "Input file could not be read\n");
 272                        goto end;
 273                }
 274                if (fseek(f, 0, SEEK_SET) != 0) {
 275                        RTE_LOG(ERR, USER1,
 276                                "Size of input could not be calculated\n");
 277                        goto end;
 278                }
 279                remaining_data -= data_to_read;
 280                data += data_to_read;
 281        }
 282
 283        printf("\n");
 284        if (test_data->input_data_sz > actual_file_sz)
 285                RTE_LOG(INFO, USER1,
 286                  "%zu bytes read from file %s, extending the file %.2f times\n",
 287                        test_data->input_data_sz, test_data->input_file,
 288                        (double)test_data->input_data_sz/actual_file_sz);
 289        else
 290                RTE_LOG(INFO, USER1,
 291                        "%zu bytes read from file %s\n",
 292                        test_data->input_data_sz, test_data->input_file);
 293
 294        ret = 0;
 295
 296end:
 297        fclose(f);
 298        return ret;
 299}
 300
 301static void
 302comp_perf_cleanup_on_signal(int signalNumber __rte_unused)
 303{
 304        test_data->perf_comp_force_stop = 1;
 305}
 306
 307static void
 308comp_perf_register_cleanup_on_signal(void)
 309{
 310        signal(SIGTERM, comp_perf_cleanup_on_signal);
 311        signal(SIGINT, comp_perf_cleanup_on_signal);
 312}
 313
 314int
 315main(int argc, char **argv)
 316{
 317        uint8_t level_idx = 0;
 318        int ret, i;
 319        void *ctx[RTE_MAX_LCORE] = {};
 320        uint8_t enabled_cdevs[RTE_COMPRESS_MAX_DEVS];
 321        int nb_compressdevs = 0;
 322        uint16_t total_nb_qps = 0;
 323        uint8_t cdev_id;
 324        uint32_t lcore_id;
 325
 326        /* Initialise DPDK EAL */
 327        ret = rte_eal_init(argc, argv);
 328        if (ret < 0)
 329                rte_exit(EXIT_FAILURE, "Invalid EAL arguments!\n");
 330        argc -= ret;
 331        argv += ret;
 332
 333        test_data = rte_zmalloc_socket(NULL, sizeof(struct comp_test_data),
 334                                        0, rte_socket_id());
 335
 336        if (test_data == NULL)
 337                rte_exit(EXIT_FAILURE, "Cannot reserve memory in socket %d\n",
 338                                rte_socket_id());
 339
 340        comp_perf_register_cleanup_on_signal();
 341
 342        ret = EXIT_SUCCESS;
 343        test_data->cleanup = ST_TEST_DATA;
 344        comp_perf_options_default(test_data);
 345
 346        if (comp_perf_options_parse(test_data, argc, argv) < 0) {
 347                RTE_LOG(ERR, USER1,
 348                        "Parsing one or more user options failed\n");
 349                ret = EXIT_FAILURE;
 350                goto end;
 351        }
 352
 353        if (comp_perf_options_check(test_data) < 0) {
 354                ret = EXIT_FAILURE;
 355                goto end;
 356        }
 357
 358        nb_compressdevs =
 359                comp_perf_initialize_compressdev(test_data, enabled_cdevs);
 360
 361        if (nb_compressdevs < 1) {
 362                ret = EXIT_FAILURE;
 363                goto end;
 364        }
 365
 366        test_data->cleanup = ST_COMPDEV;
 367        if (comp_perf_dump_input_data(test_data) < 0) {
 368                ret = EXIT_FAILURE;
 369                goto end;
 370        }
 371
 372        test_data->cleanup = ST_INPUT_DATA;
 373
 374        if (test_data->level_lst.inc != 0)
 375                test_data->level = test_data->level_lst.min;
 376        else
 377                test_data->level = test_data->level_lst.list[0];
 378
 379        printf("\nApp uses socket: %u\n", rte_socket_id());
 380        printf("Burst size = %u\n", test_data->burst_sz);
 381        printf("Input data size = %zu\n", test_data->input_data_sz);
 382        if (test_data->test == CPERF_TEST_TYPE_PMDCC)
 383                printf("Cycle-count delay = %u [us]\n",
 384                       test_data->cyclecount_delay);
 385
 386        test_data->cleanup = ST_DURING_TEST;
 387        total_nb_qps = nb_compressdevs * test_data->nb_qps;
 388
 389        i = 0;
 390        uint8_t qp_id = 0, cdev_index = 0;
 391
 392        RTE_LCORE_FOREACH_WORKER(lcore_id) {
 393
 394                if (i == total_nb_qps)
 395                        break;
 396
 397                cdev_id = enabled_cdevs[cdev_index];
 398                ctx[i] = cperf_testmap[test_data->test].constructor(
 399                                                        cdev_id, qp_id,
 400                                                        test_data);
 401                if (ctx[i] == NULL) {
 402                        RTE_LOG(ERR, USER1, "Test run constructor failed\n");
 403                        goto end;
 404                }
 405                qp_id = (qp_id + 1) % test_data->nb_qps;
 406                if (qp_id == 0)
 407                        cdev_index++;
 408                i++;
 409        }
 410
 411        print_test_dynamics(test_data);
 412
 413        while (test_data->level <= test_data->level_lst.max) {
 414
 415                i = 0;
 416                RTE_LCORE_FOREACH_WORKER(lcore_id) {
 417
 418                        if (i == total_nb_qps)
 419                                break;
 420
 421                        rte_eal_remote_launch(
 422                                        cperf_testmap[test_data->test].runner,
 423                                        ctx[i], lcore_id);
 424                        i++;
 425                }
 426                i = 0;
 427                RTE_LCORE_FOREACH_WORKER(lcore_id) {
 428
 429                        if (i == total_nb_qps)
 430                                break;
 431                        ret |= rte_eal_wait_lcore(lcore_id);
 432                        i++;
 433                }
 434
 435                if (ret != EXIT_SUCCESS)
 436                        break;
 437
 438                if (test_data->level_lst.inc != 0)
 439                        test_data->level += test_data->level_lst.inc;
 440                else {
 441                        if (++level_idx == test_data->level_lst.count)
 442                                break;
 443                        test_data->level = test_data->level_lst.list[level_idx];
 444                }
 445        }
 446
 447end:
 448        switch (test_data->cleanup) {
 449
 450        case ST_DURING_TEST:
 451                i = 0;
 452                RTE_LCORE_FOREACH_WORKER(lcore_id) {
 453                        if (i == total_nb_qps)
 454                                break;
 455
 456                        if (ctx[i] && cperf_testmap[test_data->test].destructor)
 457                                cperf_testmap[test_data->test].destructor(
 458                                                                        ctx[i]);
 459                        i++;
 460                }
 461                /* fallthrough */
 462        case ST_INPUT_DATA:
 463                rte_free(test_data->input_data);
 464                /* fallthrough */
 465        case ST_COMPDEV:
 466                for (i = 0; i < nb_compressdevs &&
 467                     i < RTE_COMPRESS_MAX_DEVS; i++) {
 468                        rte_compressdev_stop(enabled_cdevs[i]);
 469                        rte_compressdev_close(enabled_cdevs[i]);
 470                }
 471                /* fallthrough */
 472        case ST_TEST_DATA:
 473                rte_free(test_data);
 474                /* fallthrough */
 475        case ST_CLEAR:
 476        default:
 477                i = rte_eal_cleanup();
 478                if (i) {
 479                        RTE_LOG(ERR, USER1,
 480                                "Error from rte_eal_cleanup(), %d\n", i);
 481                        ret = i;
 482                }
 483                break;
 484        }
 485        return ret;
 486}
 487
 488__rte_weak void *
 489cperf_cyclecount_test_constructor(uint8_t dev_id __rte_unused,
 490                                 uint16_t qp_id __rte_unused,
 491                                 struct comp_test_data *options __rte_unused)
 492{
 493        RTE_LOG(INFO, USER1, "Cycle count test is not supported yet\n");
 494        return NULL;
 495}
 496
 497__rte_weak void
 498cperf_cyclecount_test_destructor(void *arg __rte_unused)
 499{
 500        RTE_LOG(INFO, USER1, "Something wrong happened!!!\n");
 501}
 502
 503__rte_weak int
 504cperf_cyclecount_test_runner(void *test_ctx __rte_unused)
 505{
 506        return 0;
 507}
 508
 509__rte_weak void *
 510cperf_throughput_test_constructor(uint8_t dev_id __rte_unused,
 511                                 uint16_t qp_id __rte_unused,
 512                                 struct comp_test_data *options __rte_unused)
 513{
 514        RTE_LOG(INFO, USER1, "Benchmark test is not supported yet\n");
 515        return NULL;
 516}
 517
 518__rte_weak void
 519cperf_throughput_test_destructor(void *arg __rte_unused)
 520{
 521
 522}
 523
 524__rte_weak int
 525cperf_throughput_test_runner(void *test_ctx __rte_unused)
 526{
 527        return 0;
 528}
 529__rte_weak void *
 530cperf_verify_test_constructor(uint8_t dev_id __rte_unused,
 531                                 uint16_t qp_id __rte_unused,
 532                                 struct comp_test_data *options __rte_unused)
 533{
 534        RTE_LOG(INFO, USER1, "Verify test is not supported yet\n");
 535        return NULL;
 536}
 537
 538__rte_weak void
 539cperf_verify_test_destructor(void *arg __rte_unused)
 540{
 541
 542}
 543
 544__rte_weak int
 545cperf_verify_test_runner(void *test_ctx __rte_unused)
 546{
 547        return 0;
 548}
 549