Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2023 Intel Corporation
3 : : */
4 : :
5 : : #include <inttypes.h>
6 : : #include <stdio.h>
7 : : #include <stdlib.h>
8 : : #include <unistd.h>
9 : :
10 : : #include <rte_time.h>
11 : : #include <rte_mbuf.h>
12 : : #include <rte_dmadev.h>
13 : : #include <rte_malloc.h>
14 : : #include <rte_lcore.h>
15 : : #include <rte_random.h>
16 : :
17 : : #include "main.h"
18 : :
19 : : #define MAX_DMA_CPL_NB 255
20 : :
21 : : #define TEST_WAIT_U_SECOND 10000
22 : :
23 : : #define CSV_LINE_DMA_FMT "Scenario %u,%u,%s,%u,%u,%u,%u,%.2lf,%" PRIu64 ",%.3lf,%.3lf\n"
24 : : #define CSV_LINE_CPU_FMT "Scenario %u,%u,NA,NA,NA,%u,%u,%.2lf,%" PRIu64 ",%.3lf,%.3lf\n"
25 : :
26 : : #define CSV_TOTAL_LINE_FMT "Scenario %u Summary, , , , , ,%u,%.2lf,%.1lf,%.3lf,%.3lf\n"
27 : :
28 : : struct worker_info {
29 : : bool ready_flag;
30 : : bool start_flag;
31 : : bool stop_flag;
32 : : uint32_t total_cpl;
33 : : uint32_t test_cpl;
34 : : };
35 : :
36 : : struct sge_info {
37 : : struct rte_dma_sge *srcs;
38 : : struct rte_dma_sge *dsts;
39 : : uint8_t nb_srcs;
40 : : uint8_t nb_dsts;
41 : : };
42 : :
43 : : struct lcore_params {
44 : : uint8_t scenario_id;
45 : : unsigned int lcore_id;
46 : : char *dma_name;
47 : : uint16_t worker_id;
48 : : uint16_t dev_id;
49 : : uint32_t nr_buf;
50 : : uint16_t kick_batch;
51 : : uint32_t buf_size;
52 : : uint16_t test_secs;
53 : : struct rte_mbuf **srcs;
54 : : struct rte_mbuf **dsts;
55 : : struct sge_info sge;
56 : : struct rte_dma_op **dma_ops;
57 : : volatile struct worker_info worker_info;
58 : : };
59 : :
60 : : static struct rte_mempool *src_pool;
61 : : static struct rte_mempool *dst_pool;
62 : :
63 : : static struct lcore_params *lcores[MAX_WORKER_NB];
64 : :
65 : : #define PRINT_ERR(...) print_err(__func__, __LINE__, __VA_ARGS__)
66 : :
67 : : static inline int
68 : : __rte_format_printf(3, 4)
69 : 0 : print_err(const char *func, int lineno, const char *format, ...)
70 : : {
71 : : va_list ap;
72 : : int ret;
73 : :
74 : 0 : ret = fprintf(stderr, "In %s:%d - ", func, lineno);
75 : 0 : va_start(ap, format);
76 : 0 : ret += vfprintf(stderr, format, ap);
77 : 0 : va_end(ap);
78 : :
79 : 0 : return ret;
80 : : }
81 : :
82 : : static inline void
83 : 0 : calc_result(uint32_t buf_size, uint32_t nr_buf, uint16_t nb_workers, uint16_t test_secs,
84 : : uint32_t total_cnt, float *memory, uint32_t *ave_cycle,
85 : : float *bandwidth, float *mops)
86 : : {
87 : : float ops;
88 : :
89 : 0 : *memory = (float)(buf_size * (nr_buf / nb_workers) * 2) / (1024 * 1024);
90 : 0 : *ave_cycle = test_secs * rte_get_timer_hz() / total_cnt;
91 : 0 : ops = (float)total_cnt / test_secs;
92 : 0 : *mops = ops / (1000 * 1000);
93 : 0 : *bandwidth = (ops * buf_size * 8) / (1000 * 1000 * 1000);
94 : 0 : }
95 : :
96 : : static void
97 : 0 : output_result(struct test_configure *cfg, struct lcore_params *para,
98 : : uint16_t kick_batch, uint64_t ave_cycle, uint32_t buf_size,
99 : : uint32_t nr_buf, float memory, float bandwidth, float mops)
100 : : {
101 : 0 : uint16_t ring_size = cfg->ring_size.cur;
102 : 0 : uint8_t scenario_id = cfg->scenario_id;
103 : 0 : uint32_t lcore_id = para->lcore_id;
104 : 0 : char *dma_name = para->dma_name;
105 : :
106 : 0 : if (cfg->test_type == TEST_TYPE_DMA_MEM_COPY) {
107 : 0 : printf("lcore %u, DMA %s, DMA Ring Size: %u, Kick Batch Size: %u", lcore_id,
108 : : dma_name, ring_size, kick_batch);
109 : 0 : if (cfg->is_sg)
110 : 0 : printf(" DMA src sges: %u, dst sges: %u",
111 : 0 : para->sge.nb_srcs, para->sge.nb_dsts);
112 : : printf(".\n");
113 : : } else {
114 : : printf("lcore %u\n", lcore_id);
115 : : }
116 : :
117 : 0 : printf("Average Cycles/op: %" PRIu64 ", Buffer Size: %u B, Buffer Number: %u, Memory: %.2lf MB, Frequency: %.3lf Ghz.\n",
118 : : ave_cycle, buf_size, nr_buf, memory, rte_get_timer_hz()/1000000000.0);
119 : 0 : printf("Average Bandwidth: %.3lf Gbps, MOps: %.3lf\n", bandwidth, mops);
120 : :
121 : 0 : if (cfg->test_type == TEST_TYPE_DMA_MEM_COPY)
122 : 0 : output_csv(CSV_LINE_DMA_FMT,
123 : : scenario_id, lcore_id, dma_name, ring_size, kick_batch, buf_size,
124 : : nr_buf, memory, ave_cycle, bandwidth, mops);
125 : : else
126 : 0 : output_csv(CSV_LINE_CPU_FMT,
127 : : scenario_id, lcore_id, buf_size,
128 : : nr_buf, memory, ave_cycle, bandwidth, mops);
129 : 0 : }
130 : :
131 : : static inline void
132 : : cache_flush_buf(__rte_unused struct rte_mbuf **array,
133 : : __rte_unused uint32_t buf_size,
134 : : __rte_unused uint32_t nr_buf)
135 : : {
136 : : #ifdef RTE_ARCH_X86_64
137 : : char *data;
138 : : struct rte_mbuf **srcs = array;
139 : : uint32_t i, offset;
140 : :
141 : 0 : for (i = 0; i < nr_buf; i++) {
142 : 0 : data = rte_pktmbuf_mtod(srcs[i], char *);
143 : 0 : for (offset = 0; offset < buf_size; offset += 64)
144 : 0 : __builtin_ia32_clflush(data + offset);
145 : : }
146 : : #endif
147 : : }
148 : :
149 : : static int
150 : 0 : vchan_data_populate(uint32_t dev_id, struct rte_dma_vchan_conf *qconf,
151 : : struct test_configure *cfg, uint16_t dev_num)
152 : : {
153 : : struct vchan_dev_config *vchan_dconfig;
154 : : struct rte_dma_info info;
155 : :
156 : 0 : vchan_dconfig = &cfg->dma_config[dev_num].vchan_dev;
157 : 0 : qconf->direction = vchan_dconfig->tdir;
158 : :
159 : 0 : rte_dma_info_get(dev_id, &info);
160 : 0 : if (!(RTE_BIT64(qconf->direction) & info.dev_capa))
161 : : return -1;
162 : :
163 : 0 : qconf->nb_desc = cfg->ring_size.cur;
164 : :
165 : 0 : switch (qconf->direction) {
166 : 0 : case RTE_DMA_DIR_MEM_TO_DEV:
167 : 0 : qconf->dst_port.pcie.vfen = 1;
168 : 0 : qconf->dst_port.port_type = RTE_DMA_PORT_PCIE;
169 : 0 : qconf->dst_port.pcie.coreid = vchan_dconfig->port.pcie.coreid;
170 : 0 : qconf->dst_port.pcie.vfid = vchan_dconfig->port.pcie.vfid;
171 : 0 : qconf->dst_port.pcie.pfid = vchan_dconfig->port.pcie.pfid;
172 : 0 : break;
173 : 0 : case RTE_DMA_DIR_DEV_TO_MEM:
174 : 0 : qconf->src_port.pcie.vfen = 1;
175 : 0 : qconf->src_port.port_type = RTE_DMA_PORT_PCIE;
176 : 0 : qconf->src_port.pcie.coreid = vchan_dconfig->port.pcie.coreid;
177 : 0 : qconf->src_port.pcie.vfid = vchan_dconfig->port.pcie.vfid;
178 : 0 : qconf->src_port.pcie.pfid = vchan_dconfig->port.pcie.pfid;
179 : 0 : break;
180 : : case RTE_DMA_DIR_MEM_TO_MEM:
181 : : case RTE_DMA_DIR_DEV_TO_DEV:
182 : : break;
183 : : }
184 : :
185 : : return 0;
186 : : }
187 : :
188 : : /* Configuration of device. */
189 : : static void
190 : 0 : configure_dmadev_queue(uint32_t dev_id, struct test_configure *cfg, uint8_t sges_max,
191 : : uint16_t dev_num)
192 : : {
193 : : uint16_t vchan = 0;
194 : : struct rte_dma_info info;
195 : 0 : struct rte_dma_conf dev_config = { .nb_vchans = 1 };
196 : 0 : struct rte_dma_vchan_conf qconf = { 0 };
197 : :
198 : 0 : if (vchan_data_populate(dev_id, &qconf, cfg, dev_num) != 0)
199 : 0 : rte_exit(EXIT_FAILURE, "Error with vchan data populate.\n");
200 : :
201 : 0 : if (rte_dma_info_get(dev_id, &info) != 0)
202 : 0 : rte_exit(EXIT_FAILURE, "Error with getting device info.\n");
203 : :
204 : 0 : if (cfg->use_ops && !(info.dev_capa & RTE_DMA_CAPA_OPS_ENQ_DEQ))
205 : 0 : rte_exit(EXIT_FAILURE, "Error with device %s not support enq_deq ops.\n",
206 : : info.dev_name);
207 : :
208 : 0 : if (cfg->use_ops)
209 : 0 : dev_config.flags = RTE_DMA_CFG_FLAG_ENQ_DEQ;
210 : :
211 : 0 : if (rte_dma_configure(dev_id, &dev_config) != 0)
212 : 0 : rte_exit(EXIT_FAILURE, "Error with dma configure.\n");
213 : :
214 : 0 : if (rte_dma_vchan_setup(dev_id, vchan, &qconf) != 0)
215 : 0 : rte_exit(EXIT_FAILURE, "Error with queue configuration.\n");
216 : :
217 : 0 : if (rte_dma_info_get(dev_id, &info) != 0)
218 : 0 : rte_exit(EXIT_FAILURE, "Error with getting device info.\n");
219 : :
220 : 0 : if (info.nb_vchans != 1)
221 : 0 : rte_exit(EXIT_FAILURE, "Error, no configured queues reported on device id. %u\n",
222 : : dev_id);
223 : :
224 : 0 : if (info.max_sges < sges_max)
225 : 0 : rte_exit(EXIT_FAILURE, "Error with unsupported max_sges on device id %u.\n",
226 : : dev_id);
227 : :
228 : 0 : if (rte_dma_start(dev_id) != 0)
229 : 0 : rte_exit(EXIT_FAILURE, "Error with dma start.\n");
230 : 0 : }
231 : :
232 : : static int
233 : 0 : config_dmadevs(struct test_configure *cfg)
234 : : {
235 : 0 : uint32_t nb_workers = cfg->num_worker;
236 : : struct lcore_dma_map_t *ldm;
237 : : uint32_t i;
238 : : int dev_id;
239 : : uint16_t nb_dmadevs = 0;
240 : : uint8_t nb_sges = 0;
241 : : char *dma_name;
242 : :
243 : 0 : if (cfg->test_type != TEST_TYPE_DMA_MEM_COPY)
244 : : return 0;
245 : :
246 : 0 : if (cfg->is_sg)
247 : 0 : nb_sges = RTE_MAX(cfg->nb_src_sges, cfg->nb_dst_sges);
248 : :
249 : 0 : for (i = 0; i < nb_workers; i++) {
250 : : ldm = &cfg->dma_config[i].lcore_dma_map;
251 : 0 : dma_name = ldm->dma_names;
252 : 0 : dev_id = rte_dma_get_dev_id_by_name(dma_name);
253 : 0 : if (dev_id < 0) {
254 : 0 : fprintf(stderr, "Error: Fail to find DMA %s.\n", dma_name);
255 : 0 : goto end;
256 : : }
257 : :
258 : 0 : ldm->dma_id = dev_id;
259 : 0 : configure_dmadev_queue(dev_id, cfg, nb_sges, nb_dmadevs);
260 : 0 : ++nb_dmadevs;
261 : : }
262 : :
263 : 0 : end:
264 : 0 : if (nb_dmadevs < nb_workers) {
265 : 0 : printf("Not enough dmadevs (%u) for all workers (%u).\n", nb_dmadevs, nb_workers);
266 : 0 : return -1;
267 : : }
268 : :
269 : 0 : printf("Number of used dmadevs: %u.\n", nb_dmadevs);
270 : :
271 : 0 : return 0;
272 : : }
273 : :
274 : : static void
275 : 0 : stop_dmadev(struct test_configure *cfg, bool *stopped)
276 : : {
277 : : struct lcore_dma_map_t *lcore_dma_map;
278 : : uint32_t i;
279 : :
280 : 0 : if (*stopped)
281 : : return;
282 : :
283 : 0 : if (cfg->test_type == TEST_TYPE_DMA_MEM_COPY) {
284 : 0 : for (i = 0; i < cfg->num_worker; i++) {
285 : : lcore_dma_map = &cfg->dma_config[i].lcore_dma_map;
286 : 0 : printf("Stopping dmadev %d\n", lcore_dma_map->dma_id);
287 : 0 : rte_dma_stop(lcore_dma_map->dma_id);
288 : : }
289 : : }
290 : 0 : *stopped = true;
291 : : }
292 : :
293 : : static void
294 : 0 : error_exit(int dev_id)
295 : : {
296 : 0 : rte_dma_stop(dev_id);
297 : 0 : rte_dma_close(dev_id);
298 : 0 : rte_exit(EXIT_FAILURE, "DMA error\n");
299 : : }
300 : :
301 : : static inline void
302 : 0 : do_dma_submit_and_poll(uint16_t dev_id, uint64_t *async_cnt,
303 : : volatile struct worker_info *worker_info)
304 : : {
305 : : int ret;
306 : : uint16_t nr_cpl;
307 : :
308 : 0 : ret = rte_dma_submit(dev_id, 0);
309 : 0 : if (ret < 0)
310 : 0 : error_exit(dev_id);
311 : :
312 : : nr_cpl = rte_dma_completed(dev_id, 0, MAX_DMA_CPL_NB, NULL, NULL);
313 : 0 : *async_cnt -= nr_cpl;
314 : 0 : worker_info->total_cpl += nr_cpl;
315 : 0 : }
316 : :
317 : : static int
318 : 0 : do_dma_submit_and_wait_cpl(uint16_t dev_id, uint64_t async_cnt, bool use_ops)
319 : : {
320 : : #define MAX_WAIT_MSEC 1000
321 : : #define MAX_POLL 1000
322 : : #define DEQ_SZ 64
323 : : struct rte_dma_op *op[DEQ_SZ];
324 : : enum rte_dma_vchan_status st;
325 : : uint32_t poll_cnt = 0;
326 : : uint32_t wait_ms = 0;
327 : : uint16_t nr_cpl;
328 : :
329 : 0 : if (!use_ops)
330 : 0 : rte_dma_submit(dev_id, 0);
331 : :
332 : 0 : if (rte_dma_vchan_status(dev_id, 0, &st) < 0) {
333 : : rte_delay_ms(MAX_WAIT_MSEC);
334 : 0 : goto wait_cpl;
335 : : }
336 : :
337 : 0 : while (st == RTE_DMA_VCHAN_ACTIVE && wait_ms++ < MAX_WAIT_MSEC) {
338 : : rte_delay_ms(1);
339 : 0 : rte_dma_vchan_status(dev_id, 0, &st);
340 : : }
341 : :
342 : 0 : wait_cpl:
343 : 0 : while ((async_cnt > 0) && (poll_cnt++ < MAX_POLL)) {
344 : 0 : if (use_ops)
345 : : nr_cpl = rte_dma_dequeue_ops(dev_id, 0, op, DEQ_SZ);
346 : : else
347 : : nr_cpl = rte_dma_completed(dev_id, 0, MAX_DMA_CPL_NB, NULL, NULL);
348 : 0 : async_cnt -= nr_cpl;
349 : : }
350 : 0 : if (async_cnt > 0)
351 : 0 : PRINT_ERR("Error: wait DMA %u failed!\n", dev_id);
352 : :
353 : 0 : return async_cnt == 0 ? 0 : -1;
354 : : }
355 : :
356 : : static inline int
357 : 0 : do_dma_plain_mem_copy(void *p)
358 : : {
359 : : struct lcore_params *para = (struct lcore_params *)p;
360 : 0 : volatile struct worker_info *worker_info = &(para->worker_info);
361 : 0 : const uint16_t dev_id = para->dev_id;
362 : 0 : const uint32_t nr_buf = para->nr_buf;
363 : 0 : const uint16_t kick_batch = para->kick_batch;
364 : 0 : const uint32_t buf_size = para->buf_size;
365 : 0 : struct rte_mbuf **srcs = para->srcs;
366 : 0 : struct rte_mbuf **dsts = para->dsts;
367 : 0 : uint64_t async_cnt = 0;
368 : : uint32_t i;
369 : : int ret;
370 : :
371 : 0 : worker_info->stop_flag = false;
372 : 0 : worker_info->ready_flag = true;
373 : :
374 : 0 : while (!worker_info->start_flag)
375 : : ;
376 : :
377 : : while (1) {
378 : 0 : for (i = 0; i < nr_buf; i++) {
379 : 0 : dma_copy:
380 : 0 : ret = rte_dma_copy(dev_id, 0, rte_mbuf_data_iova(srcs[i]),
381 : 0 : rte_mbuf_data_iova(dsts[i]), buf_size, 0);
382 : 0 : if (unlikely(ret < 0)) {
383 : 0 : if (ret == -ENOSPC) {
384 : 0 : do_dma_submit_and_poll(dev_id, &async_cnt, worker_info);
385 : 0 : goto dma_copy;
386 : : } else
387 : 0 : error_exit(dev_id);
388 : : }
389 : 0 : async_cnt++;
390 : :
391 : 0 : if ((async_cnt % kick_batch) == 0)
392 : 0 : do_dma_submit_and_poll(dev_id, &async_cnt, worker_info);
393 : : }
394 : :
395 : 0 : if (worker_info->stop_flag)
396 : : break;
397 : : }
398 : :
399 : 0 : return do_dma_submit_and_wait_cpl(dev_id, async_cnt, false);
400 : : }
401 : :
402 : : static inline int
403 : 0 : do_dma_sg_mem_copy(void *p)
404 : : {
405 : : struct lcore_params *para = (struct lcore_params *)p;
406 : 0 : volatile struct worker_info *worker_info = &(para->worker_info);
407 : 0 : struct rte_dma_sge *src_sges = para->sge.srcs;
408 : 0 : struct rte_dma_sge *dst_sges = para->sge.dsts;
409 : 0 : const uint8_t nb_src_sges = para->sge.nb_srcs;
410 : 0 : const uint8_t nb_dst_sges = para->sge.nb_dsts;
411 : 0 : const uint16_t kick_batch = para->kick_batch;
412 : 0 : const uint16_t dev_id = para->dev_id;
413 : 0 : uint32_t nr_buf = para->nr_buf;
414 : 0 : uint64_t async_cnt = 0;
415 : : uint32_t i, j;
416 : : int ret;
417 : :
418 : 0 : nr_buf /= RTE_MAX(nb_src_sges, nb_dst_sges);
419 : 0 : worker_info->stop_flag = false;
420 : 0 : worker_info->ready_flag = true;
421 : :
422 : 0 : while (!worker_info->start_flag)
423 : : ;
424 : :
425 : : while (1) {
426 : : j = 0;
427 : 0 : for (i = 0; i < nr_buf; i++) {
428 : 0 : dma_copy:
429 : 0 : ret = rte_dma_copy_sg(dev_id, 0,
430 : 0 : &src_sges[i * nb_src_sges], &dst_sges[j * nb_dst_sges],
431 : : nb_src_sges, nb_dst_sges, 0);
432 : 0 : if (unlikely(ret < 0)) {
433 : 0 : if (ret == -ENOSPC) {
434 : 0 : do_dma_submit_and_poll(dev_id, &async_cnt, worker_info);
435 : 0 : goto dma_copy;
436 : : } else
437 : 0 : error_exit(dev_id);
438 : : }
439 : 0 : async_cnt++;
440 : 0 : j++;
441 : :
442 : 0 : if ((async_cnt % kick_batch) == 0)
443 : 0 : do_dma_submit_and_poll(dev_id, &async_cnt, worker_info);
444 : : }
445 : :
446 : 0 : if (worker_info->stop_flag)
447 : : break;
448 : : }
449 : :
450 : 0 : return do_dma_submit_and_wait_cpl(dev_id, async_cnt, false);
451 : : }
452 : :
453 : : static inline int
454 : 0 : do_dma_enq_deq_mem_copy(void *p)
455 : : {
456 : : #define DEQ_SZ 64
457 : : struct lcore_params *para = (struct lcore_params *)p;
458 : : volatile struct worker_info *worker_info = &(para->worker_info);
459 : 0 : struct rte_dma_op **dma_ops = para->dma_ops;
460 : 0 : uint16_t kick_batch = para->kick_batch, sz;
461 : 0 : const uint16_t dev_id = para->dev_id;
462 : 0 : uint32_t nr_buf = para->nr_buf;
463 : : struct rte_dma_op *op[DEQ_SZ];
464 : : uint64_t tenq, tdeq;
465 : : uint16_t enq, deq;
466 : : uint32_t i;
467 : :
468 : 0 : worker_info->stop_flag = false;
469 : 0 : worker_info->ready_flag = true;
470 : :
471 : 0 : while (!worker_info->start_flag)
472 : : ;
473 : :
474 : 0 : if (kick_batch > nr_buf)
475 : 0 : kick_batch = nr_buf;
476 : :
477 : : tenq = 0;
478 : : tdeq = 0;
479 : : while (1) {
480 : 0 : for (i = 0; i < nr_buf; i += kick_batch) {
481 : 0 : sz = RTE_MIN(nr_buf - i, kick_batch);
482 : 0 : enq = rte_dma_enqueue_ops(dev_id, 0, &dma_ops[i], sz);
483 : 0 : while (enq < sz) {
484 : : do {
485 : : deq = rte_dma_dequeue_ops(dev_id, 0, op, DEQ_SZ);
486 : 0 : tdeq += deq;
487 : 0 : } while (deq);
488 : 0 : enq += rte_dma_enqueue_ops(dev_id, 0, &dma_ops[i + enq], sz - enq);
489 : 0 : if (worker_info->stop_flag)
490 : : break;
491 : : }
492 : 0 : tenq += enq;
493 : :
494 : 0 : worker_info->total_cpl += enq;
495 : : }
496 : :
497 : 0 : if (worker_info->stop_flag)
498 : : break;
499 : : }
500 : :
501 : 0 : return do_dma_submit_and_wait_cpl(dev_id, tenq - tdeq, true);
502 : : }
503 : :
504 : : static inline int
505 : 0 : do_cpu_mem_copy(void *p)
506 : : {
507 : : struct lcore_params *para = (struct lcore_params *)p;
508 : : volatile struct worker_info *worker_info = &(para->worker_info);
509 : 0 : const uint32_t nr_buf = para->nr_buf;
510 : 0 : const uint32_t buf_size = para->buf_size;
511 : 0 : struct rte_mbuf **srcs = para->srcs;
512 : 0 : struct rte_mbuf **dsts = para->dsts;
513 : : uint32_t i;
514 : :
515 : 0 : worker_info->stop_flag = false;
516 : 0 : worker_info->ready_flag = true;
517 : :
518 : 0 : while (!worker_info->start_flag)
519 : : ;
520 : :
521 : : while (1) {
522 : 0 : for (i = 0; i < nr_buf; i++) {
523 : 0 : const void *src = rte_pktmbuf_mtod(dsts[i], void *);
524 : 0 : void *dst = rte_pktmbuf_mtod(srcs[i], void *);
525 : :
526 : : /* copy buffer form src to dst */
527 : 0 : rte_memcpy(dst, src, (size_t)buf_size);
528 : 0 : worker_info->total_cpl++;
529 : : }
530 : 0 : if (worker_info->stop_flag)
531 : : break;
532 : : }
533 : :
534 : 0 : return 0;
535 : : }
536 : :
537 : : static void
538 : 0 : dummy_free_ext_buf(void *addr, void *opaque)
539 : : {
540 : : RTE_SET_USED(addr);
541 : : RTE_SET_USED(opaque);
542 : 0 : }
543 : :
544 : : static int
545 : 0 : setup_memory_env(struct test_configure *cfg, uint32_t nr_buf,
546 : : struct rte_mbuf ***srcs, struct rte_mbuf ***dsts,
547 : : struct rte_dma_sge **src_sges, struct rte_dma_sge **dst_sges,
548 : : struct rte_dma_op ***dma_ops)
549 : : {
550 : 0 : unsigned int cur_buf_size = cfg->buf_size.cur;
551 : 0 : unsigned int buf_size = cur_buf_size + RTE_PKTMBUF_HEADROOM;
552 : : bool is_src_numa_incorrect, is_dst_numa_incorrect;
553 : : unsigned int nr_sockets;
554 : : uintptr_t ops;
555 : : uint32_t i;
556 : :
557 : 0 : nr_sockets = rte_socket_count();
558 : 0 : is_src_numa_incorrect = (cfg->src_numa_node >= nr_sockets);
559 : 0 : is_dst_numa_incorrect = (cfg->dst_numa_node >= nr_sockets);
560 : :
561 : 0 : if (is_src_numa_incorrect || is_dst_numa_incorrect) {
562 : 0 : PRINT_ERR("Error: Incorrect NUMA config for %s.\n",
563 : : (is_src_numa_incorrect && is_dst_numa_incorrect) ? "source & destination" :
564 : : (is_src_numa_incorrect) ? "source" : "destination");
565 : 0 : return -1;
566 : : }
567 : :
568 : 0 : if (buf_size > UINT16_MAX) {
569 : 0 : PRINT_ERR("Error: Invalid buf size: %u\n", cur_buf_size);
570 : 0 : return -1;
571 : : }
572 : :
573 : 0 : src_pool = rte_pktmbuf_pool_create("Benchmark_DMA_SRC",
574 : : nr_buf,
575 : : 0,
576 : : 0,
577 : : buf_size,
578 : : cfg->src_numa_node);
579 : 0 : if (src_pool == NULL) {
580 : 0 : PRINT_ERR("Error with source mempool creation.\n");
581 : 0 : return -1;
582 : : }
583 : :
584 : 0 : dst_pool = rte_pktmbuf_pool_create("Benchmark_DMA_DST",
585 : : nr_buf,
586 : : 0,
587 : : 0,
588 : : buf_size,
589 : 0 : cfg->dst_numa_node);
590 : 0 : if (dst_pool == NULL) {
591 : 0 : PRINT_ERR("Error with destination mempool creation.\n");
592 : 0 : return -1;
593 : : }
594 : :
595 : 0 : *srcs = rte_malloc(NULL, nr_buf * sizeof(struct rte_mbuf *), 0);
596 : 0 : if (*srcs == NULL) {
597 : : printf("Error: srcs malloc failed.\n");
598 : 0 : return -1;
599 : : }
600 : :
601 : 0 : *dsts = rte_malloc(NULL, nr_buf * sizeof(struct rte_mbuf *), 0);
602 : 0 : if (*dsts == NULL) {
603 : : printf("Error: dsts malloc failed.\n");
604 : 0 : return -1;
605 : : }
606 : :
607 : 0 : if (rte_pktmbuf_alloc_bulk(src_pool, *srcs, nr_buf) != 0) {
608 : : printf("alloc src mbufs failed.\n");
609 : 0 : return -1;
610 : : }
611 : :
612 : 0 : if (rte_pktmbuf_alloc_bulk(dst_pool, *dsts, nr_buf) != 0) {
613 : : printf("alloc dst mbufs failed.\n");
614 : 0 : return -1;
615 : : }
616 : :
617 : 0 : for (i = 0; i < nr_buf; i++) {
618 : 0 : memset(rte_pktmbuf_mtod((*srcs)[i], void *), rte_rand(), cur_buf_size);
619 : 0 : memset(rte_pktmbuf_mtod((*dsts)[i], void *), 0, cur_buf_size);
620 : : }
621 : :
622 : 0 : if (cfg->is_sg) {
623 : 0 : uint8_t nb_src_sges = cfg->nb_src_sges;
624 : 0 : uint8_t nb_dst_sges = cfg->nb_dst_sges;
625 : : uint32_t sglen_src, sglen_dst;
626 : :
627 : 0 : *src_sges = rte_zmalloc(NULL, nr_buf * sizeof(struct rte_dma_sge),
628 : : RTE_CACHE_LINE_SIZE);
629 : 0 : if (*src_sges == NULL) {
630 : : printf("Error: src_sges array malloc failed.\n");
631 : 0 : return -1;
632 : : }
633 : :
634 : 0 : *dst_sges = rte_zmalloc(NULL, nr_buf * sizeof(struct rte_dma_sge),
635 : : RTE_CACHE_LINE_SIZE);
636 : 0 : if (*dst_sges == NULL) {
637 : : printf("Error: dst_sges array malloc failed.\n");
638 : 0 : return -1;
639 : : }
640 : :
641 : 0 : sglen_src = cur_buf_size / nb_src_sges;
642 : 0 : sglen_dst = cur_buf_size / nb_dst_sges;
643 : :
644 : 0 : for (i = 0; i < nr_buf; i++) {
645 : 0 : (*src_sges)[i].addr = rte_pktmbuf_iova((*srcs)[i]);
646 : 0 : (*src_sges)[i].length = sglen_src;
647 : 0 : if (!((i+1) % nb_src_sges))
648 : 0 : (*src_sges)[i].length += (cur_buf_size % nb_src_sges);
649 : :
650 : 0 : (*dst_sges)[i].addr = rte_pktmbuf_iova((*dsts)[i]);
651 : 0 : (*dst_sges)[i].length = sglen_dst;
652 : 0 : if (!((i+1) % nb_dst_sges))
653 : 0 : (*dst_sges)[i].length += (cur_buf_size % nb_dst_sges);
654 : : }
655 : :
656 : 0 : if (cfg->use_ops) {
657 : 0 : nr_buf /= RTE_MAX(nb_src_sges, nb_dst_sges);
658 : 0 : *dma_ops = rte_zmalloc(NULL, nr_buf * (sizeof(struct rte_dma_op *)),
659 : : RTE_CACHE_LINE_SIZE);
660 : 0 : if (*dma_ops == NULL) {
661 : : printf("Error: dma_ops container malloc failed.\n");
662 : 0 : return -1;
663 : : }
664 : :
665 : 0 : ops = (uintptr_t)rte_zmalloc(
666 : : NULL,
667 : 0 : nr_buf * (sizeof(struct rte_dma_op) + ((nb_src_sges + nb_dst_sges) *
668 : : sizeof(struct rte_dma_sge))),
669 : : RTE_CACHE_LINE_SIZE);
670 : 0 : if (ops == 0) {
671 : : printf("Error: dma_ops malloc failed.\n");
672 : 0 : return -1;
673 : : }
674 : :
675 : 0 : for (i = 0; i < nr_buf; i++)
676 : 0 : (*dma_ops)[i] =
677 : 0 : (struct rte_dma_op *)(ops +
678 : 0 : (i * (sizeof(struct rte_dma_op) +
679 : : ((nb_src_sges + nb_dst_sges) *
680 : : sizeof(struct rte_dma_sge)))));
681 : : }
682 : : }
683 : :
684 : : return 0;
685 : : }
686 : :
687 : : static void
688 : 0 : teardown_memory_env(uint32_t nr_buf, struct rte_mbuf **srcs, struct rte_mbuf **dsts,
689 : : struct rte_dma_sge *src_sges, struct rte_dma_sge *dst_sges,
690 : : struct rte_dma_op **dma_ops)
691 : : {
692 : : /* free mbufs used in the test */
693 : 0 : if (srcs != NULL)
694 : 0 : rte_pktmbuf_free_bulk(srcs, nr_buf);
695 : 0 : if (dsts != NULL)
696 : 0 : rte_pktmbuf_free_bulk(dsts, nr_buf);
697 : :
698 : : /* free the points for the mbufs */
699 : 0 : rte_free(srcs);
700 : : srcs = NULL;
701 : 0 : rte_free(dsts);
702 : : dsts = NULL;
703 : :
704 : 0 : rte_mempool_free(src_pool);
705 : 0 : src_pool = NULL;
706 : :
707 : 0 : rte_mempool_free(dst_pool);
708 : 0 : dst_pool = NULL;
709 : :
710 : : /* free sges for mbufs */
711 : 0 : rte_free(src_sges);
712 : : src_sges = NULL;
713 : :
714 : 0 : rte_free(dst_sges);
715 : : dst_sges = NULL;
716 : :
717 : 0 : rte_free(dma_ops);
718 : 0 : }
719 : :
720 : : static uint32_t
721 : 0 : align_buffer_count(struct test_configure *cfg, uint32_t *nr_sgsrc, uint32_t *nr_sgdst)
722 : : {
723 : 0 : uint16_t nb_workers = cfg->num_worker;
724 : : uint32_t nr_buf;
725 : :
726 : 0 : nr_buf = (cfg->mem_size.cur * 1024 * 1024) / (cfg->buf_size.cur * 2);
727 : 0 : nr_buf -= (nr_buf % nb_workers);
728 : :
729 : 0 : if (nr_sgsrc == NULL || nr_sgdst == NULL)
730 : : return nr_buf;
731 : :
732 : 0 : if (cfg->is_sg) {
733 : 0 : nr_buf /= nb_workers;
734 : 0 : nr_buf -= nr_buf % (cfg->nb_src_sges * cfg->nb_dst_sges);
735 : 0 : nr_buf *= nb_workers;
736 : :
737 : 0 : if (cfg->nb_dst_sges > cfg->nb_src_sges) {
738 : 0 : *nr_sgsrc = (nr_buf / cfg->nb_dst_sges * cfg->nb_src_sges);
739 : 0 : *nr_sgdst = nr_buf;
740 : : } else {
741 : 0 : *nr_sgsrc = nr_buf;
742 : 0 : *nr_sgdst = (nr_buf / cfg->nb_src_sges * cfg->nb_dst_sges);
743 : : }
744 : : }
745 : :
746 : : return nr_buf;
747 : : }
748 : :
749 : : static lcore_function_t *
750 : : get_work_function(struct test_configure *cfg)
751 : : {
752 : : lcore_function_t *fn;
753 : :
754 : 0 : if (cfg->test_type == TEST_TYPE_DMA_MEM_COPY) {
755 : 0 : if (!cfg->is_sg)
756 : : fn = do_dma_plain_mem_copy;
757 : : else {
758 : 0 : if (cfg->use_ops)
759 : : fn = do_dma_enq_deq_mem_copy;
760 : : else
761 : : fn = do_dma_sg_mem_copy;
762 : : }
763 : : } else {
764 : : fn = do_cpu_mem_copy;
765 : : }
766 : :
767 : : return fn;
768 : : }
769 : :
770 : : static int
771 : 0 : attach_ext_buffer(struct vchan_dev_config *vchan_dev, struct lcore_params *lcore, bool is_sg,
772 : : uint32_t nr_sgsrc, uint32_t nr_sgdst)
773 : : {
774 : : static struct rte_mbuf_ext_shared_info *ext_buf_info;
775 : : struct rte_dma_sge **src_sges, **dst_sges;
776 : : struct rte_mbuf **srcs, **dsts;
777 : : unsigned int cur_buf_size;
778 : : unsigned int buf_size;
779 : : uint32_t nr_buf;
780 : : uint32_t i;
781 : :
782 : 0 : cur_buf_size = lcore->buf_size;
783 : 0 : buf_size = cur_buf_size + RTE_PKTMBUF_HEADROOM;
784 : 0 : nr_buf = lcore->nr_buf;
785 : 0 : srcs = lcore->srcs;
786 : 0 : dsts = lcore->dsts;
787 : :
788 : 0 : ext_buf_info = rte_malloc(NULL, sizeof(struct rte_mbuf_ext_shared_info), 0);
789 : 0 : if (ext_buf_info == NULL) {
790 : : printf("Error: ext_buf_info malloc failed.\n");
791 : 0 : return -1;
792 : : }
793 : 0 : ext_buf_info->free_cb = dummy_free_ext_buf;
794 : 0 : ext_buf_info->fcb_opaque = NULL;
795 : :
796 : 0 : if (vchan_dev->tdir == RTE_DMA_DIR_DEV_TO_MEM) {
797 : 0 : for (i = 0; i < nr_buf; i++) {
798 : : /* Using mbuf structure to hold remote iova address. */
799 : 0 : rte_pktmbuf_attach_extbuf(srcs[i],
800 : : (void *)(vchan_dev->raddr + (i * buf_size)),
801 : 0 : (rte_iova_t)(vchan_dev->raddr + (i * buf_size)), 0, ext_buf_info);
802 : 0 : rte_mbuf_ext_refcnt_update(ext_buf_info, 1);
803 : : }
804 : : }
805 : :
806 : 0 : if (vchan_dev->tdir == RTE_DMA_DIR_MEM_TO_DEV) {
807 : 0 : for (i = 0; i < nr_buf; i++) {
808 : : /* Using mbuf structure to hold remote iova address. */
809 : 0 : rte_pktmbuf_attach_extbuf(dsts[i],
810 : : (void *)(vchan_dev->raddr + (i * buf_size)),
811 : 0 : (rte_iova_t)(vchan_dev->raddr + (i * buf_size)), 0, ext_buf_info);
812 : 0 : rte_mbuf_ext_refcnt_update(ext_buf_info, 1);
813 : : }
814 : : }
815 : :
816 : 0 : if (is_sg) {
817 : 0 : uint8_t nb_src_sges = lcore->sge.nb_srcs;
818 : 0 : uint8_t nb_dst_sges = lcore->sge.nb_dsts;
819 : : uint32_t sglen_src, sglen_dst;
820 : :
821 : : src_sges = &lcore->sge.srcs;
822 : : dst_sges = &lcore->sge.dsts;
823 : :
824 : 0 : sglen_src = cur_buf_size / nb_src_sges;
825 : 0 : sglen_dst = cur_buf_size / nb_dst_sges;
826 : :
827 : 0 : if (vchan_dev->tdir == RTE_DMA_DIR_DEV_TO_MEM) {
828 : 0 : for (i = 0; i < nr_sgsrc; i++) {
829 : 0 : (*src_sges)[i].addr = rte_pktmbuf_iova(srcs[i]);
830 : 0 : (*src_sges)[i].length = sglen_src;
831 : 0 : if (!((i+1) % nb_src_sges))
832 : 0 : (*src_sges)[i].length += (cur_buf_size % nb_src_sges);
833 : : }
834 : : }
835 : :
836 : 0 : if (vchan_dev->tdir == RTE_DMA_DIR_MEM_TO_DEV) {
837 : 0 : for (i = 0; i < nr_sgdst; i++) {
838 : 0 : (*dst_sges)[i].addr = rte_pktmbuf_iova(dsts[i]);
839 : 0 : (*dst_sges)[i].length = sglen_dst;
840 : 0 : if (!((i+1) % nb_dst_sges))
841 : 0 : (*dst_sges)[i].length += (cur_buf_size % nb_dst_sges);
842 : : }
843 : : }
844 : : }
845 : :
846 : : return 0;
847 : : }
848 : :
849 : : static int
850 : 0 : verify_data(struct test_configure *cfg, struct rte_mbuf **srcs, struct rte_mbuf **dsts,
851 : : uint32_t nr_buf)
852 : : {
853 : : struct rte_mbuf **src_buf = NULL, **dst_buf = NULL;
854 : 0 : uint32_t nr_buf_pt = nr_buf / cfg->num_worker;
855 : : struct vchan_dev_config *vchan_dev = NULL;
856 : 0 : unsigned int buf_size = cfg->buf_size.cur;
857 : : uint32_t offset, work_idx, i, j;
858 : :
859 : 0 : for (work_idx = 0; work_idx < cfg->num_worker; work_idx++) {
860 : : vchan_dev = &cfg->dma_config[work_idx].vchan_dev;
861 : 0 : offset = nr_buf / cfg->num_worker * work_idx;
862 : 0 : src_buf = srcs + offset;
863 : 0 : dst_buf = dsts + offset;
864 : :
865 : 0 : if (vchan_dev->tdir == RTE_DMA_DIR_MEM_TO_MEM && !cfg->is_sg) {
866 : 0 : for (i = 0; i < nr_buf_pt; i++) {
867 : 0 : if (memcmp(rte_pktmbuf_mtod(src_buf[i], void *),
868 : 0 : rte_pktmbuf_mtod(dst_buf[i], void *),
869 : 0 : cfg->buf_size.cur) != 0) {
870 : : printf("Copy validation fails for buffer number %d\n", i);
871 : 0 : return -1;
872 : : }
873 : : }
874 : 0 : continue;
875 : : }
876 : :
877 : 0 : if (vchan_dev->tdir == RTE_DMA_DIR_MEM_TO_MEM && cfg->is_sg) {
878 : 0 : size_t src_remsz = buf_size % cfg->nb_src_sges;
879 : 0 : size_t dst_remsz = buf_size % cfg->nb_dst_sges;
880 : 0 : size_t src_sz = buf_size / cfg->nb_src_sges;
881 : 0 : size_t dst_sz = buf_size / cfg->nb_dst_sges;
882 : 0 : uint8_t src[buf_size], dst[buf_size];
883 : : uint8_t *sbuf, *dbuf, *ptr;
884 : :
885 : 0 : for (i = 0; i < (nr_buf_pt / RTE_MAX(cfg->nb_src_sges, cfg->nb_dst_sges));
886 : 0 : i++) {
887 : : sbuf = src;
888 : : dbuf = dst;
889 : : ptr = NULL;
890 : :
891 : 0 : for (j = 0; j < cfg->nb_src_sges; j++) {
892 : 0 : ptr = rte_pktmbuf_mtod(src_buf[i * cfg->nb_src_sges + j],
893 : : uint8_t *);
894 : : memcpy(sbuf, ptr, src_sz);
895 : 0 : sbuf += src_sz;
896 : : }
897 : 0 : if (src_remsz)
898 : 0 : memcpy(sbuf, ptr + src_sz, src_remsz);
899 : :
900 : 0 : for (j = 0; j < cfg->nb_dst_sges; j++) {
901 : 0 : ptr = rte_pktmbuf_mtod(dst_buf[i * cfg->nb_dst_sges + j],
902 : : uint8_t *);
903 : : memcpy(dbuf, ptr, dst_sz);
904 : 0 : dbuf += dst_sz;
905 : : }
906 : 0 : if (dst_remsz)
907 : 0 : memcpy(dbuf, ptr + dst_sz, dst_remsz);
908 : :
909 : 0 : if (memcmp(src, dst, buf_size) != 0) {
910 : 0 : printf("SG Copy validation fails for buffer number %d\n",
911 : : i * cfg->nb_src_sges);
912 : 0 : return -1;
913 : : }
914 : : }
915 : 0 : continue;
916 : : }
917 : : }
918 : :
919 : : return 0;
920 : : }
921 : :
922 : : static int
923 : 0 : setup_worker(struct test_configure *cfg, uint32_t nr_buf,
924 : : struct rte_mbuf **srcs, struct rte_mbuf **dsts,
925 : : struct rte_dma_sge *src_sges, struct rte_dma_sge *dst_sges,
926 : : struct rte_dma_op **dma_ops,
927 : : uint32_t nr_sgsrc, uint32_t nr_sgdst)
928 : : {
929 : : struct lcore_dma_map_t *lcore_dma_map = NULL;
930 : : struct vchan_dev_config *vchan_dev = NULL;
931 : 0 : unsigned int buf_size = cfg->buf_size.cur;
932 : 0 : uint16_t kick_batch = cfg->kick_batch.cur;
933 : 0 : uint16_t test_secs = global_cfg.test_secs;
934 : 0 : uint16_t nb_workers = cfg->num_worker;
935 : : unsigned int lcore_id = 0;
936 : : uint32_t i, j, k;
937 : : uint32_t nr_ops;
938 : : uint32_t offset;
939 : :
940 : 0 : for (i = 0; i < nb_workers; i++) {
941 : : lcore_dma_map = &cfg->dma_config[i].lcore_dma_map;
942 : 0 : vchan_dev = &cfg->dma_config[i].vchan_dev;
943 : :
944 : 0 : lcore_id = lcore_dma_map->lcore;
945 : 0 : offset = nr_buf / nb_workers * i;
946 : 0 : lcores[i] = rte_malloc(NULL, sizeof(struct lcore_params), 0);
947 : 0 : if (lcores[i] == NULL) {
948 : : printf("lcore parameters malloc failure for lcore %d\n", lcore_id);
949 : 0 : return -1;
950 : : }
951 : 0 : if (cfg->test_type == TEST_TYPE_DMA_MEM_COPY) {
952 : 0 : lcores[i]->dma_name = lcore_dma_map->dma_names;
953 : 0 : lcores[i]->dev_id = lcore_dma_map->dma_id;
954 : 0 : lcores[i]->kick_batch = kick_batch;
955 : : }
956 : :
957 : 0 : lcores[i]->worker_id = i;
958 : 0 : lcores[i]->nr_buf = (uint32_t)(nr_buf / nb_workers);
959 : 0 : lcores[i]->buf_size = buf_size;
960 : 0 : lcores[i]->test_secs = test_secs;
961 : 0 : lcores[i]->srcs = srcs + offset;
962 : 0 : lcores[i]->dsts = dsts + offset;
963 : 0 : lcores[i]->scenario_id = cfg->scenario_id;
964 : 0 : lcores[i]->lcore_id = lcore_id;
965 : :
966 : 0 : if (cfg->is_sg) {
967 : 0 : lcores[i]->sge.nb_srcs = cfg->nb_src_sges;
968 : 0 : lcores[i]->sge.nb_dsts = cfg->nb_dst_sges;
969 : 0 : lcores[i]->sge.srcs = src_sges + (nr_sgsrc / nb_workers * i);
970 : 0 : lcores[i]->sge.dsts = dst_sges + (nr_sgdst / nb_workers * i);
971 : : }
972 : :
973 : 0 : if (vchan_dev->tdir == RTE_DMA_DIR_DEV_TO_MEM ||
974 : : vchan_dev->tdir == RTE_DMA_DIR_MEM_TO_DEV) {
975 : 0 : if (attach_ext_buffer(vchan_dev, lcores[i], cfg->is_sg,
976 : : (nr_sgsrc/nb_workers), (nr_sgdst/nb_workers)) < 0)
977 : : return -1;
978 : : }
979 : :
980 : 0 : if (cfg->is_sg && cfg->use_ops) {
981 : 0 : nr_ops = nr_buf / RTE_MAX(cfg->nb_src_sges, cfg->nb_dst_sges);
982 : 0 : lcores[i]->nr_buf = nr_ops / nb_workers;
983 : 0 : lcores[i]->dma_ops = dma_ops + (nr_ops / nb_workers * i);
984 : 0 : for (j = 0; j < (nr_ops / nb_workers); j++) {
985 : 0 : for (k = 0; k < cfg->nb_src_sges; k++)
986 : 0 : lcores[i]->dma_ops[j]->src_dst_seg[k] =
987 : 0 : lcores[i]->sge.srcs[(j * cfg->nb_src_sges) + k];
988 : :
989 : 0 : for (k = 0; k < cfg->nb_dst_sges; k++)
990 : 0 : lcores[i]->dma_ops[j]->src_dst_seg[k + cfg->nb_src_sges] =
991 : 0 : lcores[i]->sge.dsts[(j * cfg->nb_dst_sges) + k];
992 : :
993 : 0 : lcores[i]->dma_ops[j]->nb_src = cfg->nb_src_sges;
994 : 0 : lcores[i]->dma_ops[j]->nb_dst = cfg->nb_dst_sges;
995 : 0 : lcores[i]->dma_ops[j]->vchan = 0;
996 : : }
997 : : }
998 : :
999 : 0 : rte_eal_remote_launch(get_work_function(cfg), (void *)(lcores[i]), lcore_id);
1000 : : }
1001 : :
1002 : : return 0;
1003 : : }
1004 : :
1005 : : static void
1006 : 0 : teardown_worker_res(struct test_configure *cfg, uint32_t nr_buf,
1007 : : struct rte_mbuf **srcs, struct rte_mbuf **dsts)
1008 : : {
1009 : 0 : uint16_t nb_workers = cfg->num_worker;
1010 : : struct vchan_dev_config *vchan_dev;
1011 : : struct rte_mbuf **m;
1012 : : uint32_t offset;
1013 : : uint32_t i, j;
1014 : :
1015 : 0 : for (i = 0; i < nb_workers; i++) {
1016 : : struct rte_mbuf **sbuf = NULL, **dbuf = NULL;
1017 : : vchan_dev = &cfg->dma_config[i].vchan_dev;
1018 : 0 : offset = nr_buf / nb_workers * i;
1019 : : m = NULL;
1020 : 0 : if (vchan_dev->tdir == RTE_DMA_DIR_DEV_TO_MEM) {
1021 : 0 : sbuf = srcs + offset;
1022 : : m = sbuf;
1023 : 0 : } else if (vchan_dev->tdir == RTE_DMA_DIR_MEM_TO_DEV) {
1024 : 0 : dbuf = dsts + offset;
1025 : : m = dbuf;
1026 : : }
1027 : :
1028 : 0 : if (m) {
1029 : 0 : for (j = 0; j < (nr_buf / nb_workers); j++)
1030 : 0 : rte_pktmbuf_detach_extbuf(m[j]);
1031 : :
1032 : 0 : if (m[0]->shinfo && rte_mbuf_ext_refcnt_read(m[0]->shinfo) == 0)
1033 : 0 : rte_free(m[0]->shinfo);
1034 : : }
1035 : :
1036 : 0 : rte_free(lcores[i]);
1037 : 0 : lcores[i] = NULL;
1038 : : }
1039 : 0 : }
1040 : :
1041 : : int
1042 : 0 : mem_copy_benchmark(struct test_configure *cfg)
1043 : : {
1044 : 0 : struct rte_mbuf **srcs = NULL, **dsts = NULL;
1045 : 0 : struct rte_dma_sge *src_sges = NULL, *dst_sges = NULL;
1046 : : struct vchan_dev_config *vchan_dev = NULL;
1047 : 0 : unsigned int buf_size = cfg->buf_size.cur;
1048 : 0 : uint16_t kick_batch = cfg->kick_batch.cur;
1049 : 0 : uint16_t test_secs = global_cfg.test_secs;
1050 : 0 : uint16_t nb_workers = cfg->num_worker;
1051 : 0 : uint32_t nr_sgsrc = 0, nr_sgdst = 0;
1052 : 0 : struct rte_dma_op **dma_ops = NULL;
1053 : : float bandwidth, bandwidth_total;
1054 : : uint32_t avg_cycles_total;
1055 : 0 : bool dev_stopped = false;
1056 : 0 : uint32_t avg_cycles = 0;
1057 : : float mops, mops_total;
1058 : 0 : float memory = 0;
1059 : : uint32_t nr_buf;
1060 : : int ret = -1;
1061 : : uint32_t i;
1062 : :
1063 : 0 : nr_buf = align_buffer_count(cfg, &nr_sgsrc, &nr_sgdst);
1064 : :
1065 : 0 : if (setup_memory_env(cfg, nr_buf, &srcs, &dsts, &src_sges, &dst_sges, &dma_ops) < 0)
1066 : 0 : goto out;
1067 : :
1068 : 0 : if (config_dmadevs(cfg) < 0)
1069 : 0 : goto out;
1070 : :
1071 : 0 : if (global_cfg.cache_flush > 0) {
1072 : 0 : cache_flush_buf(srcs, buf_size, nr_buf);
1073 : 0 : cache_flush_buf(dsts, buf_size, nr_buf);
1074 : : rte_mb();
1075 : : }
1076 : :
1077 : : printf("Start testing....\n");
1078 : :
1079 : 0 : ret = setup_worker(cfg, nr_buf, srcs, dsts, src_sges, dst_sges, dma_ops,
1080 : : nr_sgsrc, nr_sgdst);
1081 : 0 : if (ret != 0)
1082 : 0 : goto stop_dmadev;
1083 : :
1084 : : while (1) {
1085 : : bool ready = true;
1086 : 0 : for (i = 0; i < nb_workers; i++) {
1087 : 0 : if (lcores[i]->worker_info.ready_flag == false) {
1088 : : ready = 0;
1089 : : break;
1090 : : }
1091 : : }
1092 : 0 : if (ready)
1093 : : break;
1094 : : }
1095 : :
1096 : 0 : for (i = 0; i < nb_workers; i++)
1097 : 0 : lcores[i]->worker_info.start_flag = true;
1098 : :
1099 : 0 : usleep(TEST_WAIT_U_SECOND);
1100 : 0 : for (i = 0; i < nb_workers; i++)
1101 : 0 : lcores[i]->worker_info.test_cpl = lcores[i]->worker_info.total_cpl;
1102 : :
1103 : 0 : usleep(test_secs * 1000 * 1000);
1104 : 0 : for (i = 0; i < nb_workers; i++)
1105 : 0 : lcores[i]->worker_info.test_cpl = lcores[i]->worker_info.total_cpl -
1106 : 0 : lcores[i]->worker_info.test_cpl;
1107 : :
1108 : 0 : for (i = 0; i < nb_workers; i++)
1109 : 0 : lcores[i]->worker_info.stop_flag = true;
1110 : :
1111 : 0 : rte_eal_mp_wait_lcore();
1112 : :
1113 : 0 : stop_dmadev(cfg, &dev_stopped);
1114 : :
1115 : 0 : ret = verify_data(cfg, srcs, dsts, nr_buf);
1116 : 0 : if (ret != 0)
1117 : 0 : goto out;
1118 : :
1119 : : mops_total = 0;
1120 : : bandwidth_total = 0;
1121 : : avg_cycles_total = 0;
1122 : 0 : for (i = 0; i < nb_workers; i++) {
1123 : : vchan_dev = &cfg->dma_config[i].vchan_dev;
1124 : 0 : calc_result(buf_size, nr_buf, nb_workers, test_secs,
1125 : 0 : lcores[i]->worker_info.test_cpl,
1126 : : &memory, &avg_cycles, &bandwidth, &mops);
1127 : 0 : printf("Direction: %s\n", vchan_dev->tdir == 0 ? "mem2mem" :
1128 : 0 : vchan_dev->tdir == 1 ? "mem2dev" : "dev2mem");
1129 : 0 : output_result(cfg, lcores[i], kick_batch, avg_cycles, buf_size,
1130 : : nr_buf / nb_workers, memory, bandwidth, mops);
1131 : 0 : mops_total += mops;
1132 : 0 : bandwidth_total += bandwidth;
1133 : 0 : avg_cycles_total += avg_cycles;
1134 : : }
1135 : 0 : printf("\nAverage Cycles/op per worker: %.1lf, Total Bandwidth: %.3lf Gbps, Total MOps: %.3lf\n",
1136 : 0 : (avg_cycles_total * (float) 1.0) / nb_workers, bandwidth_total, mops_total);
1137 : 0 : output_csv(CSV_TOTAL_LINE_FMT, cfg->scenario_id, nr_buf, memory * nb_workers,
1138 : : (avg_cycles_total * (float) 1.0) / nb_workers, bandwidth_total, mops_total);
1139 : :
1140 : 0 : stop_dmadev:
1141 : 0 : stop_dmadev(cfg, &dev_stopped);
1142 : :
1143 : 0 : out:
1144 : 0 : teardown_worker_res(cfg, nr_buf, srcs, dsts);
1145 : 0 : teardown_memory_env(nr_buf, srcs, dsts, src_sges, dst_sges, dma_ops);
1146 : :
1147 : 0 : return ret;
1148 : : }
|