dpdk/app/test-regex/main.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: BSD-3-Clause
   2 * Copyright 2020 Mellanox Technologies, Ltd
   3 */
   4
   5#include <stdio.h>
   6#include <stdlib.h>
   7#include <string.h>
   8#include <stdint.h>
   9#include <stdbool.h>
  10#include <stdarg.h>
  11#include <ctype.h>
  12#include <errno.h>
  13#include <getopt.h>
  14#include <signal.h>
  15
  16#include <rte_eal.h>
  17#include <rte_common.h>
  18#include <rte_malloc.h>
  19#include <rte_mempool.h>
  20#include <rte_mbuf.h>
  21#include <rte_cycles.h>
  22#include <rte_regexdev.h>
  23
  24#define MAX_FILE_NAME 255
  25#define MBUF_CACHE_SIZE 256
  26#define MBUF_SIZE (1 << 8)
  27#define START_BURST_SIZE 32u
  28
  29enum app_args {
  30        ARG_HELP,
  31        ARG_RULES_FILE_NAME,
  32        ARG_DATA_FILE_NAME,
  33        ARG_NUM_OF_JOBS,
  34        ARG_PERF_MODE,
  35        ARG_NUM_OF_ITERATIONS,
  36        ARG_NUM_OF_QPS,
  37        ARG_NUM_OF_LCORES,
  38        ARG_NUM_OF_MBUF_SEGS,
  39};
  40
  41struct job_ctx {
  42        struct rte_mbuf *mbuf;
  43};
  44
  45struct qp_params {
  46        uint32_t total_enqueue;
  47        uint32_t total_dequeue;
  48        uint32_t total_matches;
  49        struct rte_regex_ops **ops;
  50        struct job_ctx *jobs_ctx;
  51        char *buf;
  52        uint64_t start;
  53        uint64_t cycles;
  54};
  55
  56struct qps_per_lcore {
  57        unsigned int lcore_id;
  58        int socket;
  59        uint16_t qp_id_base;
  60        uint16_t nb_qps;
  61};
  62
  63struct regex_conf {
  64        uint32_t nb_jobs;
  65        bool perf_mode;
  66        uint32_t nb_iterations;
  67        char *data_file;
  68        uint8_t nb_max_matches;
  69        uint32_t nb_qps;
  70        uint16_t qp_id_base;
  71        char *data_buf;
  72        long data_len;
  73        long job_len;
  74        uint32_t nb_segs;
  75};
  76
  77static void
  78usage(const char *prog_name)
  79{
  80        printf("%s [EAL options] --\n"
  81                " --rules NAME: precompiled rules file\n"
  82                " --data NAME: data file to use\n"
  83                " --nb_jobs: number of jobs to use\n"
  84                " --perf N: only outputs the performance data\n"
  85                " --nb_iter N: number of iteration to run\n"
  86                " --nb_qps N: number of queues to use\n"
  87                " --nb_lcores N: number of lcores to use\n"
  88                " --nb_segs N: number of mbuf segments\n",
  89                prog_name);
  90}
  91
  92static void
  93args_parse(int argc, char **argv, char *rules_file, char *data_file,
  94           uint32_t *nb_jobs, bool *perf_mode, uint32_t *nb_iterations,
  95           uint32_t *nb_qps, uint32_t *nb_lcores, uint32_t *nb_segs)
  96{
  97        char **argvopt;
  98        int opt;
  99        int opt_idx;
 100        size_t len;
 101        static struct option lgopts[] = {
 102                { "help",  0, 0, ARG_HELP},
 103                /* Rules database file to load. */
 104                { "rules",  1, 0, ARG_RULES_FILE_NAME},
 105                /* Data file to load. */
 106                { "data",  1, 0, ARG_DATA_FILE_NAME},
 107                /* Number of jobs to create. */
 108                { "nb_jobs",  1, 0, ARG_NUM_OF_JOBS},
 109                /* Perf test only */
 110                { "perf", 0, 0, ARG_PERF_MODE},
 111                /* Number of iterations to run with perf test */
 112                { "nb_iter", 1, 0, ARG_NUM_OF_ITERATIONS},
 113                /* Number of QPs. */
 114                { "nb_qps", 1, 0, ARG_NUM_OF_QPS},
 115                /* Number of lcores. */
 116                { "nb_lcores", 1, 0, ARG_NUM_OF_LCORES},
 117                /* Number of mbuf segments. */
 118                { "nb_segs", 1, 0, ARG_NUM_OF_MBUF_SEGS},
 119                /* End of options */
 120                { 0, 0, 0, 0 }
 121        };
 122
 123        argvopt = argv;
 124        while ((opt = getopt_long(argc, argvopt, "",
 125                                lgopts, &opt_idx)) != EOF) {
 126                switch (opt) {
 127                case ARG_RULES_FILE_NAME:
 128                        len = strnlen(optarg, MAX_FILE_NAME - 1);
 129                        if (len == MAX_FILE_NAME)
 130                                rte_exit(EXIT_FAILURE,
 131                                         "Rule file name to long max %d\n",
 132                                         MAX_FILE_NAME - 1);
 133                        strncpy(rules_file, optarg, MAX_FILE_NAME - 1);
 134                        break;
 135                case ARG_DATA_FILE_NAME:
 136                        len = strnlen(optarg, MAX_FILE_NAME - 1);
 137                        if (len == MAX_FILE_NAME)
 138                                rte_exit(EXIT_FAILURE,
 139                                         "Data file name to long max %d\n",
 140                                         MAX_FILE_NAME - 1);
 141                        strncpy(data_file, optarg, MAX_FILE_NAME - 1);
 142                        break;
 143                case ARG_NUM_OF_JOBS:
 144                        *nb_jobs = atoi(optarg);
 145                        break;
 146                case ARG_PERF_MODE:
 147                        *perf_mode = true;
 148                        break;
 149                case ARG_NUM_OF_ITERATIONS:
 150                        *nb_iterations = atoi(optarg);
 151                        break;
 152                case ARG_NUM_OF_QPS:
 153                        *nb_qps = atoi(optarg);
 154                        break;
 155                case ARG_NUM_OF_LCORES:
 156                        *nb_lcores = atoi(optarg);
 157                        break;
 158                case ARG_NUM_OF_MBUF_SEGS:
 159                        *nb_segs = atoi(optarg);
 160                        break;
 161                case ARG_HELP:
 162                        usage(argv[0]);
 163                        break;
 164                default:
 165                        usage(argv[0]);
 166                        rte_exit(EXIT_FAILURE, "Invalid option: %s\n", argv[optind]);
 167                        break;
 168                }
 169        }
 170
 171        if (!perf_mode)
 172                *nb_iterations = 1;
 173}
 174
 175static long
 176read_file(char *file, char **buf)
 177{
 178        FILE *fp;
 179        long buf_len = 0;
 180        size_t read_len;
 181        int res = 0;
 182
 183        fp = fopen(file, "r");
 184        if (!fp)
 185                return -EIO;
 186        if (fseek(fp, 0L, SEEK_END) == 0) {
 187                buf_len = ftell(fp);
 188                if (buf_len == -1) {
 189                        res = EIO;
 190                        goto error;
 191                }
 192                *buf = rte_malloc(NULL, sizeof(char) * (buf_len + 1), 4096);
 193                if (!*buf) {
 194                        res = ENOMEM;
 195                        goto error;
 196                }
 197                if (fseek(fp, 0L, SEEK_SET) != 0) {
 198                        res = EIO;
 199                        goto error;
 200                }
 201                read_len = fread(*buf, sizeof(char), buf_len, fp);
 202                if (read_len != (unsigned long)buf_len) {
 203                        res = EIO;
 204                        goto error;
 205                }
 206        }
 207        fclose(fp);
 208        return buf_len;
 209error:
 210        printf("Error, can't open file %s\n, err = %d", file, res);
 211        if (fp)
 212                fclose(fp);
 213        if (*buf)
 214                rte_free(*buf);
 215        return -res;
 216}
 217
 218static int
 219clone_buf(char *data_buf, char **buf, long data_len)
 220{
 221        char *dest_buf;
 222        dest_buf =
 223                rte_malloc(NULL, sizeof(char) * (data_len + 1), 4096);
 224        if (!dest_buf)
 225                return -ENOMEM;
 226        memcpy(dest_buf, data_buf, data_len + 1);
 227        *buf = dest_buf;
 228        return 0;
 229}
 230
 231static int
 232init_port(uint16_t *nb_max_payload, char *rules_file, uint8_t *nb_max_matches,
 233          uint32_t nb_qps)
 234{
 235        uint16_t id;
 236        uint16_t qp_id;
 237        uint16_t num_devs;
 238        char *rules = NULL;
 239        long rules_len;
 240        struct rte_regexdev_info info;
 241        struct rte_regexdev_config dev_conf = {
 242                .nb_queue_pairs = nb_qps,
 243                .nb_groups = 1,
 244        };
 245        struct rte_regexdev_qp_conf qp_conf = {
 246                .nb_desc = 1024,
 247                .qp_conf_flags = 0,
 248        };
 249        int res = 0;
 250
 251        num_devs = rte_regexdev_count();
 252        if (num_devs == 0) {
 253                printf("Error, no devices detected.\n");
 254                return -EINVAL;
 255        }
 256
 257        rules_len = read_file(rules_file, &rules);
 258        if (rules_len < 0) {
 259                printf("Error, can't read rules files.\n");
 260                res = -EIO;
 261                goto error;
 262        }
 263
 264        for (id = 0; id < num_devs; id++) {
 265                res = rte_regexdev_info_get(id, &info);
 266                if (res != 0) {
 267                        printf("Error, can't get device info.\n");
 268                        goto error;
 269                }
 270                printf(":: initializing dev: %d\n", id);
 271                *nb_max_matches = info.max_matches;
 272                *nb_max_payload = info.max_payload_size;
 273                if (info.regexdev_capa & RTE_REGEXDEV_SUPP_MATCH_AS_END_F)
 274                        dev_conf.dev_cfg_flags |=
 275                        RTE_REGEXDEV_CFG_MATCH_AS_END_F;
 276                dev_conf.nb_max_matches = info.max_matches;
 277                dev_conf.nb_rules_per_group = info.max_rules_per_group;
 278                dev_conf.rule_db_len = rules_len;
 279                dev_conf.rule_db = rules;
 280                res = rte_regexdev_configure(id, &dev_conf);
 281                if (res < 0) {
 282                        printf("Error, can't configure device %d.\n", id);
 283                        goto error;
 284                }
 285                if (info.regexdev_capa & RTE_REGEXDEV_CAPA_QUEUE_PAIR_OOS_F)
 286                        qp_conf.qp_conf_flags |=
 287                        RTE_REGEX_QUEUE_PAIR_CFG_OOS_F;
 288                for (qp_id = 0; qp_id < nb_qps; qp_id++) {
 289                        res = rte_regexdev_queue_pair_setup(id, qp_id,
 290                                                            &qp_conf);
 291                        if (res < 0) {
 292                                printf("Error, can't setup queue pair %u for "
 293                                       "device %d.\n", qp_id, id);
 294                                goto error;
 295                        }
 296                }
 297                printf(":: initializing device: %d done\n", id);
 298        }
 299        rte_free(rules);
 300        return 0;
 301error:
 302        if (rules)
 303                rte_free(rules);
 304        return res;
 305}
 306
 307static void
 308extbuf_free_cb(void *addr __rte_unused, void *fcb_opaque __rte_unused)
 309{
 310}
 311
 312static inline struct rte_mbuf *
 313regex_create_segmented_mbuf(struct rte_mempool *mbuf_pool, int pkt_len,
 314                int nb_segs, void *buf) {
 315
 316        struct rte_mbuf *m = NULL, *mbuf = NULL;
 317        uint8_t *dst;
 318        char *src = buf;
 319        int data_len = 0;
 320        int i, size;
 321        int t_len;
 322
 323        if (pkt_len < 1) {
 324                printf("Packet size must be 1 or more (is %d)\n", pkt_len);
 325                return NULL;
 326        }
 327
 328        if (nb_segs < 1) {
 329                printf("Number of segments must be 1 or more (is %d)\n",
 330                                nb_segs);
 331                return NULL;
 332        }
 333
 334        t_len = pkt_len >= nb_segs ? (pkt_len / nb_segs +
 335                                     !!(pkt_len % nb_segs)) : 1;
 336        size = pkt_len;
 337
 338        /* Create chained mbuf_src and fill it with buf data */
 339        for (i = 0; size > 0; i++) {
 340
 341                m = rte_pktmbuf_alloc(mbuf_pool);
 342                if (i == 0)
 343                        mbuf = m;
 344
 345                if (m == NULL) {
 346                        printf("Cannot create segment for source mbuf");
 347                        goto fail;
 348                }
 349
 350                data_len = size > t_len ? t_len : size;
 351                memset(rte_pktmbuf_mtod(m, uint8_t *), 0,
 352                                rte_pktmbuf_tailroom(m));
 353                memcpy(rte_pktmbuf_mtod(m, uint8_t *), src, data_len);
 354                dst = (uint8_t *)rte_pktmbuf_append(m, data_len);
 355                if (dst == NULL) {
 356                        printf("Cannot append %d bytes to the mbuf\n",
 357                                        data_len);
 358                        goto fail;
 359                }
 360
 361                if (mbuf != m)
 362                        rte_pktmbuf_chain(mbuf, m);
 363                src += data_len;
 364                size -= data_len;
 365
 366        }
 367        return mbuf;
 368
 369fail:
 370        if (mbuf)
 371                rte_pktmbuf_free(mbuf);
 372        return NULL;
 373}
 374
 375static int
 376run_regex(void *args)
 377{
 378        struct regex_conf *rgxc = args;
 379        uint32_t nb_jobs = rgxc->nb_jobs;
 380        uint32_t nb_segs = rgxc->nb_segs;
 381        uint32_t nb_iterations = rgxc->nb_iterations;
 382        uint8_t nb_max_matches = rgxc->nb_max_matches;
 383        uint32_t nb_qps = rgxc->nb_qps;
 384        uint16_t qp_id_base  = rgxc->qp_id_base;
 385        char *data_buf = rgxc->data_buf;
 386        long data_len = rgxc->data_len;
 387        long job_len = rgxc->job_len;
 388
 389        char *buf = NULL;
 390        uint32_t actual_jobs = 0;
 391        uint32_t i;
 392        uint16_t qp_id;
 393        uint16_t dev_id = 0;
 394        uint8_t nb_matches;
 395        struct rte_regexdev_match *match;
 396        long pos;
 397        unsigned long d_ind = 0;
 398        struct rte_mbuf_ext_shared_info shinfo;
 399        int res = 0;
 400        long double time;
 401        struct rte_mempool *mbuf_mp;
 402        struct qp_params *qp;
 403        struct qp_params *qps = NULL;
 404        bool update;
 405        uint16_t qps_used = 0;
 406        char mbuf_pool[16];
 407
 408        shinfo.free_cb = extbuf_free_cb;
 409        snprintf(mbuf_pool,
 410                 sizeof(mbuf_pool),
 411                 "mbuf_pool_%2u", qp_id_base);
 412        mbuf_mp = rte_pktmbuf_pool_create(mbuf_pool,
 413                        rte_align32pow2(nb_jobs * nb_qps * nb_segs),
 414                        0, 0, (nb_segs == 1) ? MBUF_SIZE :
 415                        (rte_align32pow2(job_len) / nb_segs +
 416                        RTE_PKTMBUF_HEADROOM),
 417                        rte_socket_id());
 418        if (mbuf_mp == NULL) {
 419                printf("Error, can't create memory pool\n");
 420                return -ENOMEM;
 421        }
 422
 423        qps = rte_malloc(NULL, sizeof(*qps) * nb_qps, 0);
 424        if (!qps) {
 425                printf("Error, can't allocate memory for QPs\n");
 426                res = -ENOMEM;
 427                goto end;
 428        }
 429
 430        for (qp_id = 0; qp_id < nb_qps; qp_id++) {
 431                struct rte_regex_ops **ops;
 432                struct job_ctx *jobs_ctx;
 433
 434                qps_used++;
 435                qp = &qps[qp_id];
 436                qp->jobs_ctx = NULL;
 437                qp->buf = NULL;
 438                qp->ops = ops = rte_malloc(NULL, sizeof(*ops) * nb_jobs, 0);
 439                if (!ops) {
 440                        printf("Error, can't allocate memory for ops.\n");
 441                        res = -ENOMEM;
 442                        goto end;
 443                }
 444
 445                qp->jobs_ctx = jobs_ctx =
 446                        rte_malloc(NULL, sizeof(*jobs_ctx) * nb_jobs, 0);
 447                if (!jobs_ctx) {
 448                        printf("Error, can't allocate memory for jobs_ctx.\n");
 449                        res = -ENOMEM;
 450                        goto end;
 451                }
 452
 453                if (clone_buf(data_buf, &buf, data_len)) {
 454                        printf("Error, can't clone buf.\n");
 455                        res = -EXIT_FAILURE;
 456                        goto end;
 457                }
 458
 459                /* Assign each mbuf with the data to handle. */
 460                actual_jobs = 0;
 461                pos = 0;
 462                /* Allocate the jobs and assign each job with an mbuf. */
 463                for (i = 0; (pos < data_len) && (i < nb_jobs) ; i++) {
 464                        long act_job_len = RTE_MIN(job_len, data_len - pos);
 465
 466                        ops[i] = rte_malloc(NULL, sizeof(*ops[0]) +
 467                                        nb_max_matches *
 468                                        sizeof(struct rte_regexdev_match), 0);
 469                        if (!ops[i]) {
 470                                printf("Error, can't allocate "
 471                                       "memory for op.\n");
 472                                res = -ENOMEM;
 473                                goto end;
 474                        }
 475                        if (nb_segs > 1) {
 476                                ops[i]->mbuf = regex_create_segmented_mbuf
 477                                                        (mbuf_mp, act_job_len,
 478                                                         nb_segs, &buf[pos]);
 479                        } else {
 480                                ops[i]->mbuf = rte_pktmbuf_alloc(mbuf_mp);
 481                                if (ops[i]->mbuf) {
 482                                        rte_pktmbuf_attach_extbuf(ops[i]->mbuf,
 483                                        &buf[pos], 0, act_job_len, &shinfo);
 484                                        ops[i]->mbuf->data_len = job_len;
 485                                        ops[i]->mbuf->pkt_len = act_job_len;
 486                                }
 487                        }
 488                        if (!ops[i]->mbuf) {
 489                                printf("Error, can't add mbuf.\n");
 490                                res = -ENOMEM;
 491                                goto end;
 492                        }
 493
 494                        jobs_ctx[i].mbuf = ops[i]->mbuf;
 495                        ops[i]->user_id = i;
 496                        ops[i]->group_id0 = 1;
 497                        pos += act_job_len;
 498                        actual_jobs++;
 499                }
 500
 501                qp->buf = buf;
 502                qp->total_matches = 0;
 503                qp->start = 0;
 504                qp->cycles = 0;
 505        }
 506
 507        for (i = 0; i < nb_iterations; i++) {
 508                for (qp_id = 0; qp_id < nb_qps; qp_id++) {
 509                        qp = &qps[qp_id];
 510                        qp->total_enqueue = 0;
 511                        qp->total_dequeue = 0;
 512                }
 513                do {
 514                        update = false;
 515                        for (qp_id = 0; qp_id < nb_qps; qp_id++) {
 516                                qp = &qps[qp_id];
 517                                if (qp->total_dequeue < actual_jobs) {
 518                                        qp->start = rte_rdtsc_precise();
 519                                        struct rte_regex_ops **
 520                                                cur_ops_to_enqueue = qp->ops +
 521                                                qp->total_enqueue;
 522
 523                                        if (actual_jobs - qp->total_enqueue)
 524                                                qp->total_enqueue +=
 525                                                rte_regexdev_enqueue_burst
 526                                                        (dev_id,
 527                                                        qp_id_base + qp_id,
 528                                                        cur_ops_to_enqueue,
 529                                                        actual_jobs -
 530                                                        qp->total_enqueue);
 531                                }
 532                        }
 533                        for (qp_id = 0; qp_id < nb_qps; qp_id++) {
 534                                qp = &qps[qp_id];
 535                                if (qp->total_dequeue < actual_jobs) {
 536                                        struct rte_regex_ops **
 537                                                cur_ops_to_dequeue = qp->ops +
 538                                                qp->total_dequeue;
 539
 540                                        qp->total_dequeue +=
 541                                                rte_regexdev_dequeue_burst
 542                                                        (dev_id,
 543                                                        qp_id_base + qp_id,
 544                                                        cur_ops_to_dequeue,
 545                                                        qp->total_enqueue -
 546                                                        qp->total_dequeue);
 547                                        qp->cycles +=
 548                                             (rte_rdtsc_precise() - qp->start);
 549                                        update = true;
 550                                }
 551                        }
 552                } while (update);
 553        }
 554        for (qp_id = 0; qp_id < nb_qps; qp_id++) {
 555                qp = &qps[qp_id];
 556                time = (long double)qp->cycles / rte_get_timer_hz();
 557                printf("Core=%u QP=%u Job=%ld Bytes Time=%Lf sec Perf=%Lf "
 558                       "Gbps\n", rte_lcore_id(), qp_id + qp_id_base,
 559                       job_len, time,
 560                       (((double)actual_jobs * job_len * nb_iterations * 8)
 561                       / time) / 1000000000.0);
 562        }
 563
 564        if (rgxc->perf_mode)
 565                goto end;
 566        for (qp_id = 0; qp_id < nb_qps; qp_id++) {
 567                printf("\n############ Core=%u QP=%u ############\n",
 568                       rte_lcore_id(), qp_id + qp_id_base);
 569                qp = &qps[qp_id];
 570                /* Log results per job. */
 571                for (d_ind = 0; d_ind < qp->total_dequeue; d_ind++) {
 572                        nb_matches = qp->ops[d_ind % actual_jobs]->nb_matches;
 573                        printf("Job id %"PRIu64" number of matches = %d\n",
 574                                        qp->ops[d_ind]->user_id, nb_matches);
 575                        qp->total_matches += nb_matches;
 576                        match = qp->ops[d_ind % actual_jobs]->matches;
 577                        for (i = 0; i < nb_matches; i++) {
 578                                printf("match %d, rule = %d, "
 579                                       "start = %d,len = %d\n",
 580                                       i, match->rule_id, match->start_offset,
 581                                       match->len);
 582                                match++;
 583                        }
 584                }
 585                printf("Total matches = %d\n", qp->total_matches);
 586                printf("All Matches:\n");
 587                /* Log absolute results. */
 588                for (d_ind = 0; d_ind < qp->total_dequeue; d_ind++) {
 589                        nb_matches = qp->ops[d_ind % actual_jobs]->nb_matches;
 590                        qp->total_matches += nb_matches;
 591                        match = qp->ops[d_ind % actual_jobs]->matches;
 592                        for (i = 0; i < nb_matches; i++) {
 593                                printf("start = %ld, len = %d, rule = %d\n",
 594                                                match->start_offset +
 595                                                d_ind * job_len,
 596                                                match->len, match->rule_id);
 597                                match++;
 598                        }
 599                }
 600        }
 601end:
 602        for (qp_id = 0; qp_id < qps_used; qp_id++) {
 603                qp = &qps[qp_id];
 604                for (i = 0; i < actual_jobs && qp->ops; i++)
 605                        rte_free(qp->ops[i]);
 606                rte_free(qp->ops);
 607                qp->ops = NULL;
 608                for (i = 0; i < actual_jobs && qp->jobs_ctx; i++)
 609                        rte_pktmbuf_free(qp->jobs_ctx[i].mbuf);
 610                rte_free(qp->jobs_ctx);
 611                qp->jobs_ctx = NULL;
 612                rte_free(qp->buf);
 613                qp->buf = NULL;
 614        }
 615        if (mbuf_mp)
 616                rte_mempool_free(mbuf_mp);
 617        rte_free(qps);
 618        return res;
 619}
 620
 621static int
 622distribute_qps_to_lcores(uint32_t nb_cores, uint32_t nb_qps,
 623                         struct qps_per_lcore **qpl)
 624{
 625        int socket;
 626        unsigned lcore_id;
 627        uint32_t i;
 628        uint16_t min_qp_id;
 629        uint16_t max_qp_id;
 630        struct qps_per_lcore *qps_per_lcore;
 631        uint32_t detected_lcores;
 632
 633        if (nb_qps < nb_cores) {
 634                nb_cores = nb_qps;
 635                printf("Reducing number of cores to number of QPs (%u)\n",
 636                       nb_cores);
 637        }
 638        /* Allocate qps_per_lcore array */
 639        qps_per_lcore =
 640                rte_malloc(NULL, sizeof(*qps_per_lcore) * nb_cores, 0);
 641        if (!qps_per_lcore)
 642                rte_exit(EXIT_FAILURE, "Failed to create qps_per_lcore array\n");
 643        *qpl = qps_per_lcore;
 644        detected_lcores = 0;
 645        min_qp_id = 0;
 646
 647        RTE_LCORE_FOREACH_WORKER(lcore_id) {
 648                if (detected_lcores >= nb_cores)
 649                        break;
 650                qps_per_lcore[detected_lcores].lcore_id = lcore_id;
 651                socket = rte_lcore_to_socket_id(lcore_id);
 652                if (socket == SOCKET_ID_ANY)
 653                        socket = 0;
 654                qps_per_lcore[detected_lcores].socket = socket;
 655                qps_per_lcore[detected_lcores].qp_id_base = min_qp_id;
 656                max_qp_id = min_qp_id + nb_qps / nb_cores - 1;
 657                if (nb_qps % nb_cores > detected_lcores)
 658                        max_qp_id++;
 659                qps_per_lcore[detected_lcores].nb_qps = max_qp_id -
 660                                                        min_qp_id + 1;
 661                min_qp_id = max_qp_id + 1;
 662                detected_lcores++;
 663        }
 664        if (detected_lcores != nb_cores)
 665                return -1;
 666
 667        for (i = 0; i < detected_lcores; i++) {
 668                printf("===> Core %d: allocated queues: ",
 669                       qps_per_lcore[i].lcore_id);
 670                min_qp_id = qps_per_lcore[i].qp_id_base;
 671                max_qp_id =
 672                        qps_per_lcore[i].qp_id_base + qps_per_lcore[i].nb_qps;
 673                while (min_qp_id < max_qp_id) {
 674                        printf("%u ", min_qp_id);
 675                        min_qp_id++;
 676                }
 677                printf("\n");
 678        }
 679        return 0;
 680}
 681
 682int
 683main(int argc, char **argv)
 684{
 685        char rules_file[MAX_FILE_NAME];
 686        char data_file[MAX_FILE_NAME];
 687        uint32_t nb_jobs = 0;
 688        bool perf_mode = 0;
 689        uint32_t nb_iterations = 0;
 690        int ret;
 691        uint16_t nb_max_payload = 0;
 692        uint8_t nb_max_matches = 0;
 693        uint32_t nb_qps = 1;
 694        char *data_buf;
 695        long data_len;
 696        long job_len;
 697        uint32_t nb_lcores = 1, nb_segs = 1;
 698        struct regex_conf *rgxc;
 699        uint32_t i;
 700        struct qps_per_lcore *qps_per_lcore;
 701
 702        /* Init EAL. */
 703        ret = rte_eal_init(argc, argv);
 704        if (ret < 0)
 705                rte_exit(EXIT_FAILURE, "EAL init failed\n");
 706        argc -= ret;
 707        argv += ret;
 708        if (argc > 1)
 709                args_parse(argc, argv, rules_file, data_file, &nb_jobs,
 710                                &perf_mode, &nb_iterations, &nb_qps,
 711                                &nb_lcores, &nb_segs);
 712
 713        if (nb_qps == 0)
 714                rte_exit(EXIT_FAILURE, "Number of QPs must be greater than 0\n");
 715        if (nb_lcores == 0)
 716                rte_exit(EXIT_FAILURE, "Number of lcores must be greater than 0\n");
 717        if (distribute_qps_to_lcores(nb_lcores, nb_qps, &qps_per_lcore) < 0)
 718                rte_exit(EXIT_FAILURE, "Failed to distribute queues to lcores!\n");
 719        ret = init_port(&nb_max_payload, rules_file,
 720                        &nb_max_matches, nb_qps);
 721        if (ret < 0)
 722                rte_exit(EXIT_FAILURE, "init port failed\n");
 723
 724        data_len = read_file(data_file, &data_buf);
 725        if (data_len <= 0)
 726                rte_exit(EXIT_FAILURE, "Error, can't read file, or file is empty.\n");
 727
 728        job_len = data_len / nb_jobs;
 729        if (job_len == 0)
 730                rte_exit(EXIT_FAILURE, "Error, To many jobs, for the given input.\n");
 731
 732        if (job_len > nb_max_payload)
 733                rte_exit(EXIT_FAILURE, "Error, not enough jobs to cover input.\n");
 734
 735        rgxc = rte_malloc(NULL, sizeof(*rgxc) * nb_lcores, 0);
 736        if (!rgxc)
 737                rte_exit(EXIT_FAILURE, "Failed to create Regex Conf\n");
 738        for (i = 0; i < nb_lcores; i++) {
 739                rgxc[i] = (struct regex_conf){
 740                        .nb_jobs = nb_jobs,
 741                        .nb_segs = nb_segs,
 742                        .perf_mode = perf_mode,
 743                        .nb_iterations = nb_iterations,
 744                        .nb_max_matches = nb_max_matches,
 745                        .nb_qps = qps_per_lcore[i].nb_qps,
 746                        .qp_id_base = qps_per_lcore[i].qp_id_base,
 747                        .data_buf = data_buf,
 748                        .data_len = data_len,
 749                        .job_len = job_len,
 750                };
 751                rte_eal_remote_launch(run_regex, &rgxc[i],
 752                                      qps_per_lcore[i].lcore_id);
 753        }
 754        rte_eal_mp_wait_lcore();
 755        rte_free(data_buf);
 756        rte_free(rgxc);
 757        rte_free(qps_per_lcore);
 758        return EXIT_SUCCESS;
 759}
 760