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