Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2023 Intel Corporation
3 : : */
4 : :
5 : : #include <stdio.h>
6 : : #include <stdlib.h>
7 : : #include <getopt.h>
8 : : #include <signal.h>
9 : : #include <stdbool.h>
10 : : #include <unistd.h>
11 : : #include <sys/wait.h>
12 : : #include <inttypes.h>
13 : : #include <libgen.h>
14 : :
15 : : #include <rte_argparse.h>
16 : : #include <rte_eal.h>
17 : : #include <rte_cfgfile.h>
18 : : #include <rte_string_fns.h>
19 : : #include <rte_lcore.h>
20 : : #include <rte_dmadev.h>
21 : : #include <rte_kvargs.h>
22 : :
23 : : #include "main.h"
24 : :
25 : : #define CSV_HDR_FMT "Case %u : %s,lcore,DMA,DMA ring size,kick batch size,buffer size(B),number of buffers,memory(MB),average cycle,bandwidth(Gbps),MOps\n"
26 : :
27 : : #define DMA_MEM_COPY "DMA_MEM_COPY"
28 : : #define CPU_MEM_COPY "CPU_MEM_COPY"
29 : :
30 : : #define MAX_PARAMS_PER_ENTRY 4
31 : :
32 : : #define MAX_TEST_CASES 16
33 : : static struct test_configure test_cases[MAX_TEST_CASES];
34 : :
35 : : #define GLOBAL_SECTION_NAME "GLOBAL"
36 : : struct global_configure global_cfg;
37 : :
38 : : static char *config_path;
39 : : static char *result_path;
40 : : static bool list_dma;
41 : :
42 : : __rte_format_printf(1, 2)
43 : : void
44 : 0 : output_csv(const char *fmt, ...)
45 : : {
46 : : #define MAX_OUTPUT_STR_LEN 512
47 : 0 : char str[MAX_OUTPUT_STR_LEN] = {0};
48 : : va_list ap;
49 : : FILE *fd;
50 : :
51 : 0 : fd = fopen(result_path, "a");
52 : 0 : if (fd == NULL) {
53 : : printf("Open output CSV file error.\n");
54 : 0 : return;
55 : : }
56 : :
57 : 0 : va_start(ap, fmt);
58 : : vsnprintf(str, MAX_OUTPUT_STR_LEN, fmt, ap);
59 : 0 : va_end(ap);
60 : :
61 : : fprintf(fd, "%s", str);
62 : :
63 : 0 : fflush(fd);
64 : 0 : fclose(fd);
65 : : }
66 : :
67 : : static void
68 : : output_blanklines(int lines)
69 : : {
70 : : int i;
71 : 0 : for (i = 0; i < lines; i++)
72 : 0 : output_csv("%s\n", ",,,,,,,,");
73 : : }
74 : :
75 : : static void
76 : 0 : output_env_info(void)
77 : : {
78 : : output_blanklines(2);
79 : 0 : output_csv("Test Environment:\n"
80 : : "CPU frequency,%.3lf Ghz\n", rte_get_timer_hz() / 1000000000.0);
81 : : output_blanklines(1);
82 : 0 : }
83 : :
84 : : static void
85 : : output_header(uint32_t case_id, struct test_configure *case_cfg)
86 : : {
87 : : static const char * const type_str[] = { "NONE", DMA_MEM_COPY, CPU_MEM_COPY };
88 : 0 : output_csv(CSV_HDR_FMT, case_id, type_str[case_cfg->test_type]);
89 : : }
90 : :
91 : : static int
92 : 0 : run_test_case(struct test_configure *case_cfg)
93 : : {
94 : : int ret = 0;
95 : :
96 : 0 : switch (case_cfg->test_type) {
97 : 0 : case TEST_TYPE_DMA_MEM_COPY:
98 : : case TEST_TYPE_CPU_MEM_COPY:
99 : 0 : ret = mem_copy_benchmark(case_cfg);
100 : 0 : break;
101 : : default:
102 : : printf("Unknown test type\n");
103 : : break;
104 : : }
105 : :
106 : 0 : return ret;
107 : : }
108 : :
109 : : static void
110 : 0 : run_test(uint32_t case_id, struct test_configure *case_cfg)
111 : : {
112 : 0 : uint32_t nb_lcores = rte_lcore_count();
113 : 0 : uint32_t main_lcore = rte_get_main_lcore();
114 : 0 : struct test_configure_entry *mem_size = &case_cfg->mem_size;
115 : 0 : struct test_configure_entry *buf_size = &case_cfg->buf_size;
116 : 0 : struct test_configure_entry *ring_size = &case_cfg->ring_size;
117 : 0 : struct test_configure_entry *kick_batch = &case_cfg->kick_batch;
118 : 0 : struct test_configure_entry dummy = { 0 };
119 : : struct test_configure_entry *var_entry = &dummy;
120 : :
121 : 0 : if (nb_lcores <= case_cfg->num_worker) {
122 : : printf("Case %u: Not enough lcores.\n", case_id);
123 : 0 : return;
124 : : }
125 : :
126 : 0 : for (uint32_t i = 0; i < case_cfg->num_worker; i++) {
127 : 0 : if (case_cfg->dma_config[i].lcore_dma_map.lcore == main_lcore) {
128 : : printf("Case %u: worker %u cannot run on the EAL main lcore (%u).\n",
129 : : case_id, i, main_lcore);
130 : 0 : return;
131 : : }
132 : : }
133 : :
134 : : printf("Number of used lcores: %u.\n", nb_lcores);
135 : :
136 : 0 : if (mem_size->incr != 0)
137 : : var_entry = mem_size;
138 : :
139 : 0 : if (buf_size->incr != 0)
140 : : var_entry = buf_size;
141 : :
142 : 0 : if (ring_size->incr != 0)
143 : : var_entry = ring_size;
144 : :
145 : 0 : if (kick_batch->incr != 0)
146 : : var_entry = kick_batch;
147 : :
148 : 0 : case_cfg->scenario_id = 0;
149 : :
150 : : output_header(case_id, case_cfg);
151 : :
152 : 0 : for (var_entry->cur = var_entry->first; var_entry->cur <= var_entry->last;) {
153 : 0 : case_cfg->scenario_id++;
154 : 0 : printf("\nRunning scenario %d\n", case_cfg->scenario_id);
155 : :
156 : 0 : if (run_test_case(case_cfg) < 0)
157 : : printf("\nTest fails! skipping this scenario.\n");
158 : :
159 : 0 : if (var_entry->op == OP_ADD)
160 : 0 : var_entry->cur += var_entry->incr;
161 : 0 : else if (var_entry->op == OP_MUL)
162 : 0 : var_entry->cur *= var_entry->incr;
163 : : else {
164 : : printf("No proper operation for variable entry.\n");
165 : : break;
166 : : }
167 : : }
168 : : }
169 : :
170 : : /* Exit process if the entry couldn't find in the section. */
171 : : static const char *
172 : 0 : get_cfgfile_entry(struct rte_cfgfile *cfgfile, const char *section_name, const char *entry_name)
173 : : {
174 : 0 : const char *entry = rte_cfgfile_get_entry(cfgfile, section_name, entry_name);
175 : 0 : if (entry == NULL) {
176 : : printf("Error: can't get entry '%s' in section '%s'\n", entry_name, section_name);
177 : 0 : exit(1);
178 : : }
179 : 0 : return entry;
180 : : }
181 : :
182 : : static int
183 : 0 : parse_lcore(struct test_configure *test_case, const char *value)
184 : : {
185 : : uint16_t len;
186 : : char *input;
187 : : struct lcore_dma_map_t *lcore_dma_map;
188 : :
189 : 0 : len = strlen(value);
190 : 0 : input = (char *)malloc((len + 1) * sizeof(char));
191 : : strlcpy(input, value, len + 1);
192 : :
193 : 0 : char *token = strtok(input, ", ");
194 : 0 : while (token != NULL) {
195 : 0 : lcore_dma_map = &(test_case->dma_config[test_case->num_worker++].lcore_dma_map);
196 : : memset(lcore_dma_map, 0, sizeof(struct lcore_dma_map_t));
197 : 0 : if (test_case->num_worker >= MAX_WORKER_NB) {
198 : 0 : free(input);
199 : 0 : return -1;
200 : : }
201 : :
202 : 0 : uint16_t lcore_id = atoi(token);
203 : 0 : lcore_dma_map->lcore = lcore_id;
204 : :
205 : 0 : token = strtok(NULL, ", ");
206 : : }
207 : :
208 : 0 : free(input);
209 : 0 : return 0;
210 : : }
211 : :
212 : : static void
213 : 0 : parse_cpu_config(struct test_configure *test_case, int case_id,
214 : : struct rte_cfgfile *cfgfile, char *section_name)
215 : : {
216 : 0 : const char *lcore = get_cfgfile_entry(cfgfile, section_name, "lcore");
217 : 0 : int lcore_ret = parse_lcore(test_case, lcore);
218 : 0 : if (lcore_ret < 0) {
219 : : printf("parse lcore error in case %d.\n", case_id);
220 : 0 : test_case->is_valid = false;
221 : : }
222 : 0 : }
223 : :
224 : : static int
225 : 0 : parse_entry(const char *value, struct test_configure_entry *entry)
226 : : {
227 : 0 : char input[255] = {0};
228 : : char *args[MAX_PARAMS_PER_ENTRY];
229 : : int args_nr = -1;
230 : : int ret;
231 : :
232 : : strlcpy(input, value, sizeof(input));
233 : 0 : if (*input == '\0')
234 : 0 : goto out;
235 : :
236 : 0 : ret = rte_strsplit(input, strlen(input), args, MAX_PARAMS_PER_ENTRY, ',');
237 : 0 : if (ret != 1 && ret != 4)
238 : 0 : goto out;
239 : :
240 : 0 : entry->cur = entry->first = (uint32_t)atoi(args[0]);
241 : :
242 : 0 : if (ret == 4) {
243 : : args_nr = 4;
244 : 0 : entry->last = (uint32_t)atoi(args[1]);
245 : 0 : entry->incr = (uint32_t)atoi(args[2]);
246 : 0 : if (!strcmp(args[3], "MUL"))
247 : 0 : entry->op = OP_MUL;
248 : 0 : else if (!strcmp(args[3], "ADD"))
249 : 0 : entry->op = OP_ADD;
250 : : else {
251 : : args_nr = -1;
252 : : printf("Invalid op %s.\n", args[3]);
253 : : }
254 : :
255 : : } else {
256 : : args_nr = 1;
257 : 0 : entry->op = OP_NONE;
258 : 0 : entry->last = 0;
259 : 0 : entry->incr = 0;
260 : : }
261 : 0 : out:
262 : 0 : return args_nr;
263 : : }
264 : :
265 : 0 : static int populate_dma_dev_config(const char *key, const char *value, void *test)
266 : : {
267 : : struct lcore_dma_config *dma_config = (struct lcore_dma_config *)test;
268 : : struct vchan_dev_config *vchan_config = &dma_config->vchan_dev;
269 : : struct lcore_dma_map_t *lcore_map = &dma_config->lcore_dma_map;
270 : : char *endptr;
271 : : int ret = 0;
272 : :
273 : 0 : if (strcmp(key, "lcore") == 0)
274 : 0 : lcore_map->lcore = (uint16_t)atoi(value);
275 : 0 : else if (strcmp(key, "dev") == 0)
276 : 0 : strlcpy(lcore_map->dma_names, value, RTE_DEV_NAME_MAX_LEN);
277 : 0 : else if (strcmp(key, "dir") == 0 && strcmp(value, "mem2mem") == 0)
278 : 0 : vchan_config->tdir = RTE_DMA_DIR_MEM_TO_MEM;
279 : 0 : else if (strcmp(key, "dir") == 0 && strcmp(value, "mem2dev") == 0)
280 : 0 : vchan_config->tdir = RTE_DMA_DIR_MEM_TO_DEV;
281 : 0 : else if (strcmp(key, "dir") == 0 && strcmp(value, "dev2mem") == 0)
282 : 0 : vchan_config->tdir = RTE_DMA_DIR_DEV_TO_MEM;
283 : 0 : else if (strcmp(key, "raddr") == 0)
284 : 0 : vchan_config->raddr = strtoull(value, &endptr, 16);
285 : 0 : else if (strcmp(key, "coreid") == 0)
286 : 0 : vchan_config->port.pcie.coreid = (uint8_t)atoi(value);
287 : 0 : else if (strcmp(key, "vfid") == 0)
288 : 0 : vchan_config->port.pcie.vfid = (uint16_t)atoi(value);
289 : 0 : else if (strcmp(key, "pfid") == 0)
290 : 0 : vchan_config->port.pcie.pfid = (uint16_t)atoi(value);
291 : : else {
292 : : printf("Invalid config param: %s\n", key);
293 : : ret = -1;
294 : : }
295 : :
296 : 0 : return ret;
297 : : }
298 : :
299 : : static void
300 : 0 : parse_dma_config(struct test_configure *test_case, int case_id,
301 : : struct rte_cfgfile *cfgfile, char *section_name, int *nb_vp)
302 : : {
303 : : const char *ring_size_str, *kick_batch_str, *src_sges_str, *dst_sges_str, *use_dma_ops;
304 : : char lc_dma[RTE_DEV_NAME_MAX_LEN];
305 : : struct rte_kvargs *kvlist;
306 : : const char *lcore_dma;
307 : : int args_nr;
308 : : int i;
309 : :
310 : 0 : use_dma_ops = rte_cfgfile_get_entry(cfgfile, section_name, "use_enq_deq_ops");
311 : 0 : test_case->use_ops = (use_dma_ops != NULL && (atoi(use_dma_ops) == 1));
312 : :
313 : 0 : ring_size_str = get_cfgfile_entry(cfgfile, section_name, "dma_ring_size");
314 : 0 : args_nr = parse_entry(ring_size_str, &test_case->ring_size);
315 : 0 : if (args_nr < 0) {
316 : : printf("parse error in case %d.\n", case_id);
317 : 0 : test_case->is_valid = false;
318 : 0 : return;
319 : 0 : } else if (args_nr == 4)
320 : 0 : *nb_vp += 1;
321 : :
322 : 0 : src_sges_str = rte_cfgfile_get_entry(cfgfile, section_name, "dma_src_sge");
323 : 0 : if (src_sges_str != NULL)
324 : 0 : test_case->nb_src_sges = (int)atoi(src_sges_str);
325 : :
326 : 0 : dst_sges_str = rte_cfgfile_get_entry(cfgfile, section_name, "dma_dst_sge");
327 : 0 : if (dst_sges_str != NULL)
328 : 0 : test_case->nb_dst_sges = (int)atoi(dst_sges_str);
329 : :
330 : 0 : if ((src_sges_str != NULL && dst_sges_str == NULL) ||
331 : : (src_sges_str == NULL && dst_sges_str != NULL)) {
332 : : printf("parse dma_src_sge, dma_dst_sge error in case %d.\n", case_id);
333 : 0 : test_case->is_valid = false;
334 : 0 : return;
335 : 0 : } else if (src_sges_str != NULL && dst_sges_str != NULL) {
336 : 0 : if (test_case->nb_src_sges == 0 || test_case->nb_dst_sges == 0) {
337 : : printf("dma_src_sge and dma_dst_sge can not be 0 in case %d.\n", case_id);
338 : 0 : test_case->is_valid = false;
339 : 0 : return;
340 : : }
341 : 0 : test_case->is_sg = true;
342 : : }
343 : :
344 : 0 : kick_batch_str = get_cfgfile_entry(cfgfile, section_name, "kick_batch");
345 : 0 : args_nr = parse_entry(kick_batch_str, &test_case->kick_batch);
346 : 0 : if (args_nr < 0) {
347 : : printf("parse error in case %d.\n", case_id);
348 : 0 : test_case->is_valid = false;
349 : 0 : return;
350 : 0 : } else if (args_nr == 4)
351 : 0 : *nb_vp += 1;
352 : :
353 : : i = 0;
354 : : while (1) {
355 : 0 : snprintf(lc_dma, RTE_DEV_NAME_MAX_LEN, "lcore_dma%d", i);
356 : 0 : lcore_dma = rte_cfgfile_get_entry(cfgfile, section_name, lc_dma);
357 : 0 : if (lcore_dma == NULL)
358 : : break;
359 : :
360 : 0 : kvlist = rte_kvargs_parse(lcore_dma, NULL);
361 : 0 : if (kvlist == NULL) {
362 : : printf("rte_kvargs_parse() error");
363 : 0 : test_case->is_valid = false;
364 : 0 : break;
365 : : }
366 : :
367 : 0 : if (rte_kvargs_process(kvlist, NULL, populate_dma_dev_config,
368 : 0 : (void *)&test_case->dma_config[i]) < 0) {
369 : : printf("rte_kvargs_process() error\n");
370 : 0 : rte_kvargs_free(kvlist);
371 : 0 : test_case->is_valid = false;
372 : 0 : break;
373 : : }
374 : 0 : i++;
375 : 0 : test_case->num_worker++;
376 : 0 : rte_kvargs_free(kvlist);
377 : : }
378 : :
379 : 0 : if (test_case->num_worker == 0) {
380 : : printf("Error: Parsing %s Failed\n", lc_dma);
381 : 0 : test_case->is_valid = false;
382 : : }
383 : : }
384 : :
385 : : static int
386 : 0 : parse_global_config(struct rte_cfgfile *cfgfile)
387 : : {
388 : : static char prog_name[] = "test-dma-perf";
389 : : char *tokens[MAX_EAL_ARGV_NB];
390 : : const char *entry;
391 : : int token_nb;
392 : : char *args;
393 : : int ret;
394 : : int i;
395 : :
396 : 0 : ret = rte_cfgfile_num_sections(cfgfile, GLOBAL_SECTION_NAME, strlen(GLOBAL_SECTION_NAME));
397 : 0 : if (ret != 1) {
398 : : printf("Error: GLOBAL section not exist or has multiple!\n");
399 : 0 : return -1;
400 : : }
401 : :
402 : 0 : entry = get_cfgfile_entry(cfgfile, GLOBAL_SECTION_NAME, "eal_args");
403 : 0 : args = strdup(entry);
404 : 0 : if (args == NULL) {
405 : : printf("Error: dup GLOBAL 'eal_args' failed!\n");
406 : 0 : return -1;
407 : : }
408 : 0 : token_nb = rte_strsplit(args, strlen(args), tokens, MAX_EAL_ARGV_NB, ' ');
409 : 0 : global_cfg.eal_argv[0] = prog_name;
410 : 0 : for (i = 0; i < token_nb; i++)
411 : 0 : global_cfg.eal_argv[i + 1] = tokens[i];
412 : 0 : global_cfg.eal_argc = i + 1;
413 : :
414 : 0 : entry = get_cfgfile_entry(cfgfile, GLOBAL_SECTION_NAME, "cache_flush");
415 : 0 : global_cfg.cache_flush = (uint8_t)atoi(entry);
416 : :
417 : 0 : entry = get_cfgfile_entry(cfgfile, GLOBAL_SECTION_NAME, "test_seconds");
418 : 0 : global_cfg.test_secs = (uint16_t)atoi(entry);
419 : :
420 : 0 : return 0;
421 : : }
422 : :
423 : : static uint16_t
424 : 0 : load_configs(const char *path)
425 : : {
426 : : const char *mem_size_str, *buf_size_str;
427 : : struct test_configure *test_case;
428 : : char section_name[CFG_NAME_LEN];
429 : : struct rte_cfgfile *cfgfile;
430 : : const char *case_type;
431 : : int nb_sections, i;
432 : : int args_nr, nb_vp;
433 : : const char *skip;
434 : :
435 : : printf("config file parsing...\n");
436 : 0 : cfgfile = rte_cfgfile_load(path, 0);
437 : 0 : if (!cfgfile) {
438 : : printf("Open configure file error.\n");
439 : 0 : exit(1);
440 : : }
441 : :
442 : 0 : if (parse_global_config(cfgfile) != 0)
443 : 0 : exit(1);
444 : :
445 : 0 : nb_sections = rte_cfgfile_num_sections(cfgfile, NULL, 0) - 1;
446 : 0 : if (nb_sections > MAX_TEST_CASES) {
447 : : printf("Error: The maximum number of cases is %d.\n", MAX_TEST_CASES);
448 : 0 : exit(1);
449 : : }
450 : :
451 : 0 : for (i = 0; i < nb_sections; i++) {
452 : 0 : snprintf(section_name, CFG_NAME_LEN, "case%d", i + 1);
453 : 0 : test_case = &test_cases[i];
454 : :
455 : 0 : skip = rte_cfgfile_get_entry(cfgfile, section_name, "skip");
456 : 0 : if (skip && (atoi(skip) == 1)) {
457 : 0 : test_case->is_skip = true;
458 : 0 : continue;
459 : : }
460 : :
461 : 0 : test_case->is_valid = true;
462 : 0 : case_type = get_cfgfile_entry(cfgfile, section_name, "type");
463 : 0 : if (strcmp(case_type, DMA_MEM_COPY) == 0) {
464 : 0 : test_case->test_type = TEST_TYPE_DMA_MEM_COPY;
465 : 0 : } else if (strcmp(case_type, CPU_MEM_COPY) == 0) {
466 : 0 : test_case->test_type = TEST_TYPE_CPU_MEM_COPY;
467 : : } else {
468 : : printf("Error: Wrong test case type %s in case%d.\n", case_type, i + 1);
469 : 0 : test_case->is_valid = false;
470 : 0 : continue;
471 : : }
472 : :
473 : 0 : test_case->src_numa_node = (int)atoi(get_cfgfile_entry(cfgfile,
474 : : section_name, "src_numa_node"));
475 : 0 : test_case->dst_numa_node = (int)atoi(get_cfgfile_entry(cfgfile,
476 : : section_name, "dst_numa_node"));
477 : 0 : nb_vp = 0;
478 : 0 : mem_size_str = get_cfgfile_entry(cfgfile, section_name, "mem_size");
479 : 0 : args_nr = parse_entry(mem_size_str, &test_case->mem_size);
480 : 0 : if (args_nr < 0) {
481 : : printf("parse error in case %d.\n", i + 1);
482 : 0 : test_case->is_valid = false;
483 : 0 : continue;
484 : 0 : } else if (args_nr == 4)
485 : 0 : nb_vp++;
486 : :
487 : 0 : buf_size_str = get_cfgfile_entry(cfgfile, section_name, "buf_size");
488 : 0 : args_nr = parse_entry(buf_size_str, &test_case->buf_size);
489 : 0 : if (args_nr < 0) {
490 : : printf("parse error in case %d.\n", i + 1);
491 : 0 : test_case->is_valid = false;
492 : 0 : continue;
493 : 0 : } else if (args_nr == 4)
494 : 0 : nb_vp++;
495 : :
496 : 0 : if (test_case->test_type == TEST_TYPE_DMA_MEM_COPY)
497 : 0 : parse_dma_config(test_case, i + 1, cfgfile, section_name, &nb_vp);
498 : : else
499 : 0 : parse_cpu_config(test_case, i + 1, cfgfile, section_name);
500 : :
501 : 0 : if (test_case->is_valid && nb_vp > 1) {
502 : : printf("Case %d error, each section can only have a single variable parameter.\n",
503 : : i + 1);
504 : 0 : test_case->is_valid = false;
505 : 0 : continue;
506 : : }
507 : : }
508 : :
509 : 0 : rte_cfgfile_close(cfgfile);
510 : : printf("config file parsing complete.\n\n");
511 : 0 : return i;
512 : : }
513 : :
514 : : static int
515 : 0 : parse_args(int argc, char **argv)
516 : : {
517 : : static struct rte_argparse obj = {
518 : : .prog_name = "test-dma-perf",
519 : : .usage = "[optional parameters]",
520 : : .descriptor = NULL,
521 : : .epilog = NULL,
522 : : .exit_on_error = true,
523 : : .args = {
524 : : { "--config", NULL, "Specify a configuration file",
525 : : (void *)&config_path, NULL,
526 : : RTE_ARGPARSE_VALUE_REQUIRED, RTE_ARGPARSE_VALUE_TYPE_STR,
527 : : },
528 : : { "--result", NULL, "Optional, specify a result file name",
529 : : (void *)&result_path, NULL,
530 : : RTE_ARGPARSE_VALUE_REQUIRED, RTE_ARGPARSE_VALUE_TYPE_STR,
531 : : },
532 : : { "--list-dma", NULL, "Optional, list dma devices and exit",
533 : : (void *)&list_dma, (void *)true,
534 : : RTE_ARGPARSE_VALUE_NONE, RTE_ARGPARSE_VALUE_TYPE_BOOL,
535 : : },
536 : : ARGPARSE_ARG_END(),
537 : : },
538 : : };
539 : 0 : char rst_path[PATH_MAX + 16] = {0};
540 : : FILE *fd;
541 : : int ret;
542 : :
543 : 0 : ret = rte_argparse_parse(&obj, argc, argv);
544 : 0 : if (ret < 0)
545 : 0 : exit(1);
546 : :
547 : 0 : if (config_path == NULL) {
548 : : printf("Config file not assigned.\n");
549 : 0 : exit(1);
550 : : }
551 : :
552 : 0 : if (result_path == NULL) {
553 : 0 : rte_basename(config_path, rst_path, sizeof(rst_path));
554 : 0 : char *token = strtok(rst_path, ".");
555 : 0 : if (token == NULL) {
556 : : printf("Config file error.\n");
557 : 0 : return -1;
558 : : }
559 : 0 : strlcat(token, "_result.csv", sizeof(rst_path));
560 : 0 : result_path = strdup(rst_path);
561 : 0 : if (result_path == NULL) {
562 : : printf("Generate result file path error.\n");
563 : 0 : exit(1);
564 : : }
565 : : }
566 : 0 : fd = fopen(result_path, "w");
567 : 0 : if (fd == NULL) {
568 : : printf("Open output CSV file error.\n");
569 : 0 : exit(1);
570 : : }
571 : 0 : fclose(fd);
572 : :
573 : 0 : return 0;
574 : : }
575 : :
576 : : static void
577 : 0 : list_dma_dev(void)
578 : : {
579 : : static const struct {
580 : : uint64_t capability;
581 : : const char *name;
582 : : } capa_names[] = {
583 : : { RTE_DMA_CAPA_MEM_TO_MEM, "mem2mem" },
584 : : { RTE_DMA_CAPA_MEM_TO_DEV, "mem2dev" },
585 : : { RTE_DMA_CAPA_DEV_TO_MEM, "dev2mem" },
586 : : { RTE_DMA_CAPA_DEV_TO_DEV, "dev2dev" },
587 : : };
588 : : struct rte_dma_info info;
589 : : uint32_t count = 0;
590 : : int idx = 0;
591 : : uint32_t i;
592 : : int ret;
593 : :
594 : 0 : ret = rte_eal_init(global_cfg.eal_argc, global_cfg.eal_argv);
595 : 0 : if (ret < 0)
596 : 0 : rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
597 : :
598 : 0 : RTE_DMA_FOREACH_DEV(idx) {
599 : 0 : ret = rte_dma_info_get(idx, &info);
600 : 0 : if (ret != 0)
601 : 0 : continue;
602 : :
603 : 0 : printf("\nDMA device name: %s\n", info.dev_name);
604 : : printf(" transfer-capa:");
605 : 0 : for (i = 0; i < RTE_DIM(capa_names); i++) {
606 : 0 : if (capa_names[i].capability & info.dev_capa)
607 : 0 : printf(" %s", capa_names[i].name);
608 : : }
609 : : printf("\n");
610 : 0 : printf(" max-segs: %u numa-node: %d min-desc: %u max-desc: %u\n",
611 : 0 : info.max_sges, info.numa_node, info.min_desc, info.max_desc);
612 : 0 : count++;
613 : : }
614 : :
615 : : printf("\n");
616 : 0 : if (count == 0)
617 : : printf("There are no dmadev devices!\n\n");
618 : :
619 : 0 : rte_eal_cleanup();
620 : 0 : }
621 : :
622 : : int
623 : 0 : main(int argc, char *argv[])
624 : : {
625 : : uint32_t i, nb_lcores;
626 : : pid_t cpid, wpid;
627 : : uint16_t case_nb;
628 : : int wstatus;
629 : : int ret;
630 : :
631 : 0 : parse_args(argc, argv);
632 : :
633 : 0 : case_nb = load_configs(config_path);
634 : :
635 : 0 : if (list_dma) {
636 : 0 : list_dma_dev();
637 : 0 : return 0;
638 : : }
639 : :
640 : : printf("Running cases...\n");
641 : 0 : for (i = 0; i < case_nb; i++) {
642 : 0 : if (test_cases[i].is_skip) {
643 : 0 : printf("Test case %d configured to be skipped.\n\n", i + 1);
644 : : output_blanklines(2);
645 : 0 : output_csv("Skip the test-case %d\n", i + 1);
646 : 0 : continue;
647 : : }
648 : :
649 : 0 : if (!test_cases[i].is_valid) {
650 : 0 : printf("Invalid test case %d.\n\n", i + 1);
651 : : output_blanklines(2);
652 : 0 : output_csv("Invalid case %d\n", i + 1);
653 : 0 : continue;
654 : : }
655 : :
656 : 0 : cpid = fork();
657 : 0 : if (cpid < 0) {
658 : 0 : printf("Fork case %d failed.\n", i + 1);
659 : 0 : exit(EXIT_FAILURE);
660 : 0 : } else if (cpid == 0) {
661 : 0 : printf("\nRunning case %u\n\n", i + 1);
662 : :
663 : 0 : ret = rte_eal_init(global_cfg.eal_argc, global_cfg.eal_argv);
664 : 0 : if (ret < 0)
665 : 0 : rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
666 : :
667 : : /* Check lcores. */
668 : 0 : nb_lcores = rte_lcore_count();
669 : 0 : if (nb_lcores < 2)
670 : 0 : rte_exit(EXIT_FAILURE,
671 : : "There should be at least 2 worker lcores.\n");
672 : :
673 : 0 : output_env_info();
674 : :
675 : 0 : run_test(i + 1, &test_cases[i]);
676 : :
677 : : /* clean up the EAL */
678 : 0 : rte_eal_cleanup();
679 : :
680 : : printf("\nCase %u completed.\n\n", i + 1);
681 : :
682 : 0 : exit(EXIT_SUCCESS);
683 : : } else {
684 : 0 : wpid = waitpid(cpid, &wstatus, 0);
685 : 0 : if (wpid == -1) {
686 : : printf("waitpid error.\n");
687 : 0 : exit(EXIT_FAILURE);
688 : : }
689 : :
690 : 0 : if (WIFEXITED(wstatus))
691 : 0 : printf("Case process exited. status %d\n\n",
692 : 0 : WEXITSTATUS(wstatus));
693 : 0 : else if (WIFSIGNALED(wstatus))
694 : : printf("Case process killed by signal %d\n\n",
695 : : WTERMSIG(wstatus));
696 : 0 : else if (WIFSTOPPED(wstatus))
697 : 0 : printf("Case process stopped by signal %d\n\n",
698 : 0 : WSTOPSIG(wstatus));
699 : 0 : else if (WIFCONTINUED(wstatus))
700 : : printf("Case process continued.\n\n");
701 : : else
702 : : printf("Case process unknown terminated.\n\n");
703 : : }
704 : : }
705 : :
706 : : printf("Bye...\n");
707 : 0 : return 0;
708 : : }
|