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 clone_buf(char *data_buf, char **buf, long data_len)
187 rte_malloc(NULL, sizeof(char) * (data_len + 1), 4096);
190 memcpy(dest_buf, data_buf, data_len + 1);
196 init_port(uint16_t *nb_max_payload, char *rules_file, uint8_t *nb_max_matches,
204 struct rte_regexdev_info info;
205 struct rte_regexdev_config dev_conf = {
206 .nb_queue_pairs = nb_qps,
209 struct rte_regexdev_qp_conf qp_conf = {
215 num_devs = rte_regexdev_count();
217 printf("Error, no devices detected.\n");
221 rules_len = read_file(rules_file, &rules);
223 printf("Error, can't read rules files.\n");
228 for (id = 0; id < num_devs; id++) {
229 res = rte_regexdev_info_get(id, &info);
231 printf("Error, can't get device info.\n");
234 printf(":: initializing dev: %d\n", id);
235 *nb_max_matches = info.max_matches;
236 *nb_max_payload = info.max_payload_size;
237 if (info.regexdev_capa & RTE_REGEXDEV_SUPP_MATCH_AS_END_F)
238 dev_conf.dev_cfg_flags |=
239 RTE_REGEXDEV_CFG_MATCH_AS_END_F;
240 dev_conf.nb_max_matches = info.max_matches;
241 dev_conf.nb_rules_per_group = info.max_rules_per_group;
242 dev_conf.rule_db_len = rules_len;
243 dev_conf.rule_db = rules;
244 res = rte_regexdev_configure(id, &dev_conf);
246 printf("Error, can't configure device %d.\n", id);
249 if (info.regexdev_capa & RTE_REGEXDEV_CAPA_QUEUE_PAIR_OOS_F)
250 qp_conf.qp_conf_flags |=
251 RTE_REGEX_QUEUE_PAIR_CFG_OOS_F;
252 for (qp_id = 0; qp_id < nb_qps; qp_id++) {
253 res = rte_regexdev_queue_pair_setup(id, qp_id,
256 printf("Error, can't setup queue pair %u for "
257 "device %d.\n", qp_id, id);
261 printf(":: initializing device: %d done\n", id);
272 extbuf_free_cb(void *addr __rte_unused, void *fcb_opaque __rte_unused)
277 run_regex(uint32_t nb_jobs,
278 bool perf_mode, uint32_t nb_iterations,
279 uint8_t nb_max_matches, uint32_t nb_qps,
280 char *data_buf, long data_len, long job_len)
283 uint32_t actual_jobs = 0;
288 struct rte_regexdev_match *match;
290 unsigned long d_ind = 0;
291 struct rte_mbuf_ext_shared_info shinfo;
296 struct rte_mempool *mbuf_mp;
297 struct qp_params *qp;
298 struct qp_params *qps = NULL;
300 uint16_t qps_used = 0;
302 shinfo.free_cb = extbuf_free_cb;
303 mbuf_mp = rte_pktmbuf_pool_create("mbuf_pool", nb_jobs * nb_qps, 0,
304 0, MBUF_SIZE, rte_socket_id());
305 if (mbuf_mp == NULL) {
306 printf("Error, can't create memory pool\n");
310 qps = rte_malloc(NULL, sizeof(*qps) * nb_qps, 0);
312 printf("Error, can't allocate memory for QPs\n");
317 for (qp_id = 0; qp_id < nb_qps; qp_id++) {
318 struct rte_regex_ops **ops;
319 struct job_ctx *jobs_ctx;
325 qp->ops = ops = rte_malloc(NULL, sizeof(*ops) * nb_jobs, 0);
327 printf("Error, can't allocate memory for ops.\n");
332 qp->jobs_ctx = jobs_ctx =
333 rte_malloc(NULL, sizeof(*jobs_ctx) * nb_jobs, 0);
335 printf("Error, can't allocate memory for jobs_ctx.\n");
340 /* Allocate the jobs and assign each job with an mbuf. */
341 for (i = 0; i < nb_jobs; i++) {
342 ops[i] = rte_malloc(NULL, sizeof(*ops[0]) +
344 sizeof(struct rte_regexdev_match), 0);
346 printf("Error, can't allocate "
351 ops[i]->mbuf = rte_pktmbuf_alloc(mbuf_mp);
353 printf("Error, can't attach mbuf.\n");
359 if (clone_buf(data_buf, &buf, data_len)) {
360 printf("Error, can't clone buf.\n");
365 /* Assign each mbuf with the data to handle. */
368 for (i = 0; (pos < data_len) && (i < nb_jobs) ; i++) {
369 long act_job_len = RTE_MIN(job_len, data_len - pos);
370 rte_pktmbuf_attach_extbuf(ops[i]->mbuf, &buf[pos], 0,
371 act_job_len, &shinfo);
372 jobs_ctx[i].mbuf = ops[i]->mbuf;
373 ops[i]->mbuf->data_len = job_len;
374 ops[i]->mbuf->pkt_len = act_job_len;
376 ops[i]->group_id0 = 1;
382 qp->total_matches = 0;
386 for (i = 0; i < nb_iterations; i++) {
387 for (qp_id = 0; qp_id < nb_qps; qp_id++) {
389 qp->total_enqueue = 0;
390 qp->total_dequeue = 0;
394 for (qp_id = 0; qp_id < nb_qps; qp_id++) {
396 if (qp->total_dequeue < actual_jobs) {
397 struct rte_regex_ops **
398 cur_ops_to_enqueue = qp->ops +
401 if (actual_jobs - qp->total_enqueue)
403 rte_regexdev_enqueue_burst
411 for (qp_id = 0; qp_id < nb_qps; qp_id++) {
413 if (qp->total_dequeue < actual_jobs) {
414 struct rte_regex_ops **
415 cur_ops_to_dequeue = qp->ops +
419 rte_regexdev_dequeue_burst
431 time = ((double)end - start) / CLOCKS_PER_SEC;
432 printf("Job len = %ld Bytes\n", job_len);
433 printf("Time = %lf sec\n", time);
434 printf("Perf = %lf Gbps\n",
435 (((double)actual_jobs * job_len * nb_iterations * 8) / time) /
440 for (qp_id = 0; qp_id < nb_qps; qp_id++) {
441 printf("\n############ QP id=%u ############\n", qp_id);
443 /* Log results per job. */
444 for (d_ind = 0; d_ind < qp->total_dequeue; d_ind++) {
445 nb_matches = qp->ops[d_ind % actual_jobs]->nb_matches;
446 printf("Job id %"PRIu64" number of matches = %d\n",
447 qp->ops[d_ind]->user_id, nb_matches);
448 qp->total_matches += nb_matches;
449 match = qp->ops[d_ind % actual_jobs]->matches;
450 for (i = 0; i < nb_matches; i++) {
451 printf("match %d, rule = %d, "
452 "start = %d,len = %d\n",
453 i, match->rule_id, match->start_offset,
458 printf("Total matches = %d\n", qp->total_matches);
459 printf("All Matches:\n");
460 /* Log absolute results. */
461 for (d_ind = 0; d_ind < qp->total_dequeue; d_ind++) {
462 nb_matches = qp->ops[d_ind % actual_jobs]->nb_matches;
463 qp->total_matches += nb_matches;
464 match = qp->ops[d_ind % actual_jobs]->matches;
465 for (i = 0; i < nb_matches; i++) {
466 printf("start = %ld, len = %d, rule = %d\n",
467 match->start_offset +
469 match->len, match->rule_id);
475 for (qp_id = 0; qp_id < qps_used; qp_id++) {
477 for (i = 0; i < actual_jobs && qp->ops; i++)
478 rte_free(qp->ops[i]);
481 for (i = 0; i < actual_jobs && qp->jobs_ctx; i++)
482 rte_pktmbuf_free(qp->jobs_ctx[i].mbuf);
483 rte_free(qp->jobs_ctx);
489 rte_mempool_free(mbuf_mp);
495 main(int argc, char **argv)
497 char rules_file[MAX_FILE_NAME];
498 char data_file[MAX_FILE_NAME];
499 uint32_t nb_jobs = 0;
501 uint32_t nb_iterations = 0;
503 uint16_t nb_max_payload = 0;
504 uint8_t nb_max_matches = 0;
511 ret = rte_eal_init(argc, argv);
513 rte_exit(EXIT_FAILURE, "EAL init failed\n");
517 args_parse(argc, argv, rules_file, data_file, &nb_jobs,
518 &perf_mode, &nb_iterations, &nb_qps);
521 rte_exit(EXIT_FAILURE, "Number of QPs must be greater than 0\n");
522 ret = init_port(&nb_max_payload, rules_file,
523 &nb_max_matches, nb_qps);
525 rte_exit(EXIT_FAILURE, "init port failed\n");
527 data_len = read_file(data_file, &data_buf);
529 rte_exit(EXIT_FAILURE, "Error, can't read file, or file is empty.\n");
531 job_len = data_len / nb_jobs;
533 rte_exit(EXIT_FAILURE, "Error, To many jobs, for the given input.\n");
535 if (job_len > nb_max_payload)
536 rte_exit(EXIT_FAILURE, "Error, not enough jobs to cover input.\n");
538 ret = run_regex(nb_jobs, perf_mode,
539 nb_iterations, nb_max_matches, nb_qps,
540 data_buf, data_len, job_len);
542 rte_exit(EXIT_FAILURE, "RegEx function failed\n");