1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2020 Mellanox Technologies, Ltd
17 #include <rte_common.h>
18 #include <rte_malloc.h>
19 #include <rte_mempool.h>
21 #include <rte_cycles.h>
22 #include <rte_regexdev.h>
24 #define MAX_FILE_NAME 255
25 #define MBUF_CACHE_SIZE 256
26 #define MBUF_SIZE (1 << 8)
27 #define START_BURST_SIZE 32u
35 ARG_NUM_OF_ITERATIONS,
40 struct rte_mbuf *mbuf;
44 uint32_t total_enqueue;
45 uint32_t total_dequeue;
46 uint32_t total_matches;
47 struct rte_regex_ops **ops;
48 struct job_ctx *jobs_ctx;
53 usage(const char *prog_name)
55 printf("%s [EAL options] --\n"
56 " --rules NAME: precompiled rules file\n"
57 " --data NAME: data file to use\n"
58 " --nb_jobs: number of jobs to use\n"
59 " --perf N: only outputs the performance data\n"
60 " --nb_iter N: number of iteration to run\n"
61 " --nb_qps N: number of queues to use\n",
66 args_parse(int argc, char **argv, char *rules_file, char *data_file,
67 uint32_t *nb_jobs, bool *perf_mode, uint32_t *nb_iterations,
74 static struct option lgopts[] = {
75 { "help", 0, 0, ARG_HELP},
76 /* Rules database file to load. */
77 { "rules", 1, 0, ARG_RULES_FILE_NAME},
78 /* Data file to load. */
79 { "data", 1, 0, ARG_DATA_FILE_NAME},
80 /* Number of jobs to create. */
81 { "nb_jobs", 1, 0, ARG_NUM_OF_JOBS},
83 { "perf", 0, 0, ARG_PERF_MODE},
84 /* Number of iterations to run with perf test */
85 { "nb_iter", 1, 0, ARG_NUM_OF_ITERATIONS},
87 { "nb_qps", 1, 0, ARG_NUM_OF_QPS},
93 while ((opt = getopt_long(argc, argvopt, "",
94 lgopts, &opt_idx)) != EOF) {
96 case ARG_RULES_FILE_NAME:
97 len = strnlen(optarg, MAX_FILE_NAME - 1);
98 if (len == MAX_FILE_NAME)
99 rte_exit(EXIT_FAILURE,
100 "Rule file name to long max %d\n",
102 strncpy(rules_file, optarg, MAX_FILE_NAME - 1);
104 case ARG_DATA_FILE_NAME:
105 len = strnlen(optarg, MAX_FILE_NAME - 1);
106 if (len == MAX_FILE_NAME)
107 rte_exit(EXIT_FAILURE,
108 "Data file name to long max %d\n",
110 strncpy(data_file, optarg, MAX_FILE_NAME - 1);
112 case ARG_NUM_OF_JOBS:
113 *nb_jobs = atoi(optarg);
118 case ARG_NUM_OF_ITERATIONS:
119 *nb_iterations = atoi(optarg);
122 *nb_qps = atoi(optarg);
125 usage("RegEx test app");
128 fprintf(stderr, "Invalid option: %s\n", argv[optind]);
129 usage("RegEx test app");
130 rte_exit(EXIT_FAILURE, "Invalid option\n");
140 read_file(char *file, char **buf)
147 fp = fopen(file, "r");
150 if (fseek(fp, 0L, SEEK_END) == 0) {
156 *buf = rte_malloc(NULL, sizeof(char) * (buf_len + 1), 4096);
161 if (fseek(fp, 0L, SEEK_SET) != 0) {
165 read_len = fread(*buf, sizeof(char), buf_len, fp);
166 if (read_len != (unsigned long)buf_len) {
174 printf("Error, can't open file %s\n, err = %d", file, res);
183 init_port(uint16_t *nb_max_payload, char *rules_file, uint8_t *nb_max_matches,
191 struct rte_regexdev_info info;
192 struct rte_regexdev_config dev_conf = {
193 .nb_queue_pairs = nb_qps,
196 struct rte_regexdev_qp_conf qp_conf = {
202 num_devs = rte_regexdev_count();
204 printf("Error, no devices detected.\n");
208 rules_len = read_file(rules_file, &rules);
210 printf("Error, can't read rules files.\n");
215 for (id = 0; id < num_devs; id++) {
216 res = rte_regexdev_info_get(id, &info);
218 printf("Error, can't get device info.\n");
221 printf(":: initializing dev: %d\n", id);
222 *nb_max_matches = info.max_matches;
223 *nb_max_payload = info.max_payload_size;
224 if (info.regexdev_capa & RTE_REGEXDEV_SUPP_MATCH_AS_END_F)
225 dev_conf.dev_cfg_flags |=
226 RTE_REGEXDEV_CFG_MATCH_AS_END_F;
227 dev_conf.nb_max_matches = info.max_matches;
228 dev_conf.nb_rules_per_group = info.max_rules_per_group;
229 dev_conf.rule_db_len = rules_len;
230 dev_conf.rule_db = rules;
231 res = rte_regexdev_configure(id, &dev_conf);
233 printf("Error, can't configure device %d.\n", id);
236 if (info.regexdev_capa & RTE_REGEXDEV_CAPA_QUEUE_PAIR_OOS_F)
237 qp_conf.qp_conf_flags |=
238 RTE_REGEX_QUEUE_PAIR_CFG_OOS_F;
239 for (qp_id = 0; qp_id < nb_qps; qp_id++) {
240 res = rte_regexdev_queue_pair_setup(id, qp_id,
243 printf("Error, can't setup queue pair %u for "
244 "device %d.\n", qp_id, id);
248 printf(":: initializing device: %d done\n", id);
259 extbuf_free_cb(void *addr __rte_unused, void *fcb_opaque __rte_unused)
264 run_regex(uint32_t nb_jobs,
265 uint16_t nb_max_payload, bool perf_mode, uint32_t nb_iterations,
266 char *data_file, uint8_t nb_max_matches, uint32_t nb_qps)
271 uint32_t actual_jobs = 0;
276 struct rte_regexdev_match *match;
278 unsigned long d_ind = 0;
279 struct rte_mbuf_ext_shared_info shinfo;
284 struct rte_mempool *mbuf_mp;
285 struct qp_params *qp;
286 struct qp_params *qps = NULL;
288 uint16_t qps_used = 0;
290 shinfo.free_cb = extbuf_free_cb;
291 mbuf_mp = rte_pktmbuf_pool_create("mbuf_pool", nb_jobs * nb_qps, 0,
292 0, MBUF_SIZE, rte_socket_id());
293 if (mbuf_mp == NULL) {
294 printf("Error, can't create memory pool\n");
298 qps = rte_malloc(NULL, sizeof(*qps) * nb_qps, 0);
300 printf("Error, can't allocate memory for QPs\n");
305 for (qp_id = 0; qp_id < nb_qps; qp_id++) {
306 struct rte_regex_ops **ops;
307 struct job_ctx *jobs_ctx;
313 qp->ops = ops = rte_malloc(NULL, sizeof(*ops) * nb_jobs, 0);
315 printf("Error, can't allocate memory for ops.\n");
320 qp->jobs_ctx = jobs_ctx =
321 rte_malloc(NULL, sizeof(*jobs_ctx) * nb_jobs, 0);
323 printf("Error, can't allocate memory for jobs_ctx.\n");
328 /* Allocate the jobs and assign each job with an mbuf. */
329 for (i = 0; i < nb_jobs; i++) {
330 ops[i] = rte_malloc(NULL, sizeof(*ops[0]) +
332 sizeof(struct rte_regexdev_match), 0);
334 printf("Error, can't allocate "
339 ops[i]->mbuf = rte_pktmbuf_alloc(mbuf_mp);
341 printf("Error, can't attach mbuf.\n");
347 buf_len = read_file(data_file, &buf);
349 printf("Error, can't read file, or file is empty.\n");
354 job_len = buf_len / nb_jobs;
356 printf("Error, To many jobs, for the given input.\n");
361 if (job_len > nb_max_payload) {
362 printf("Error, not enough jobs to cover input.\n");
367 /* Assign each mbuf with the data to handle. */
370 for (i = 0; (pos < buf_len) && (i < nb_jobs) ; i++) {
371 long act_job_len = RTE_MIN(job_len, buf_len - pos);
372 rte_pktmbuf_attach_extbuf(ops[i]->mbuf, &buf[pos], 0,
373 act_job_len, &shinfo);
374 jobs_ctx[i].mbuf = ops[i]->mbuf;
375 ops[i]->mbuf->data_len = job_len;
376 ops[i]->mbuf->pkt_len = act_job_len;
378 ops[i]->group_id0 = 1;
384 qp->total_matches = 0;
388 for (i = 0; i < nb_iterations; i++) {
389 for (qp_id = 0; qp_id < nb_qps; qp_id++) {
391 qp->total_enqueue = 0;
392 qp->total_dequeue = 0;
396 for (qp_id = 0; qp_id < nb_qps; qp_id++) {
398 if (qp->total_dequeue < actual_jobs) {
399 struct rte_regex_ops **
400 cur_ops_to_enqueue = qp->ops +
403 if (actual_jobs - qp->total_enqueue)
405 rte_regexdev_enqueue_burst
413 for (qp_id = 0; qp_id < nb_qps; qp_id++) {
415 if (qp->total_dequeue < actual_jobs) {
416 struct rte_regex_ops **
417 cur_ops_to_dequeue = qp->ops +
421 rte_regexdev_dequeue_burst
433 time = ((double)end - start) / CLOCKS_PER_SEC;
434 printf("Job len = %ld Bytes\n", job_len);
435 printf("Time = %lf sec\n", time);
436 printf("Perf = %lf Gbps\n",
437 (((double)actual_jobs * job_len * nb_iterations * 8) / time) /
442 for (qp_id = 0; qp_id < nb_qps; qp_id++) {
443 printf("\n############ QP id=%u ############\n", qp_id);
445 /* Log results per job. */
446 for (d_ind = 0; d_ind < qp->total_dequeue; d_ind++) {
447 nb_matches = qp->ops[d_ind % actual_jobs]->nb_matches;
448 printf("Job id %"PRIu64" number of matches = %d\n",
449 qp->ops[d_ind]->user_id, nb_matches);
450 qp->total_matches += nb_matches;
451 match = qp->ops[d_ind % actual_jobs]->matches;
452 for (i = 0; i < nb_matches; i++) {
453 printf("match %d, rule = %d, "
454 "start = %d,len = %d\n",
455 i, match->rule_id, match->start_offset,
460 printf("Total matches = %d\n", qp->total_matches);
461 printf("All Matches:\n");
462 /* Log absolute results. */
463 for (d_ind = 0; d_ind < qp->total_dequeue; d_ind++) {
464 nb_matches = qp->ops[d_ind % actual_jobs]->nb_matches;
465 qp->total_matches += nb_matches;
466 match = qp->ops[d_ind % actual_jobs]->matches;
467 for (i = 0; i < nb_matches; i++) {
468 printf("start = %ld, len = %d, rule = %d\n",
469 match->start_offset +
471 match->len, match->rule_id);
477 for (qp_id = 0; qp_id < qps_used; qp_id++) {
479 for (i = 0; i < actual_jobs && qp->ops; i++)
480 rte_free(qp->ops[i]);
483 for (i = 0; i < actual_jobs && qp->jobs_ctx; i++)
484 rte_pktmbuf_free(qp->jobs_ctx[i].mbuf);
485 rte_free(qp->jobs_ctx);
491 rte_mempool_free(mbuf_mp);
497 main(int argc, char **argv)
499 char rules_file[MAX_FILE_NAME];
500 char data_file[MAX_FILE_NAME];
501 uint32_t nb_jobs = 0;
503 uint32_t nb_iterations = 0;
505 uint16_t nb_max_payload = 0;
506 uint8_t nb_max_matches = 0;
510 ret = rte_eal_init(argc, argv);
512 rte_exit(EXIT_FAILURE, "EAL init failed\n");
516 args_parse(argc, argv, rules_file, data_file, &nb_jobs,
517 &perf_mode, &nb_iterations, &nb_qps);
520 rte_exit(EXIT_FAILURE, "Number of QPs must be greater than 0\n");
521 ret = init_port(&nb_max_payload, rules_file,
522 &nb_max_matches, nb_qps);
524 rte_exit(EXIT_FAILURE, "init port failed\n");
525 ret = run_regex(nb_jobs, nb_max_payload, perf_mode,
526 nb_iterations, data_file, nb_max_matches, nb_qps);
528 rte_exit(EXIT_FAILURE, "RegEx function failed\n");