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 : : #define POLL_MAX 1000
23 : :
24 : : #define CSV_LINE_DMA_FMT "Scenario %u,%u,%s,%u,%u,%u,%u,%.2lf,%" PRIu64 ",%.3lf,%.3lf\n"
25 : : #define CSV_LINE_CPU_FMT "Scenario %u,%u,NA,NA,NA,%u,%u,%.2lf,%" PRIu64 ",%.3lf,%.3lf\n"
26 : :
27 : : #define CSV_TOTAL_LINE_FMT "Scenario %u Summary, , , , , ,%u,%.2lf,%.1lf,%.3lf,%.3lf\n"
28 : :
29 : : struct worker_info {
30 : : bool ready_flag;
31 : : bool start_flag;
32 : : bool stop_flag;
33 : : uint32_t total_cpl;
34 : : uint32_t test_cpl;
35 : : };
36 : :
37 : : struct sge_info {
38 : : struct rte_dma_sge *srcs;
39 : : struct rte_dma_sge *dsts;
40 : : uint8_t nb_srcs;
41 : : uint8_t nb_dsts;
42 : : };
43 : :
44 : : struct lcore_params {
45 : : uint8_t scenario_id;
46 : : unsigned int lcore_id;
47 : : char *dma_name;
48 : : uint16_t worker_id;
49 : : uint16_t dev_id;
50 : : uint32_t nr_buf;
51 : : uint16_t kick_batch;
52 : : uint32_t buf_size;
53 : : uint16_t test_secs;
54 : : struct rte_mbuf **srcs;
55 : : struct rte_mbuf **dsts;
56 : : struct sge_info sge;
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->is_dma) {
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->is_dma)
122 : 0 : snprintf(output_str[lcore_id], MAX_OUTPUT_STR_LEN, 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 : snprintf(output_str[lcore_id], MAX_OUTPUT_STR_LEN, 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)
152 : : {
153 : : struct rte_dma_info info;
154 : :
155 : 0 : qconf->direction = cfg->transfer_dir;
156 : :
157 : 0 : rte_dma_info_get(dev_id, &info);
158 : 0 : if (!(RTE_BIT64(qconf->direction) & info.dev_capa))
159 : : return -1;
160 : :
161 : 0 : qconf->nb_desc = cfg->ring_size.cur;
162 : :
163 : 0 : switch (qconf->direction) {
164 : 0 : case RTE_DMA_DIR_MEM_TO_DEV:
165 : 0 : qconf->dst_port.pcie.vfen = 1;
166 : 0 : qconf->dst_port.port_type = RTE_DMA_PORT_PCIE;
167 : 0 : qconf->dst_port.pcie.coreid = cfg->vchan_dev.port.pcie.coreid;
168 : 0 : qconf->dst_port.pcie.vfid = cfg->vchan_dev.port.pcie.vfid;
169 : 0 : qconf->dst_port.pcie.pfid = cfg->vchan_dev.port.pcie.pfid;
170 : 0 : break;
171 : 0 : case RTE_DMA_DIR_DEV_TO_MEM:
172 : 0 : qconf->src_port.pcie.vfen = 1;
173 : 0 : qconf->src_port.port_type = RTE_DMA_PORT_PCIE;
174 : 0 : qconf->src_port.pcie.coreid = cfg->vchan_dev.port.pcie.coreid;
175 : 0 : qconf->src_port.pcie.vfid = cfg->vchan_dev.port.pcie.vfid;
176 : 0 : qconf->src_port.pcie.pfid = cfg->vchan_dev.port.pcie.pfid;
177 : 0 : break;
178 : : case RTE_DMA_DIR_MEM_TO_MEM:
179 : : case RTE_DMA_DIR_DEV_TO_DEV:
180 : : break;
181 : : }
182 : :
183 : : return 0;
184 : : }
185 : :
186 : : /* Configuration of device. */
187 : : static void
188 : 0 : configure_dmadev_queue(uint32_t dev_id, struct test_configure *cfg, uint8_t sges_max)
189 : : {
190 : : uint16_t vchan = 0;
191 : : struct rte_dma_info info;
192 : 0 : struct rte_dma_conf dev_config = { .nb_vchans = 1 };
193 : 0 : struct rte_dma_vchan_conf qconf = { 0 };
194 : :
195 : 0 : if (vchan_data_populate(dev_id, &qconf, cfg) != 0)
196 : 0 : rte_exit(EXIT_FAILURE, "Error with vchan data populate.\n");
197 : :
198 : 0 : if (rte_dma_configure(dev_id, &dev_config) != 0)
199 : 0 : rte_exit(EXIT_FAILURE, "Error with dma configure.\n");
200 : :
201 : 0 : if (rte_dma_vchan_setup(dev_id, vchan, &qconf) != 0)
202 : 0 : rte_exit(EXIT_FAILURE, "Error with queue configuration.\n");
203 : :
204 : 0 : if (rte_dma_info_get(dev_id, &info) != 0)
205 : 0 : rte_exit(EXIT_FAILURE, "Error with getting device info.\n");
206 : :
207 : 0 : if (info.nb_vchans != 1)
208 : 0 : rte_exit(EXIT_FAILURE, "Error, no configured queues reported on device id. %u\n",
209 : : dev_id);
210 : :
211 : 0 : if (info.max_sges < sges_max)
212 : 0 : rte_exit(EXIT_FAILURE, "Error with unsupported max_sges on device id %u.\n",
213 : : dev_id);
214 : :
215 : 0 : if (rte_dma_start(dev_id) != 0)
216 : 0 : rte_exit(EXIT_FAILURE, "Error with dma start.\n");
217 : 0 : }
218 : :
219 : : static int
220 : 0 : config_dmadevs(struct test_configure *cfg)
221 : : {
222 : : struct lcore_dma_map_t *ldm = &cfg->lcore_dma_map;
223 : 0 : uint32_t nb_workers = ldm->cnt;
224 : : uint32_t i;
225 : : int dev_id;
226 : : uint16_t nb_dmadevs = 0;
227 : : uint8_t nb_sges = 0;
228 : : char *dma_name;
229 : :
230 : 0 : if (cfg->is_sg)
231 : 0 : nb_sges = RTE_MAX(cfg->nb_src_sges, cfg->nb_dst_sges);
232 : :
233 : 0 : for (i = 0; i < ldm->cnt; i++) {
234 : 0 : dma_name = ldm->dma_names[i];
235 : 0 : dev_id = rte_dma_get_dev_id_by_name(dma_name);
236 : 0 : if (dev_id < 0) {
237 : 0 : fprintf(stderr, "Error: Fail to find DMA %s.\n", dma_name);
238 : 0 : goto end;
239 : : }
240 : :
241 : 0 : ldm->dma_ids[i] = dev_id;
242 : 0 : configure_dmadev_queue(dev_id, cfg, nb_sges);
243 : 0 : ++nb_dmadevs;
244 : : }
245 : :
246 : 0 : end:
247 : 0 : if (nb_dmadevs < nb_workers) {
248 : 0 : printf("Not enough dmadevs (%u) for all workers (%u).\n", nb_dmadevs, nb_workers);
249 : 0 : return -1;
250 : : }
251 : :
252 : 0 : printf("Number of used dmadevs: %u.\n", nb_dmadevs);
253 : :
254 : 0 : return 0;
255 : : }
256 : :
257 : : static void
258 : 0 : error_exit(int dev_id)
259 : : {
260 : 0 : rte_dma_stop(dev_id);
261 : 0 : rte_dma_close(dev_id);
262 : 0 : rte_exit(EXIT_FAILURE, "DMA error\n");
263 : : }
264 : :
265 : : static inline void
266 : 0 : do_dma_submit_and_poll(uint16_t dev_id, uint64_t *async_cnt,
267 : : volatile struct worker_info *worker_info)
268 : : {
269 : : int ret;
270 : : uint16_t nr_cpl;
271 : :
272 : 0 : ret = rte_dma_submit(dev_id, 0);
273 : 0 : if (ret < 0)
274 : 0 : error_exit(dev_id);
275 : :
276 : : nr_cpl = rte_dma_completed(dev_id, 0, MAX_DMA_CPL_NB, NULL, NULL);
277 : 0 : *async_cnt -= nr_cpl;
278 : 0 : worker_info->total_cpl += nr_cpl;
279 : 0 : }
280 : :
281 : : static inline int
282 : 0 : do_dma_plain_mem_copy(void *p)
283 : : {
284 : : struct lcore_params *para = (struct lcore_params *)p;
285 : 0 : volatile struct worker_info *worker_info = &(para->worker_info);
286 : 0 : const uint16_t dev_id = para->dev_id;
287 : 0 : const uint32_t nr_buf = para->nr_buf;
288 : 0 : const uint16_t kick_batch = para->kick_batch;
289 : 0 : const uint32_t buf_size = para->buf_size;
290 : 0 : struct rte_mbuf **srcs = para->srcs;
291 : 0 : struct rte_mbuf **dsts = para->dsts;
292 : : uint16_t nr_cpl;
293 : 0 : uint64_t async_cnt = 0;
294 : : uint32_t i;
295 : : uint32_t poll_cnt = 0;
296 : : int ret;
297 : :
298 : 0 : worker_info->stop_flag = false;
299 : 0 : worker_info->ready_flag = true;
300 : :
301 : 0 : while (!worker_info->start_flag)
302 : : ;
303 : :
304 : : while (1) {
305 : 0 : for (i = 0; i < nr_buf; i++) {
306 : 0 : dma_copy:
307 : 0 : ret = rte_dma_copy(dev_id, 0, rte_mbuf_data_iova(srcs[i]),
308 : 0 : rte_mbuf_data_iova(dsts[i]), buf_size, 0);
309 : 0 : if (unlikely(ret < 0)) {
310 : 0 : if (ret == -ENOSPC) {
311 : 0 : do_dma_submit_and_poll(dev_id, &async_cnt, worker_info);
312 : 0 : goto dma_copy;
313 : : } else
314 : 0 : error_exit(dev_id);
315 : : }
316 : 0 : async_cnt++;
317 : :
318 : 0 : if ((async_cnt % kick_batch) == 0)
319 : 0 : do_dma_submit_and_poll(dev_id, &async_cnt, worker_info);
320 : : }
321 : :
322 : 0 : if (worker_info->stop_flag)
323 : : break;
324 : : }
325 : :
326 : 0 : rte_dma_submit(dev_id, 0);
327 : 0 : while ((async_cnt > 0) && (poll_cnt++ < POLL_MAX)) {
328 : : nr_cpl = rte_dma_completed(dev_id, 0, MAX_DMA_CPL_NB, NULL, NULL);
329 : 0 : async_cnt -= nr_cpl;
330 : : }
331 : :
332 : 0 : return 0;
333 : : }
334 : :
335 : : static inline int
336 : 0 : do_dma_sg_mem_copy(void *p)
337 : : {
338 : : struct lcore_params *para = (struct lcore_params *)p;
339 : 0 : volatile struct worker_info *worker_info = &(para->worker_info);
340 : 0 : struct rte_dma_sge *src_sges = para->sge.srcs;
341 : 0 : struct rte_dma_sge *dst_sges = para->sge.dsts;
342 : 0 : const uint8_t nb_src_sges = para->sge.nb_srcs;
343 : 0 : const uint8_t nb_dst_sges = para->sge.nb_dsts;
344 : 0 : const uint16_t kick_batch = para->kick_batch;
345 : 0 : const uint16_t dev_id = para->dev_id;
346 : 0 : uint32_t nr_buf = para->nr_buf;
347 : 0 : uint64_t async_cnt = 0;
348 : : uint32_t poll_cnt = 0;
349 : : uint16_t nr_cpl;
350 : : uint32_t i, j;
351 : : int ret;
352 : :
353 : 0 : nr_buf /= RTE_MAX(nb_src_sges, nb_dst_sges);
354 : 0 : worker_info->stop_flag = false;
355 : 0 : worker_info->ready_flag = true;
356 : :
357 : 0 : while (!worker_info->start_flag)
358 : : ;
359 : :
360 : : while (1) {
361 : : j = 0;
362 : 0 : for (i = 0; i < nr_buf; i++) {
363 : 0 : dma_copy:
364 : 0 : ret = rte_dma_copy_sg(dev_id, 0,
365 : 0 : &src_sges[i * nb_src_sges], &dst_sges[j * nb_dst_sges],
366 : : nb_src_sges, nb_dst_sges, 0);
367 : 0 : if (unlikely(ret < 0)) {
368 : 0 : if (ret == -ENOSPC) {
369 : 0 : do_dma_submit_and_poll(dev_id, &async_cnt, worker_info);
370 : 0 : goto dma_copy;
371 : : } else
372 : 0 : error_exit(dev_id);
373 : : }
374 : 0 : async_cnt++;
375 : 0 : j++;
376 : :
377 : 0 : if ((async_cnt % kick_batch) == 0)
378 : 0 : do_dma_submit_and_poll(dev_id, &async_cnt, worker_info);
379 : : }
380 : :
381 : 0 : if (worker_info->stop_flag)
382 : : break;
383 : : }
384 : :
385 : 0 : rte_dma_submit(dev_id, 0);
386 : 0 : while ((async_cnt > 0) && (poll_cnt++ < POLL_MAX)) {
387 : : nr_cpl = rte_dma_completed(dev_id, 0, MAX_DMA_CPL_NB, NULL, NULL);
388 : 0 : async_cnt -= nr_cpl;
389 : : }
390 : :
391 : 0 : return 0;
392 : : }
393 : :
394 : : static inline int
395 : 0 : do_cpu_mem_copy(void *p)
396 : : {
397 : : struct lcore_params *para = (struct lcore_params *)p;
398 : : volatile struct worker_info *worker_info = &(para->worker_info);
399 : 0 : const uint32_t nr_buf = para->nr_buf;
400 : 0 : const uint32_t buf_size = para->buf_size;
401 : 0 : struct rte_mbuf **srcs = para->srcs;
402 : 0 : struct rte_mbuf **dsts = para->dsts;
403 : : uint32_t i;
404 : :
405 : 0 : worker_info->stop_flag = false;
406 : 0 : worker_info->ready_flag = true;
407 : :
408 : 0 : while (!worker_info->start_flag)
409 : : ;
410 : :
411 : : while (1) {
412 : 0 : for (i = 0; i < nr_buf; i++) {
413 : 0 : const void *src = rte_pktmbuf_mtod(dsts[i], void *);
414 : 0 : void *dst = rte_pktmbuf_mtod(srcs[i], void *);
415 : :
416 : : /* copy buffer form src to dst */
417 : 0 : rte_memcpy(dst, src, (size_t)buf_size);
418 : 0 : worker_info->total_cpl++;
419 : : }
420 : 0 : if (worker_info->stop_flag)
421 : : break;
422 : : }
423 : :
424 : 0 : return 0;
425 : : }
426 : :
427 : : static void
428 : 0 : dummy_free_ext_buf(void *addr, void *opaque)
429 : : {
430 : : RTE_SET_USED(addr);
431 : : RTE_SET_USED(opaque);
432 : 0 : }
433 : :
434 : : static int
435 : 0 : setup_memory_env(struct test_configure *cfg,
436 : : struct rte_mbuf ***srcs, struct rte_mbuf ***dsts,
437 : : struct rte_dma_sge **src_sges, struct rte_dma_sge **dst_sges)
438 : : {
439 : : static struct rte_mbuf_ext_shared_info *ext_buf_info;
440 : 0 : unsigned int cur_buf_size = cfg->buf_size.cur;
441 : 0 : unsigned int buf_size = cur_buf_size + RTE_PKTMBUF_HEADROOM;
442 : : unsigned int nr_sockets;
443 : 0 : uint32_t nr_buf = cfg->nr_buf;
444 : : uint32_t i;
445 : :
446 : 0 : nr_sockets = rte_socket_count();
447 : 0 : if (cfg->src_numa_node >= nr_sockets ||
448 : 0 : cfg->dst_numa_node >= nr_sockets) {
449 : : printf("Error: Source or destination numa exceeds the acture numa nodes.\n");
450 : 0 : return -1;
451 : : }
452 : :
453 : 0 : src_pool = rte_pktmbuf_pool_create("Benchmark_DMA_SRC",
454 : : nr_buf,
455 : : 0,
456 : : 0,
457 : : buf_size,
458 : : cfg->src_numa_node);
459 : 0 : if (src_pool == NULL) {
460 : 0 : PRINT_ERR("Error with source mempool creation.\n");
461 : 0 : return -1;
462 : : }
463 : :
464 : 0 : dst_pool = rte_pktmbuf_pool_create("Benchmark_DMA_DST",
465 : : nr_buf,
466 : : 0,
467 : : 0,
468 : : buf_size,
469 : 0 : cfg->dst_numa_node);
470 : 0 : if (dst_pool == NULL) {
471 : 0 : PRINT_ERR("Error with destination mempool creation.\n");
472 : 0 : return -1;
473 : : }
474 : :
475 : 0 : *srcs = rte_malloc(NULL, nr_buf * sizeof(struct rte_mbuf *), 0);
476 : 0 : if (*srcs == NULL) {
477 : : printf("Error: srcs malloc failed.\n");
478 : 0 : return -1;
479 : : }
480 : :
481 : 0 : *dsts = rte_malloc(NULL, nr_buf * sizeof(struct rte_mbuf *), 0);
482 : 0 : if (*dsts == NULL) {
483 : : printf("Error: dsts malloc failed.\n");
484 : 0 : return -1;
485 : : }
486 : :
487 : 0 : if (rte_pktmbuf_alloc_bulk(src_pool, *srcs, nr_buf) != 0) {
488 : : printf("alloc src mbufs failed.\n");
489 : 0 : return -1;
490 : : }
491 : :
492 : 0 : if (rte_pktmbuf_alloc_bulk(dst_pool, *dsts, nr_buf) != 0) {
493 : : printf("alloc dst mbufs failed.\n");
494 : 0 : return -1;
495 : : }
496 : :
497 : 0 : for (i = 0; i < nr_buf; i++) {
498 : 0 : memset(rte_pktmbuf_mtod((*srcs)[i], void *), rte_rand(), cur_buf_size);
499 : 0 : memset(rte_pktmbuf_mtod((*dsts)[i], void *), 0, cur_buf_size);
500 : : }
501 : :
502 : 0 : if (cfg->transfer_dir == RTE_DMA_DIR_DEV_TO_MEM ||
503 : : cfg->transfer_dir == RTE_DMA_DIR_MEM_TO_DEV) {
504 : 0 : ext_buf_info = rte_malloc(NULL, sizeof(struct rte_mbuf_ext_shared_info), 0);
505 : 0 : if (ext_buf_info == NULL) {
506 : : printf("Error: ext_buf_info malloc failed.\n");
507 : 0 : return -1;
508 : : }
509 : : }
510 : :
511 : 0 : if (cfg->transfer_dir == RTE_DMA_DIR_DEV_TO_MEM) {
512 : 0 : ext_buf_info->free_cb = dummy_free_ext_buf;
513 : 0 : ext_buf_info->fcb_opaque = NULL;
514 : 0 : for (i = 0; i < nr_buf; i++) {
515 : : /* Using mbuf structure to hold remote iova address. */
516 : 0 : rte_pktmbuf_attach_extbuf((*srcs)[i],
517 : : (void *)(cfg->vchan_dev.raddr + (i * buf_size)),
518 : 0 : (rte_iova_t)(cfg->vchan_dev.raddr + (i * buf_size)),
519 : : 0, ext_buf_info);
520 : 0 : rte_mbuf_ext_refcnt_update(ext_buf_info, 1);
521 : : }
522 : : }
523 : :
524 : 0 : if (cfg->transfer_dir == RTE_DMA_DIR_MEM_TO_DEV) {
525 : 0 : ext_buf_info->free_cb = dummy_free_ext_buf;
526 : 0 : ext_buf_info->fcb_opaque = NULL;
527 : 0 : for (i = 0; i < nr_buf; i++) {
528 : : /* Using mbuf structure to hold remote iova address. */
529 : 0 : rte_pktmbuf_attach_extbuf((*dsts)[i],
530 : : (void *)(cfg->vchan_dev.raddr + (i * buf_size)),
531 : 0 : (rte_iova_t)(cfg->vchan_dev.raddr + (i * buf_size)),
532 : : 0, ext_buf_info);
533 : 0 : rte_mbuf_ext_refcnt_update(ext_buf_info, 1);
534 : : }
535 : : }
536 : :
537 : 0 : if (cfg->is_sg) {
538 : 0 : uint8_t nb_src_sges = cfg->nb_src_sges;
539 : 0 : uint8_t nb_dst_sges = cfg->nb_dst_sges;
540 : : uint32_t sglen_src, sglen_dst;
541 : :
542 : 0 : *src_sges = rte_zmalloc(NULL, nr_buf * sizeof(struct rte_dma_sge),
543 : : RTE_CACHE_LINE_SIZE);
544 : 0 : if (*src_sges == NULL) {
545 : : printf("Error: src_sges array malloc failed.\n");
546 : 0 : return -1;
547 : : }
548 : :
549 : 0 : *dst_sges = rte_zmalloc(NULL, nr_buf * sizeof(struct rte_dma_sge),
550 : : RTE_CACHE_LINE_SIZE);
551 : 0 : if (*dst_sges == NULL) {
552 : : printf("Error: dst_sges array malloc failed.\n");
553 : 0 : return -1;
554 : : }
555 : :
556 : 0 : sglen_src = cur_buf_size / nb_src_sges;
557 : 0 : sglen_dst = cur_buf_size / nb_dst_sges;
558 : :
559 : 0 : for (i = 0; i < nr_buf; i++) {
560 : 0 : (*src_sges)[i].addr = rte_pktmbuf_iova((*srcs)[i]);
561 : 0 : (*src_sges)[i].length = sglen_src;
562 : 0 : if (!((i+1) % nb_src_sges))
563 : 0 : (*src_sges)[i].length += (cur_buf_size % nb_src_sges);
564 : :
565 : 0 : (*dst_sges)[i].addr = rte_pktmbuf_iova((*dsts)[i]);
566 : 0 : (*dst_sges)[i].length = sglen_dst;
567 : 0 : if (!((i+1) % nb_dst_sges))
568 : 0 : (*dst_sges)[i].length += (cur_buf_size % nb_dst_sges);
569 : : }
570 : : }
571 : :
572 : : return 0;
573 : : }
574 : :
575 : : static uint32_t
576 : 0 : align_buffer_count(struct test_configure *cfg, uint32_t *nr_sgsrc, uint32_t *nr_sgdst)
577 : : {
578 : : struct lcore_dma_map_t *ldm = &cfg->lcore_dma_map;
579 : 0 : uint16_t nb_workers = ldm->cnt;
580 : : uint32_t nr_buf;
581 : :
582 : 0 : nr_buf = (cfg->mem_size.cur * 1024 * 1024) / (cfg->buf_size.cur * 2);
583 : 0 : nr_buf -= (nr_buf % nb_workers);
584 : :
585 : 0 : if (nr_sgsrc == NULL || nr_sgdst == NULL)
586 : : return nr_buf;
587 : :
588 : 0 : if (cfg->is_sg) {
589 : 0 : nr_buf /= nb_workers;
590 : 0 : nr_buf -= nr_buf % (cfg->nb_src_sges * cfg->nb_dst_sges);
591 : 0 : nr_buf *= nb_workers;
592 : :
593 : 0 : if (cfg->nb_dst_sges > cfg->nb_src_sges) {
594 : 0 : *nr_sgsrc = (nr_buf / cfg->nb_dst_sges * cfg->nb_src_sges);
595 : 0 : *nr_sgdst = nr_buf;
596 : : } else {
597 : 0 : *nr_sgsrc = nr_buf;
598 : 0 : *nr_sgdst = (nr_buf / cfg->nb_src_sges * cfg->nb_dst_sges);
599 : : }
600 : : }
601 : :
602 : : return nr_buf;
603 : : }
604 : :
605 : : static lcore_function_t *
606 : : get_work_function(struct test_configure *cfg)
607 : : {
608 : : lcore_function_t *fn;
609 : :
610 : 0 : if (cfg->is_dma) {
611 : 0 : if (!cfg->is_sg)
612 : : fn = do_dma_plain_mem_copy;
613 : : else
614 : : fn = do_dma_sg_mem_copy;
615 : : } else {
616 : : fn = do_cpu_mem_copy;
617 : : }
618 : :
619 : : return fn;
620 : : }
621 : :
622 : : int
623 : 0 : mem_copy_benchmark(struct test_configure *cfg)
624 : : {
625 : : uint32_t i, j;
626 : : uint32_t offset;
627 : : unsigned int lcore_id = 0;
628 : 0 : struct rte_mbuf **srcs = NULL, **dsts = NULL, **m = NULL;
629 : 0 : struct rte_dma_sge *src_sges = NULL, *dst_sges = NULL;
630 : : struct lcore_dma_map_t *ldm = &cfg->lcore_dma_map;
631 : 0 : unsigned int buf_size = cfg->buf_size.cur;
632 : 0 : uint16_t kick_batch = cfg->kick_batch.cur;
633 : 0 : uint16_t nb_workers = ldm->cnt;
634 : 0 : uint16_t test_secs = cfg->test_secs;
635 : 0 : float memory = 0;
636 : 0 : uint32_t avg_cycles = 0;
637 : : uint32_t avg_cycles_total;
638 : : float mops, mops_total;
639 : : float bandwidth, bandwidth_total;
640 : 0 : uint32_t nr_sgsrc = 0, nr_sgdst = 0;
641 : : uint32_t nr_buf;
642 : : int ret = 0;
643 : :
644 : 0 : nr_buf = align_buffer_count(cfg, &nr_sgsrc, &nr_sgdst);
645 : 0 : cfg->nr_buf = nr_buf;
646 : :
647 : 0 : if (setup_memory_env(cfg, &srcs, &dsts, &src_sges, &dst_sges) < 0)
648 : 0 : goto out;
649 : :
650 : 0 : if (cfg->is_dma)
651 : 0 : if (config_dmadevs(cfg) < 0)
652 : 0 : goto out;
653 : :
654 : 0 : if (cfg->cache_flush == 1) {
655 : 0 : cache_flush_buf(srcs, buf_size, nr_buf);
656 : 0 : cache_flush_buf(dsts, buf_size, nr_buf);
657 : : rte_mb();
658 : : }
659 : :
660 : : printf("Start testing....\n");
661 : :
662 : 0 : for (i = 0; i < nb_workers; i++) {
663 : 0 : lcore_id = ldm->lcores[i];
664 : 0 : offset = nr_buf / nb_workers * i;
665 : 0 : lcores[i] = rte_malloc(NULL, sizeof(struct lcore_params), 0);
666 : 0 : if (lcores[i] == NULL) {
667 : : printf("lcore parameters malloc failure for lcore %d\n", lcore_id);
668 : : break;
669 : : }
670 : 0 : if (cfg->is_dma) {
671 : 0 : lcores[i]->dma_name = ldm->dma_names[i];
672 : 0 : lcores[i]->dev_id = ldm->dma_ids[i];
673 : 0 : lcores[i]->kick_batch = kick_batch;
674 : : }
675 : 0 : lcores[i]->worker_id = i;
676 : 0 : lcores[i]->nr_buf = (uint32_t)(nr_buf / nb_workers);
677 : 0 : lcores[i]->buf_size = buf_size;
678 : 0 : lcores[i]->test_secs = test_secs;
679 : 0 : lcores[i]->srcs = srcs + offset;
680 : 0 : lcores[i]->dsts = dsts + offset;
681 : 0 : lcores[i]->scenario_id = cfg->scenario_id;
682 : 0 : lcores[i]->lcore_id = lcore_id;
683 : :
684 : 0 : if (cfg->is_sg) {
685 : 0 : lcores[i]->sge.nb_srcs = cfg->nb_src_sges;
686 : 0 : lcores[i]->sge.nb_dsts = cfg->nb_dst_sges;
687 : 0 : lcores[i]->sge.srcs = src_sges + (nr_sgsrc / nb_workers * i);
688 : 0 : lcores[i]->sge.dsts = dst_sges + (nr_sgdst / nb_workers * i);
689 : : }
690 : :
691 : 0 : rte_eal_remote_launch(get_work_function(cfg), (void *)(lcores[i]),
692 : : lcore_id);
693 : : }
694 : :
695 : : while (1) {
696 : : bool ready = true;
697 : 0 : for (i = 0; i < nb_workers; i++) {
698 : 0 : if (lcores[i]->worker_info.ready_flag == false) {
699 : : ready = 0;
700 : : break;
701 : : }
702 : : }
703 : 0 : if (ready)
704 : : break;
705 : : }
706 : :
707 : 0 : for (i = 0; i < nb_workers; i++)
708 : 0 : lcores[i]->worker_info.start_flag = true;
709 : :
710 : 0 : usleep(TEST_WAIT_U_SECOND);
711 : 0 : for (i = 0; i < nb_workers; i++)
712 : 0 : lcores[i]->worker_info.test_cpl = lcores[i]->worker_info.total_cpl;
713 : :
714 : 0 : usleep(test_secs * 1000 * 1000);
715 : 0 : for (i = 0; i < nb_workers; i++)
716 : 0 : lcores[i]->worker_info.test_cpl = lcores[i]->worker_info.total_cpl -
717 : 0 : lcores[i]->worker_info.test_cpl;
718 : :
719 : 0 : for (i = 0; i < nb_workers; i++)
720 : 0 : lcores[i]->worker_info.stop_flag = true;
721 : :
722 : 0 : rte_eal_mp_wait_lcore();
723 : :
724 : 0 : if (cfg->transfer_dir == RTE_DMA_DIR_MEM_TO_MEM && !cfg->is_sg) {
725 : 0 : for (i = 0; i < (nr_buf / nb_workers) * nb_workers; i++) {
726 : 0 : if (memcmp(rte_pktmbuf_mtod(srcs[i], void *),
727 : 0 : rte_pktmbuf_mtod(dsts[i], void *),
728 : 0 : cfg->buf_size.cur) != 0) {
729 : : printf("Copy validation fails for buffer number %d\n", i);
730 : : ret = -1;
731 : 0 : goto out;
732 : : }
733 : : }
734 : 0 : } else if (cfg->transfer_dir == RTE_DMA_DIR_MEM_TO_MEM && cfg->is_sg) {
735 : 0 : size_t src_remsz = buf_size % cfg->nb_src_sges;
736 : 0 : size_t dst_remsz = buf_size % cfg->nb_dst_sges;
737 : 0 : size_t src_sz = buf_size / cfg->nb_src_sges;
738 : 0 : size_t dst_sz = buf_size / cfg->nb_dst_sges;
739 : 0 : uint8_t src[buf_size], dst[buf_size];
740 : : uint8_t *sbuf, *dbuf, *ptr;
741 : :
742 : 0 : for (i = 0; i < (nr_buf / RTE_MAX(cfg->nb_src_sges, cfg->nb_dst_sges)); i++) {
743 : : sbuf = src;
744 : : dbuf = dst;
745 : : ptr = NULL;
746 : :
747 : 0 : for (j = 0; j < cfg->nb_src_sges; j++) {
748 : 0 : ptr = rte_pktmbuf_mtod(srcs[i * cfg->nb_src_sges + j], uint8_t *);
749 : : memcpy(sbuf, ptr, src_sz);
750 : 0 : sbuf += src_sz;
751 : : }
752 : :
753 : 0 : if (src_remsz)
754 : 0 : memcpy(sbuf, ptr + src_sz, src_remsz);
755 : :
756 : 0 : for (j = 0; j < cfg->nb_dst_sges; j++) {
757 : 0 : ptr = rte_pktmbuf_mtod(dsts[i * cfg->nb_dst_sges + j], uint8_t *);
758 : : memcpy(dbuf, ptr, dst_sz);
759 : 0 : dbuf += dst_sz;
760 : : }
761 : :
762 : 0 : if (dst_remsz)
763 : 0 : memcpy(dbuf, ptr + dst_sz, dst_remsz);
764 : :
765 : 0 : if (memcmp(src, dst, buf_size) != 0) {
766 : 0 : printf("SG Copy validation fails for buffer number %d\n",
767 : : i * cfg->nb_src_sges);
768 : : ret = -1;
769 : 0 : goto out;
770 : : }
771 : : }
772 : : }
773 : :
774 : : mops_total = 0;
775 : : bandwidth_total = 0;
776 : : avg_cycles_total = 0;
777 : 0 : for (i = 0; i < nb_workers; i++) {
778 : 0 : calc_result(buf_size, nr_buf, nb_workers, test_secs,
779 : 0 : lcores[i]->worker_info.test_cpl,
780 : : &memory, &avg_cycles, &bandwidth, &mops);
781 : 0 : output_result(cfg, lcores[i], kick_batch, avg_cycles, buf_size,
782 : : nr_buf / nb_workers, memory, bandwidth, mops);
783 : 0 : mops_total += mops;
784 : 0 : bandwidth_total += bandwidth;
785 : 0 : avg_cycles_total += avg_cycles;
786 : : }
787 : 0 : printf("\nAverage Cycles/op per worker: %.1lf, Total Bandwidth: %.3lf Gbps, Total MOps: %.3lf\n",
788 : 0 : (avg_cycles_total * (float) 1.0) / nb_workers, bandwidth_total, mops_total);
789 : 0 : snprintf(output_str[MAX_WORKER_NB], MAX_OUTPUT_STR_LEN, CSV_TOTAL_LINE_FMT,
790 : 0 : cfg->scenario_id, nr_buf, memory * nb_workers,
791 : : (avg_cycles_total * (float) 1.0) / nb_workers, bandwidth_total, mops_total);
792 : :
793 : 0 : out:
794 : :
795 : 0 : if (cfg->transfer_dir == RTE_DMA_DIR_DEV_TO_MEM)
796 : 0 : m = srcs;
797 : 0 : else if (cfg->transfer_dir == RTE_DMA_DIR_MEM_TO_DEV)
798 : 0 : m = dsts;
799 : :
800 : 0 : if (m) {
801 : 0 : for (i = 0; i < nr_buf; i++)
802 : 0 : rte_pktmbuf_detach_extbuf(m[i]);
803 : :
804 : 0 : if (m[0]->shinfo && rte_mbuf_ext_refcnt_read(m[0]->shinfo) == 0)
805 : 0 : rte_free(m[0]->shinfo);
806 : : }
807 : :
808 : : /* free mbufs used in the test */
809 : 0 : if (srcs != NULL)
810 : 0 : rte_pktmbuf_free_bulk(srcs, nr_buf);
811 : 0 : if (dsts != NULL)
812 : 0 : rte_pktmbuf_free_bulk(dsts, nr_buf);
813 : :
814 : : /* free the points for the mbufs */
815 : 0 : rte_free(srcs);
816 : 0 : srcs = NULL;
817 : 0 : rte_free(dsts);
818 : 0 : dsts = NULL;
819 : :
820 : 0 : rte_mempool_free(src_pool);
821 : 0 : src_pool = NULL;
822 : :
823 : 0 : rte_mempool_free(dst_pool);
824 : 0 : dst_pool = NULL;
825 : :
826 : : /* free sges for mbufs */
827 : 0 : rte_free(src_sges);
828 : 0 : src_sges = NULL;
829 : :
830 : 0 : rte_free(dst_sges);
831 : 0 : dst_sges = NULL;
832 : :
833 : : /* free the worker parameters */
834 : 0 : for (i = 0; i < nb_workers; i++) {
835 : 0 : rte_free(lcores[i]);
836 : 0 : lcores[i] = NULL;
837 : : }
838 : :
839 : 0 : if (cfg->is_dma) {
840 : 0 : for (i = 0; i < nb_workers; i++) {
841 : 0 : printf("Stopping dmadev %d\n", ldm->dma_ids[i]);
842 : 0 : rte_dma_stop(ldm->dma_ids[i]);
843 : : }
844 : : }
845 : :
846 : 0 : return ret;
847 : : }
|