X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=app%2Ftest-regex%2Fmain.c;h=7c014b2210ca48da9e6d856d17ce784ffff45ffe;hb=a538d1d2d01e85429e7dd011806b52250d37c5dc;hp=9bafd0227f29a31743c23e938af002ef4f398dc5;hpb=f5cffb7eb7fb6c2ddcfcc706c52faf538522eab7;p=dpdk.git diff --git a/app/test-regex/main.c b/app/test-regex/main.c index 9bafd0227f..7c014b2210 100644 --- a/app/test-regex/main.c +++ b/app/test-regex/main.c @@ -34,6 +34,8 @@ enum app_args { ARG_PERF_MODE, ARG_NUM_OF_ITERATIONS, ARG_NUM_OF_QPS, + ARG_NUM_OF_LCORES, + ARG_NUM_OF_MBUF_SEGS, }; struct job_ctx { @@ -47,6 +49,29 @@ struct qp_params { struct rte_regex_ops **ops; struct job_ctx *jobs_ctx; char *buf; + uint64_t start; + uint64_t cycles; +}; + +struct qps_per_lcore { + unsigned int lcore_id; + int socket; + uint16_t qp_id_base; + uint16_t nb_qps; +}; + +struct regex_conf { + uint32_t nb_jobs; + bool perf_mode; + uint32_t nb_iterations; + char *data_file; + uint8_t nb_max_matches; + uint32_t nb_qps; + uint16_t qp_id_base; + char *data_buf; + long data_len; + long job_len; + uint32_t nb_segs; }; static void @@ -58,14 +83,16 @@ usage(const char *prog_name) " --nb_jobs: number of jobs to use\n" " --perf N: only outputs the performance data\n" " --nb_iter N: number of iteration to run\n" - " --nb_qps N: number of queues to use\n", + " --nb_qps N: number of queues to use\n" + " --nb_lcores N: number of lcores to use\n" + " --nb_segs N: number of mbuf segments\n", prog_name); } static void args_parse(int argc, char **argv, char *rules_file, char *data_file, uint32_t *nb_jobs, bool *perf_mode, uint32_t *nb_iterations, - uint32_t *nb_qps) + uint32_t *nb_qps, uint32_t *nb_lcores, uint32_t *nb_segs) { char **argvopt; int opt; @@ -85,6 +112,10 @@ args_parse(int argc, char **argv, char *rules_file, char *data_file, { "nb_iter", 1, 0, ARG_NUM_OF_ITERATIONS}, /* Number of QPs. */ { "nb_qps", 1, 0, ARG_NUM_OF_QPS}, + /* Number of lcores. */ + { "nb_lcores", 1, 0, ARG_NUM_OF_LCORES}, + /* Number of mbuf segments. */ + { "nb_segs", 1, 0, ARG_NUM_OF_MBUF_SEGS}, /* End of options */ { 0, 0, 0, 0 } }; @@ -121,13 +152,18 @@ args_parse(int argc, char **argv, char *rules_file, char *data_file, case ARG_NUM_OF_QPS: *nb_qps = atoi(optarg); break; + case ARG_NUM_OF_LCORES: + *nb_lcores = atoi(optarg); + break; + case ARG_NUM_OF_MBUF_SEGS: + *nb_segs = atoi(optarg); + break; case ARG_HELP: - usage("RegEx test app"); + usage(argv[0]); break; default: - fprintf(stderr, "Invalid option: %s\n", argv[optind]); - usage("RegEx test app"); - rte_exit(EXIT_FAILURE, "Invalid option\n"); + usage(argv[0]); + rte_exit(EXIT_FAILURE, "Invalid option: %s\n", argv[optind]); break; } } @@ -174,8 +210,7 @@ error: printf("Error, can't open file %s\n, err = %d", file, res); if (fp) fclose(fp); - if (*buf) - rte_free(*buf); + rte_free(*buf); return -res; } @@ -263,8 +298,7 @@ init_port(uint16_t *nb_max_payload, char *rules_file, uint8_t *nb_max_matches, rte_free(rules); return 0; error: - if (rules) - rte_free(rules); + rte_free(rules); return res; } @@ -273,15 +307,88 @@ extbuf_free_cb(void *addr __rte_unused, void *fcb_opaque __rte_unused) { } +static inline struct rte_mbuf * +regex_create_segmented_mbuf(struct rte_mempool *mbuf_pool, int pkt_len, + int nb_segs, void *buf) { + + struct rte_mbuf *m = NULL, *mbuf = NULL; + uint8_t *dst; + char *src = buf; + int data_len = 0; + int i, size; + int t_len; + + if (pkt_len < 1) { + printf("Packet size must be 1 or more (is %d)\n", pkt_len); + return NULL; + } + + if (nb_segs < 1) { + printf("Number of segments must be 1 or more (is %d)\n", + nb_segs); + return NULL; + } + + t_len = pkt_len >= nb_segs ? (pkt_len / nb_segs + + !!(pkt_len % nb_segs)) : 1; + size = pkt_len; + + /* Create chained mbuf_src and fill it with buf data */ + for (i = 0; size > 0; i++) { + + m = rte_pktmbuf_alloc(mbuf_pool); + if (i == 0) + mbuf = m; + + if (m == NULL) { + printf("Cannot create segment for source mbuf"); + goto fail; + } + + data_len = size > t_len ? t_len : size; + memset(rte_pktmbuf_mtod(m, uint8_t *), 0, + rte_pktmbuf_tailroom(m)); + memcpy(rte_pktmbuf_mtod(m, uint8_t *), src, data_len); + dst = (uint8_t *)rte_pktmbuf_append(m, data_len); + if (dst == NULL) { + printf("Cannot append %d bytes to the mbuf\n", + data_len); + goto fail; + } + + if (mbuf != m) + rte_pktmbuf_chain(mbuf, m); + src += data_len; + size -= data_len; + + } + return mbuf; + +fail: + rte_pktmbuf_free(mbuf); + return NULL; +} + static int -run_regex(uint32_t nb_jobs, - bool perf_mode, uint32_t nb_iterations, - uint8_t nb_max_matches, uint32_t nb_qps, - char *data_buf, long data_len, long job_len) +run_regex(void *args) { + struct regex_conf *rgxc = args; + uint32_t nb_jobs = rgxc->nb_jobs; + uint32_t nb_segs = rgxc->nb_segs; + uint32_t nb_iterations = rgxc->nb_iterations; + uint8_t nb_max_matches = rgxc->nb_max_matches; + uint32_t nb_qps = rgxc->nb_qps; + uint16_t qp_id_base = rgxc->qp_id_base; + char *data_buf = rgxc->data_buf; + long data_len = rgxc->data_len; + long job_len = rgxc->job_len; + long remainder; + long act_job_len = 0; + bool last_job = false; char *buf = NULL; uint32_t actual_jobs = 0; uint32_t i; + uint32_t job_id; uint16_t qp_id; uint16_t dev_id = 0; uint8_t nb_matches; @@ -290,18 +397,24 @@ run_regex(uint32_t nb_jobs, unsigned long d_ind = 0; struct rte_mbuf_ext_shared_info shinfo; int res = 0; - time_t start; - time_t end; - double time; + long double time; struct rte_mempool *mbuf_mp; struct qp_params *qp; struct qp_params *qps = NULL; bool update; uint16_t qps_used = 0; + char mbuf_pool[16]; shinfo.free_cb = extbuf_free_cb; - mbuf_mp = rte_pktmbuf_pool_create("mbuf_pool", nb_jobs * nb_qps, 0, - 0, MBUF_SIZE, rte_socket_id()); + snprintf(mbuf_pool, + sizeof(mbuf_pool), + "mbuf_pool_%2u", qp_id_base); + mbuf_mp = rte_pktmbuf_pool_create(mbuf_pool, + rte_align32pow2(nb_jobs * nb_qps * nb_segs), + 0, 0, (nb_segs == 1) ? MBUF_SIZE : + (rte_align32pow2(job_len) / nb_segs + + RTE_PKTMBUF_HEADROOM), + rte_socket_id()); if (mbuf_mp == NULL) { printf("Error, can't create memory pool\n"); return -ENOMEM; @@ -337,8 +450,26 @@ run_regex(uint32_t nb_jobs, goto end; } + if (clone_buf(data_buf, &buf, data_len)) { + printf("Error, can't clone buf.\n"); + res = -EXIT_FAILURE; + goto end; + } + + /* Assign each mbuf with the data to handle. */ + actual_jobs = 0; + pos = 0; + remainder = data_len % nb_jobs; + /* Allocate the jobs and assign each job with an mbuf. */ - for (i = 0; i < nb_jobs; i++) { + for (i = 0; (pos < data_len) && (i < nb_jobs) ; i++) { + act_job_len = RTE_MIN(job_len, data_len - pos); + + if (i == (nb_jobs - 1)) { + last_job = true; + act_job_len += remainder; + } + ops[i] = rte_malloc(NULL, sizeof(*ops[0]) + nb_max_matches * sizeof(struct rte_regexdev_match), 0); @@ -348,30 +479,31 @@ run_regex(uint32_t nb_jobs, res = -ENOMEM; goto end; } - ops[i]->mbuf = rte_pktmbuf_alloc(mbuf_mp); + if (nb_segs > 1) { + ops[i]->mbuf = regex_create_segmented_mbuf + (mbuf_mp, act_job_len, + nb_segs, &buf[pos]); + } else { + ops[i]->mbuf = rte_pktmbuf_alloc(mbuf_mp); + if (ops[i]->mbuf) { + rte_pktmbuf_attach_extbuf(ops[i]->mbuf, + &buf[pos], 0, act_job_len, &shinfo); + + if (!last_job) + ops[i]->mbuf->data_len = job_len; + else + ops[i]->mbuf->data_len = act_job_len; + + ops[i]->mbuf->pkt_len = act_job_len; + } + } if (!ops[i]->mbuf) { - printf("Error, can't attach mbuf.\n"); + printf("Error, can't add mbuf.\n"); res = -ENOMEM; goto end; } - } - if (clone_buf(data_buf, &buf, data_len)) { - printf("Error, can't clone buf.\n"); - res = -EXIT_FAILURE; - goto end; - } - - /* Assign each mbuf with the data to handle. */ - actual_jobs = 0; - pos = 0; - for (i = 0; (pos < data_len) && (i < nb_jobs) ; i++) { - long act_job_len = RTE_MIN(job_len, data_len - pos); - rte_pktmbuf_attach_extbuf(ops[i]->mbuf, &buf[pos], 0, - act_job_len, &shinfo); jobs_ctx[i].mbuf = ops[i]->mbuf; - ops[i]->mbuf->data_len = job_len; - ops[i]->mbuf->pkt_len = act_job_len; ops[i]->user_id = i; ops[i]->group_id0 = 1; pos += act_job_len; @@ -380,20 +512,25 @@ run_regex(uint32_t nb_jobs, qp->buf = buf; qp->total_matches = 0; + qp->start = 0; + qp->cycles = 0; } - start = clock(); for (i = 0; i < nb_iterations; i++) { for (qp_id = 0; qp_id < nb_qps; qp_id++) { qp = &qps[qp_id]; qp->total_enqueue = 0; qp->total_dequeue = 0; + /* Re-set user id after dequeue to match data in mbuf. */ + for (job_id = 0 ; job_id < nb_jobs; job_id++) + qp->ops[job_id]->user_id = job_id; } do { update = false; for (qp_id = 0; qp_id < nb_qps; qp_id++) { qp = &qps[qp_id]; if (qp->total_dequeue < actual_jobs) { + qp->start = rte_rdtsc_precise(); struct rte_regex_ops ** cur_ops_to_enqueue = qp->ops + qp->total_enqueue; @@ -402,7 +539,7 @@ run_regex(uint32_t nb_jobs, qp->total_enqueue += rte_regexdev_enqueue_burst (dev_id, - qp_id, + qp_id_base + qp_id, cur_ops_to_enqueue, actual_jobs - qp->total_enqueue); @@ -418,27 +555,32 @@ run_regex(uint32_t nb_jobs, qp->total_dequeue += rte_regexdev_dequeue_burst (dev_id, - qp_id, + qp_id_base + qp_id, cur_ops_to_dequeue, qp->total_enqueue - qp->total_dequeue); + qp->cycles += + (rte_rdtsc_precise() - qp->start); update = true; } } } while (update); } - end = clock(); - time = ((double)end - start) / CLOCKS_PER_SEC; - printf("Job len = %ld Bytes\n", job_len); - printf("Time = %lf sec\n", time); - printf("Perf = %lf Gbps\n", - (((double)actual_jobs * job_len * nb_iterations * 8) / time) / - 1000000000.0); - - if (perf_mode) + for (qp_id = 0; qp_id < nb_qps; qp_id++) { + qp = &qps[qp_id]; + time = (long double)qp->cycles / rte_get_timer_hz(); + printf("Core=%u QP=%u Job=%ld Bytes Last Job=%ld Bytes Time=%Lf sec Perf=%Lf " + "Gbps\n", rte_lcore_id(), qp_id + qp_id_base, + job_len, act_job_len, time, + (((double)data_len * nb_iterations * 8) + / time) / 1000000000.0); + } + + if (rgxc->perf_mode) goto end; for (qp_id = 0; qp_id < nb_qps; qp_id++) { - printf("\n############ QP id=%u ############\n", qp_id); + printf("\n############ Core=%u QP=%u ############\n", + rte_lcore_id(), qp_id + qp_id_base); qp = &qps[qp_id]; /* Log results per job. */ for (d_ind = 0; d_ind < qp->total_dequeue; d_ind++) { @@ -463,10 +605,10 @@ run_regex(uint32_t nb_jobs, qp->total_matches += nb_matches; match = qp->ops[d_ind % actual_jobs]->matches; for (i = 0; i < nb_matches; i++) { - printf("start = %ld, len = %d, rule = %d\n", - match->start_offset + - d_ind * job_len, - match->len, match->rule_id); + printf("start = %d, len = %d, rule = %d\n", + match->start_offset + + (int)(qp->ops[d_ind % actual_jobs]->user_id * job_len), + match->len, match->rule_id); match++; } } @@ -485,12 +627,72 @@ end: rte_free(qp->buf); qp->buf = NULL; } - if (mbuf_mp) - rte_mempool_free(mbuf_mp); + rte_mempool_free(mbuf_mp); rte_free(qps); return res; } +static int +distribute_qps_to_lcores(uint32_t nb_cores, uint32_t nb_qps, + struct qps_per_lcore **qpl) +{ + int socket; + unsigned lcore_id; + uint32_t i; + uint16_t min_qp_id; + uint16_t max_qp_id; + struct qps_per_lcore *qps_per_lcore; + uint32_t detected_lcores; + + if (nb_qps < nb_cores) { + nb_cores = nb_qps; + printf("Reducing number of cores to number of QPs (%u)\n", + nb_cores); + } + /* Allocate qps_per_lcore array */ + qps_per_lcore = + rte_malloc(NULL, sizeof(*qps_per_lcore) * nb_cores, 0); + if (!qps_per_lcore) + rte_exit(EXIT_FAILURE, "Failed to create qps_per_lcore array\n"); + *qpl = qps_per_lcore; + detected_lcores = 0; + min_qp_id = 0; + + RTE_LCORE_FOREACH_WORKER(lcore_id) { + if (detected_lcores >= nb_cores) + break; + qps_per_lcore[detected_lcores].lcore_id = lcore_id; + socket = rte_lcore_to_socket_id(lcore_id); + if (socket == SOCKET_ID_ANY) + socket = 0; + qps_per_lcore[detected_lcores].socket = socket; + qps_per_lcore[detected_lcores].qp_id_base = min_qp_id; + max_qp_id = min_qp_id + nb_qps / nb_cores - 1; + if (nb_qps % nb_cores > detected_lcores) + max_qp_id++; + qps_per_lcore[detected_lcores].nb_qps = max_qp_id - + min_qp_id + 1; + min_qp_id = max_qp_id + 1; + detected_lcores++; + } + if (detected_lcores != nb_cores) + return -1; + + for (i = 0; i < detected_lcores; i++) { + printf("===> Core %d: allocated queues: ", + qps_per_lcore[i].lcore_id); + min_qp_id = qps_per_lcore[i].qp_id_base; + max_qp_id = + qps_per_lcore[i].qp_id_base + qps_per_lcore[i].nb_qps; + while (min_qp_id < max_qp_id) { + printf("%u ", min_qp_id); + min_qp_id++; + } + printf("\n"); + } + return 0; +} + int main(int argc, char **argv) { @@ -506,6 +708,10 @@ main(int argc, char **argv) char *data_buf; long data_len; long job_len; + uint32_t nb_lcores = 1, nb_segs = 1; + struct regex_conf *rgxc; + uint32_t i; + struct qps_per_lcore *qps_per_lcore; /* Init EAL. */ ret = rte_eal_init(argc, argv); @@ -515,10 +721,15 @@ main(int argc, char **argv) argv += ret; if (argc > 1) args_parse(argc, argv, rules_file, data_file, &nb_jobs, - &perf_mode, &nb_iterations, &nb_qps); + &perf_mode, &nb_iterations, &nb_qps, + &nb_lcores, &nb_segs); if (nb_qps == 0) rte_exit(EXIT_FAILURE, "Number of QPs must be greater than 0\n"); + if (nb_lcores == 0) + rte_exit(EXIT_FAILURE, "Number of lcores must be greater than 0\n"); + if (distribute_qps_to_lcores(nb_lcores, nb_qps, &qps_per_lcore) < 0) + rte_exit(EXIT_FAILURE, "Failed to distribute queues to lcores!\n"); ret = init_port(&nb_max_payload, rules_file, &nb_max_matches, nb_qps); if (ret < 0) @@ -535,12 +746,28 @@ main(int argc, char **argv) if (job_len > nb_max_payload) rte_exit(EXIT_FAILURE, "Error, not enough jobs to cover input.\n"); - ret = run_regex(nb_jobs, perf_mode, - nb_iterations, nb_max_matches, nb_qps, - data_buf, data_len, job_len); - if (ret < 0) { - rte_exit(EXIT_FAILURE, "RegEx function failed\n"); + rgxc = rte_malloc(NULL, sizeof(*rgxc) * nb_lcores, 0); + if (!rgxc) + rte_exit(EXIT_FAILURE, "Failed to create Regex Conf\n"); + for (i = 0; i < nb_lcores; i++) { + rgxc[i] = (struct regex_conf){ + .nb_jobs = nb_jobs, + .nb_segs = nb_segs, + .perf_mode = perf_mode, + .nb_iterations = nb_iterations, + .nb_max_matches = nb_max_matches, + .nb_qps = qps_per_lcore[i].nb_qps, + .qp_id_base = qps_per_lcore[i].qp_id_base, + .data_buf = data_buf, + .data_len = data_len, + .job_len = job_len, + }; + rte_eal_remote_launch(run_regex, &rgxc[i], + qps_per_lcore[i].lcore_id); } + rte_eal_mp_wait_lcore(); rte_free(data_buf); + rte_free(rgxc); + rte_free(qps_per_lcore); return EXIT_SUCCESS; }