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_eal.h>
16 : : #include <rte_cfgfile.h>
17 : : #include <rte_string_fns.h>
18 : : #include <rte_lcore.h>
19 : : #include <rte_dmadev.h>
20 : : #include <rte_kvargs.h>
21 : :
22 : : #include "main.h"
23 : :
24 : : #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"
25 : :
26 : : #define MAX_EAL_PARAM_NB 100
27 : : #define MAX_EAL_PARAM_LEN 1024
28 : :
29 : : #define DMA_MEM_COPY "DMA_MEM_COPY"
30 : : #define CPU_MEM_COPY "CPU_MEM_COPY"
31 : :
32 : : #define CMDLINE_CONFIG_ARG "--config"
33 : : #define CMDLINE_RESULT_ARG "--result"
34 : :
35 : : #define MAX_PARAMS_PER_ENTRY 4
36 : :
37 : : #define MAX_LONG_OPT_SZ 64
38 : :
39 : : enum {
40 : : TEST_TYPE_NONE = 0,
41 : : TEST_TYPE_DMA_MEM_COPY,
42 : : TEST_TYPE_CPU_MEM_COPY
43 : : };
44 : :
45 : : #define MAX_TEST_CASES 16
46 : : static struct test_configure test_cases[MAX_TEST_CASES];
47 : :
48 : : char output_str[MAX_WORKER_NB + 1][MAX_OUTPUT_STR_LEN];
49 : :
50 : : static FILE *fd;
51 : :
52 : : static void
53 : 0 : output_csv(bool need_blankline)
54 : : {
55 : : uint32_t i;
56 : :
57 : 0 : if (need_blankline) {
58 : 0 : fprintf(fd, ",,,,,,,,\n");
59 : 0 : fprintf(fd, ",,,,,,,,\n");
60 : : }
61 : :
62 : 0 : for (i = 0; i < RTE_DIM(output_str); i++) {
63 : 0 : if (output_str[i][0]) {
64 : 0 : fprintf(fd, "%s", output_str[i]);
65 : 0 : output_str[i][0] = '\0';
66 : : }
67 : : }
68 : :
69 : 0 : fflush(fd);
70 : 0 : }
71 : :
72 : : static void
73 : 0 : output_env_info(void)
74 : : {
75 : : snprintf(output_str[0], MAX_OUTPUT_STR_LEN, "Test Environment:\n");
76 : 0 : snprintf(output_str[1], MAX_OUTPUT_STR_LEN, "CPU frequency,%.3lf Ghz",
77 : : rte_get_timer_hz() / 1000000000.0);
78 : :
79 : 0 : output_csv(true);
80 : 0 : }
81 : :
82 : : static void
83 : 0 : output_header(uint32_t case_id, struct test_configure *case_cfg)
84 : : {
85 : 0 : snprintf(output_str[0], MAX_OUTPUT_STR_LEN,
86 : : CSV_HDR_FMT, case_id, case_cfg->test_type_str);
87 : :
88 : 0 : output_csv(true);
89 : 0 : }
90 : :
91 : : static int
92 : 0 : open_output_csv(const char *rst_path_ptr)
93 : : {
94 : 0 : fd = fopen(rst_path_ptr, "a");
95 : 0 : if (!fd) {
96 : : printf("Open output CSV file error.\n");
97 : 0 : return 1;
98 : : }
99 : 0 : output_csv(true);
100 : 0 : fclose(fd);
101 : 0 : return 0;
102 : : }
103 : :
104 : : static int
105 : 0 : run_test_case(struct test_configure *case_cfg)
106 : : {
107 : : int ret = 0;
108 : :
109 : 0 : switch (case_cfg->test_type) {
110 : 0 : case TEST_TYPE_DMA_MEM_COPY:
111 : : case TEST_TYPE_CPU_MEM_COPY:
112 : 0 : ret = mem_copy_benchmark(case_cfg);
113 : 0 : break;
114 : 0 : default:
115 : 0 : printf("Unknown test type. %s\n", case_cfg->test_type_str);
116 : : break;
117 : : }
118 : :
119 : 0 : return ret;
120 : : }
121 : :
122 : : static void
123 : 0 : run_test(uint32_t case_id, struct test_configure *case_cfg)
124 : : {
125 : : uint32_t i;
126 : 0 : uint32_t nb_lcores = rte_lcore_count();
127 : 0 : struct test_configure_entry *mem_size = &case_cfg->mem_size;
128 : 0 : struct test_configure_entry *buf_size = &case_cfg->buf_size;
129 : 0 : struct test_configure_entry *ring_size = &case_cfg->ring_size;
130 : 0 : struct test_configure_entry *kick_batch = &case_cfg->kick_batch;
131 : 0 : struct test_configure_entry dummy = { 0 };
132 : : struct test_configure_entry *var_entry = &dummy;
133 : :
134 : 0 : for (i = 0; i < RTE_DIM(output_str); i++)
135 : 0 : memset(output_str[i], 0, MAX_OUTPUT_STR_LEN);
136 : :
137 : 0 : if (nb_lcores <= case_cfg->lcore_dma_map.cnt) {
138 : : printf("Case %u: Not enough lcores.\n", case_id);
139 : 0 : return;
140 : : }
141 : :
142 : : printf("Number of used lcores: %u.\n", nb_lcores);
143 : :
144 : 0 : if (mem_size->incr != 0)
145 : : var_entry = mem_size;
146 : :
147 : 0 : if (buf_size->incr != 0)
148 : : var_entry = buf_size;
149 : :
150 : 0 : if (ring_size->incr != 0)
151 : : var_entry = ring_size;
152 : :
153 : 0 : if (kick_batch->incr != 0)
154 : : var_entry = kick_batch;
155 : :
156 : 0 : case_cfg->scenario_id = 0;
157 : :
158 : 0 : output_header(case_id, case_cfg);
159 : :
160 : 0 : for (var_entry->cur = var_entry->first; var_entry->cur <= var_entry->last;) {
161 : 0 : case_cfg->scenario_id++;
162 : 0 : printf("\nRunning scenario %d\n", case_cfg->scenario_id);
163 : :
164 : 0 : if (run_test_case(case_cfg) < 0)
165 : : printf("\nTest fails! skipping this scenario.\n");
166 : : else
167 : 0 : output_csv(false);
168 : :
169 : 0 : if (var_entry->op == OP_ADD)
170 : 0 : var_entry->cur += var_entry->incr;
171 : 0 : else if (var_entry->op == OP_MUL)
172 : 0 : var_entry->cur *= var_entry->incr;
173 : : else {
174 : : printf("No proper operation for variable entry.\n");
175 : : break;
176 : : }
177 : : }
178 : : }
179 : :
180 : : static int
181 : 0 : parse_lcore(struct test_configure *test_case, const char *value)
182 : : {
183 : : uint16_t len;
184 : : char *input;
185 : : struct lcore_dma_map_t *lcore_dma_map;
186 : :
187 : 0 : if (test_case == NULL || value == NULL)
188 : : return -1;
189 : :
190 : 0 : len = strlen(value);
191 : 0 : input = (char *)malloc((len + 1) * sizeof(char));
192 : : strlcpy(input, value, len + 1);
193 : 0 : lcore_dma_map = &(test_case->lcore_dma_map);
194 : :
195 : : memset(lcore_dma_map, 0, sizeof(struct lcore_dma_map_t));
196 : :
197 : 0 : char *token = strtok(input, ", ");
198 : 0 : while (token != NULL) {
199 : 0 : if (lcore_dma_map->cnt >= MAX_WORKER_NB) {
200 : 0 : free(input);
201 : 0 : return -1;
202 : : }
203 : :
204 : 0 : uint16_t lcore_id = atoi(token);
205 : 0 : lcore_dma_map->lcores[lcore_dma_map->cnt++] = lcore_id;
206 : :
207 : 0 : token = strtok(NULL, ", ");
208 : : }
209 : :
210 : 0 : free(input);
211 : 0 : return 0;
212 : : }
213 : :
214 : : static int
215 : 0 : parse_lcore_dma(struct test_configure *test_case, const char *value)
216 : : {
217 : : struct lcore_dma_map_t *lcore_dma_map;
218 : : char *input, *addrs;
219 : : char *ptrs[2];
220 : : char *start, *end, *substr;
221 : : uint16_t lcore_id;
222 : : int ret = 0;
223 : :
224 : 0 : if (test_case == NULL || value == NULL)
225 : : return -1;
226 : :
227 : 0 : input = strndup(value, strlen(value) + 1);
228 : 0 : if (input == NULL)
229 : : return -1;
230 : : addrs = input;
231 : :
232 : 0 : while (*addrs == '\0')
233 : 0 : addrs++;
234 : : if (*addrs == '\0') {
235 : : fprintf(stderr, "No input DMA addresses\n");
236 : : ret = -1;
237 : : goto out;
238 : : }
239 : :
240 : 0 : substr = strtok(addrs, ",");
241 : 0 : if (substr == NULL) {
242 : 0 : fprintf(stderr, "No input DMA address\n");
243 : : ret = -1;
244 : 0 : goto out;
245 : : }
246 : :
247 : 0 : memset(&test_case->lcore_dma_map, 0, sizeof(struct lcore_dma_map_t));
248 : :
249 : : do {
250 : 0 : if (rte_strsplit(substr, strlen(substr), ptrs, 2, '@') < 0) {
251 : 0 : fprintf(stderr, "Illegal DMA address\n");
252 : : ret = -1;
253 : 0 : break;
254 : : }
255 : :
256 : 0 : start = strstr(ptrs[0], "lcore");
257 : 0 : if (start == NULL) {
258 : 0 : fprintf(stderr, "Illegal lcore\n");
259 : : ret = -1;
260 : 0 : break;
261 : : }
262 : :
263 : 0 : start += 5;
264 : 0 : lcore_id = strtol(start, &end, 0);
265 : 0 : if (end == start) {
266 : 0 : fprintf(stderr, "No input lcore ID or ID %d is wrong\n", lcore_id);
267 : : ret = -1;
268 : 0 : break;
269 : : }
270 : :
271 : : lcore_dma_map = &test_case->lcore_dma_map;
272 : 0 : if (lcore_dma_map->cnt >= MAX_WORKER_NB) {
273 : 0 : fprintf(stderr, "lcores count error\n");
274 : : ret = -1;
275 : 0 : break;
276 : : }
277 : :
278 : 0 : lcore_dma_map->lcores[lcore_dma_map->cnt] = lcore_id;
279 : 0 : strlcpy(lcore_dma_map->dma_names[lcore_dma_map->cnt], ptrs[1],
280 : : RTE_DEV_NAME_MAX_LEN);
281 : 0 : lcore_dma_map->cnt++;
282 : 0 : substr = strtok(NULL, ",");
283 : 0 : } while (substr != NULL);
284 : :
285 : 0 : out:
286 : 0 : free(input);
287 : 0 : return ret;
288 : : }
289 : :
290 : : static int
291 : 0 : parse_entry(const char *value, struct test_configure_entry *entry)
292 : : {
293 : 0 : char input[255] = {0};
294 : : char *args[MAX_PARAMS_PER_ENTRY];
295 : : int args_nr = -1;
296 : : int ret;
297 : :
298 : 0 : if (value == NULL || entry == NULL)
299 : 0 : goto out;
300 : :
301 : : strncpy(input, value, 254);
302 : 0 : if (*input == '\0')
303 : 0 : goto out;
304 : :
305 : 0 : ret = rte_strsplit(input, strlen(input), args, MAX_PARAMS_PER_ENTRY, ',');
306 : 0 : if (ret != 1 && ret != 4)
307 : 0 : goto out;
308 : :
309 : 0 : entry->cur = entry->first = (uint32_t)atoi(args[0]);
310 : :
311 : 0 : if (ret == 4) {
312 : : args_nr = 4;
313 : 0 : entry->last = (uint32_t)atoi(args[1]);
314 : 0 : entry->incr = (uint32_t)atoi(args[2]);
315 : 0 : if (!strcmp(args[3], "MUL"))
316 : 0 : entry->op = OP_MUL;
317 : 0 : else if (!strcmp(args[3], "ADD"))
318 : 0 : entry->op = OP_ADD;
319 : : else {
320 : : args_nr = -1;
321 : : printf("Invalid op %s.\n", args[3]);
322 : : }
323 : :
324 : : } else {
325 : : args_nr = 1;
326 : 0 : entry->op = OP_NONE;
327 : 0 : entry->last = 0;
328 : 0 : entry->incr = 0;
329 : : }
330 : 0 : out:
331 : 0 : return args_nr;
332 : : }
333 : :
334 : 0 : static int populate_pcie_config(const char *key, const char *value, void *test)
335 : : {
336 : : struct test_configure *test_case = (struct test_configure *)test;
337 : : char *endptr;
338 : : int ret = 0;
339 : :
340 : 0 : if (strcmp(key, "raddr") == 0)
341 : 0 : test_case->vchan_dev.raddr = strtoull(value, &endptr, 16);
342 : 0 : else if (strcmp(key, "coreid") == 0)
343 : 0 : test_case->vchan_dev.port.pcie.coreid = (uint8_t)atoi(value);
344 : 0 : else if (strcmp(key, "vfid") == 0)
345 : 0 : test_case->vchan_dev.port.pcie.vfid = (uint16_t)atoi(value);
346 : 0 : else if (strcmp(key, "pfid") == 0)
347 : 0 : test_case->vchan_dev.port.pcie.pfid = (uint16_t)atoi(value);
348 : : else {
349 : : printf("Invalid config param: %s\n", key);
350 : : ret = -1;
351 : : }
352 : :
353 : 0 : return ret;
354 : : }
355 : :
356 : : static uint16_t
357 : 0 : load_configs(const char *path)
358 : : {
359 : : struct rte_cfgfile *cfgfile;
360 : : int nb_sections, i;
361 : : struct test_configure *test_case;
362 : : char section_name[CFG_NAME_LEN];
363 : : const char *case_type;
364 : : const char *transfer_dir;
365 : : const char *lcore_dma;
366 : : const char *mem_size_str, *buf_size_str, *ring_size_str, *kick_batch_str,
367 : : *src_sges_str, *dst_sges_str;
368 : : const char *skip;
369 : : struct rte_kvargs *kvlist;
370 : : const char *vchan_dev;
371 : : int args_nr, nb_vp;
372 : : bool is_dma;
373 : :
374 : : printf("config file parsing...\n");
375 : 0 : cfgfile = rte_cfgfile_load(path, 0);
376 : 0 : if (!cfgfile) {
377 : : printf("Open configure file error.\n");
378 : 0 : exit(1);
379 : : }
380 : :
381 : 0 : nb_sections = rte_cfgfile_num_sections(cfgfile, NULL, 0);
382 : 0 : if (nb_sections > MAX_TEST_CASES) {
383 : : printf("Error: The maximum number of cases is %d.\n", MAX_TEST_CASES);
384 : 0 : exit(1);
385 : : }
386 : :
387 : 0 : for (i = 0; i < nb_sections; i++) {
388 : 0 : snprintf(section_name, CFG_NAME_LEN, "case%d", i + 1);
389 : 0 : test_case = &test_cases[i];
390 : :
391 : 0 : skip = rte_cfgfile_get_entry(cfgfile, section_name, "skip");
392 : 0 : if (skip && (atoi(skip) == 1)) {
393 : 0 : test_case->is_skip = true;
394 : 0 : continue;
395 : : }
396 : :
397 : 0 : case_type = rte_cfgfile_get_entry(cfgfile, section_name, "type");
398 : 0 : if (case_type == NULL) {
399 : : printf("Error: No case type in case %d, the test will be finished here.\n",
400 : : i + 1);
401 : 0 : test_case->is_valid = false;
402 : 0 : continue;
403 : : }
404 : :
405 : 0 : if (strcmp(case_type, DMA_MEM_COPY) == 0) {
406 : 0 : test_case->test_type = TEST_TYPE_DMA_MEM_COPY;
407 : 0 : test_case->test_type_str = DMA_MEM_COPY;
408 : :
409 : 0 : transfer_dir = rte_cfgfile_get_entry(cfgfile, section_name, "direction");
410 : 0 : if (transfer_dir == NULL) {
411 : : printf("Transfer direction not configured."
412 : : " Defaulting it to MEM to MEM transfer.\n");
413 : 0 : test_case->transfer_dir = RTE_DMA_DIR_MEM_TO_MEM;
414 : : } else {
415 : 0 : if (strcmp(transfer_dir, "mem2dev") == 0)
416 : 0 : test_case->transfer_dir = RTE_DMA_DIR_MEM_TO_DEV;
417 : 0 : else if (strcmp(transfer_dir, "dev2mem") == 0)
418 : 0 : test_case->transfer_dir = RTE_DMA_DIR_DEV_TO_MEM;
419 : : else {
420 : : printf("Defaulting the test to MEM to MEM transfer\n");
421 : 0 : test_case->transfer_dir = RTE_DMA_DIR_MEM_TO_MEM;
422 : : }
423 : : }
424 : : is_dma = true;
425 : 0 : } else if (strcmp(case_type, CPU_MEM_COPY) == 0) {
426 : 0 : test_case->test_type = TEST_TYPE_CPU_MEM_COPY;
427 : 0 : test_case->test_type_str = CPU_MEM_COPY;
428 : : is_dma = false;
429 : : } else {
430 : : printf("Error: Wrong test case type %s in case%d.\n", case_type, i + 1);
431 : 0 : test_case->is_valid = false;
432 : 0 : continue;
433 : : }
434 : :
435 : 0 : if (test_case->transfer_dir == RTE_DMA_DIR_MEM_TO_DEV ||
436 : : test_case->transfer_dir == RTE_DMA_DIR_DEV_TO_MEM) {
437 : 0 : vchan_dev = rte_cfgfile_get_entry(cfgfile, section_name, "vchan_dev");
438 : 0 : if (vchan_dev == NULL) {
439 : : printf("Transfer direction mem2dev and dev2mem"
440 : : " vhcan_dev shall be configured.\n");
441 : 0 : test_case->is_valid = false;
442 : 0 : continue;
443 : : }
444 : :
445 : 0 : kvlist = rte_kvargs_parse(vchan_dev, NULL);
446 : 0 : if (kvlist == NULL) {
447 : : printf("rte_kvargs_parse() error");
448 : 0 : test_case->is_valid = false;
449 : 0 : continue;
450 : : }
451 : :
452 : 0 : if (rte_kvargs_process(kvlist, NULL, populate_pcie_config,
453 : : (void *)test_case) < 0) {
454 : : printf("rte_kvargs_process() error\n");
455 : 0 : rte_kvargs_free(kvlist);
456 : 0 : test_case->is_valid = false;
457 : 0 : continue;
458 : : }
459 : :
460 : 0 : if (!test_case->vchan_dev.raddr) {
461 : : printf("For mem2dev and dev2mem configure raddr\n");
462 : 0 : rte_kvargs_free(kvlist);
463 : 0 : test_case->is_valid = false;
464 : 0 : continue;
465 : : }
466 : 0 : rte_kvargs_free(kvlist);
467 : : }
468 : :
469 : 0 : test_case->is_dma = is_dma;
470 : 0 : test_case->src_numa_node = (int)atoi(rte_cfgfile_get_entry(cfgfile,
471 : : section_name, "src_numa_node"));
472 : 0 : test_case->dst_numa_node = (int)atoi(rte_cfgfile_get_entry(cfgfile,
473 : : section_name, "dst_numa_node"));
474 : : nb_vp = 0;
475 : 0 : mem_size_str = rte_cfgfile_get_entry(cfgfile, section_name, "mem_size");
476 : 0 : args_nr = parse_entry(mem_size_str, &test_case->mem_size);
477 : 0 : if (args_nr < 0) {
478 : : printf("parse error in case %d.\n", i + 1);
479 : 0 : test_case->is_valid = false;
480 : 0 : continue;
481 : 0 : } else if (args_nr == 4)
482 : : nb_vp++;
483 : :
484 : 0 : buf_size_str = rte_cfgfile_get_entry(cfgfile, section_name, "buf_size");
485 : 0 : args_nr = parse_entry(buf_size_str, &test_case->buf_size);
486 : 0 : if (args_nr < 0) {
487 : : printf("parse error in case %d.\n", i + 1);
488 : 0 : test_case->is_valid = false;
489 : 0 : continue;
490 : 0 : } else if (args_nr == 4)
491 : 0 : nb_vp++;
492 : :
493 : 0 : if (is_dma) {
494 : 0 : ring_size_str = rte_cfgfile_get_entry(cfgfile, section_name,
495 : : "dma_ring_size");
496 : 0 : args_nr = parse_entry(ring_size_str, &test_case->ring_size);
497 : 0 : if (args_nr < 0) {
498 : : printf("parse error in case %d.\n", i + 1);
499 : 0 : test_case->is_valid = false;
500 : 0 : continue;
501 : 0 : } else if (args_nr == 4)
502 : 0 : nb_vp++;
503 : :
504 : 0 : src_sges_str = rte_cfgfile_get_entry(cfgfile, section_name,
505 : : "dma_src_sge");
506 : 0 : if (src_sges_str != NULL) {
507 : 0 : test_case->nb_src_sges = (int)atoi(rte_cfgfile_get_entry(cfgfile,
508 : : section_name, "dma_src_sge"));
509 : : }
510 : :
511 : 0 : dst_sges_str = rte_cfgfile_get_entry(cfgfile, section_name,
512 : : "dma_dst_sge");
513 : 0 : if (dst_sges_str != NULL) {
514 : 0 : test_case->nb_dst_sges = (int)atoi(rte_cfgfile_get_entry(cfgfile,
515 : : section_name, "dma_dst_sge"));
516 : : }
517 : :
518 : 0 : if ((src_sges_str != NULL && dst_sges_str == NULL) ||
519 : : (src_sges_str == NULL && dst_sges_str != NULL)) {
520 : : printf("parse dma_src_sge, dma_dst_sge error in case %d.\n",
521 : : i + 1);
522 : 0 : test_case->is_valid = false;
523 : 0 : continue;
524 : 0 : } else if (src_sges_str != NULL && dst_sges_str != NULL) {
525 : 0 : test_case->is_sg = true;
526 : :
527 : 0 : if (test_case->nb_src_sges == 0 || test_case->nb_dst_sges == 0) {
528 : : printf("dma_src_sge and dma_dst_sge can not be 0 in case %d.\n",
529 : : i + 1);
530 : 0 : test_case->is_valid = false;
531 : 0 : continue;
532 : : }
533 : : } else {
534 : 0 : test_case->is_sg = false;
535 : : }
536 : :
537 : 0 : kick_batch_str = rte_cfgfile_get_entry(cfgfile, section_name, "kick_batch");
538 : 0 : args_nr = parse_entry(kick_batch_str, &test_case->kick_batch);
539 : 0 : if (args_nr < 0) {
540 : : printf("parse error in case %d.\n", i + 1);
541 : 0 : test_case->is_valid = false;
542 : 0 : continue;
543 : 0 : } else if (args_nr == 4)
544 : 0 : nb_vp++;
545 : :
546 : 0 : lcore_dma = rte_cfgfile_get_entry(cfgfile, section_name, "lcore_dma");
547 : 0 : int lcore_ret = parse_lcore_dma(test_case, lcore_dma);
548 : 0 : if (lcore_ret < 0) {
549 : : printf("parse lcore dma error in case %d.\n", i + 1);
550 : 0 : test_case->is_valid = false;
551 : 0 : continue;
552 : : }
553 : : } else {
554 : 0 : lcore_dma = rte_cfgfile_get_entry(cfgfile, section_name, "lcore");
555 : 0 : int lcore_ret = parse_lcore(test_case, lcore_dma);
556 : 0 : if (lcore_ret < 0) {
557 : : printf("parse lcore error in case %d.\n", i + 1);
558 : 0 : test_case->is_valid = false;
559 : 0 : continue;
560 : : }
561 : : }
562 : :
563 : 0 : if (nb_vp > 1) {
564 : : printf("Case %d error, each section can only have a single variable parameter.\n",
565 : : i + 1);
566 : 0 : test_case->is_valid = false;
567 : 0 : continue;
568 : : }
569 : :
570 : 0 : test_case->cache_flush =
571 : 0 : (uint8_t)atoi(rte_cfgfile_get_entry(cfgfile, section_name, "cache_flush"));
572 : 0 : test_case->test_secs = (uint16_t)atoi(rte_cfgfile_get_entry(cfgfile,
573 : : section_name, "test_seconds"));
574 : :
575 : 0 : test_case->eal_args = rte_cfgfile_get_entry(cfgfile, section_name, "eal_args");
576 : 0 : test_case->is_valid = true;
577 : : }
578 : :
579 : 0 : rte_cfgfile_close(cfgfile);
580 : : printf("config file parsing complete.\n\n");
581 : 0 : return i;
582 : : }
583 : :
584 : : /* Parse the argument given in the command line of the application */
585 : : static int
586 : 0 : append_eal_args(int argc, char **argv, const char *eal_args, char **new_argv)
587 : : {
588 : : int i;
589 : : char *tokens[MAX_EAL_PARAM_NB];
590 : 0 : char args[MAX_EAL_PARAM_LEN] = {0};
591 : : int token_nb, new_argc = 0;
592 : :
593 : 0 : for (i = 0; i < argc; i++) {
594 : 0 : if ((strcmp(argv[i], CMDLINE_CONFIG_ARG) == 0) ||
595 : 0 : (strcmp(argv[i], CMDLINE_RESULT_ARG) == 0)) {
596 : 0 : i++;
597 : 0 : continue;
598 : : }
599 : 0 : strlcpy(new_argv[new_argc], argv[i], MAX_EAL_PARAM_LEN);
600 : 0 : new_argc++;
601 : : }
602 : :
603 : 0 : if (eal_args) {
604 : : strlcpy(args, eal_args, MAX_EAL_PARAM_LEN);
605 : 0 : token_nb = rte_strsplit(args, strlen(args),
606 : : tokens, MAX_EAL_PARAM_NB, ' ');
607 : 0 : for (i = 0; i < token_nb; i++)
608 : 0 : strlcpy(new_argv[new_argc++], tokens[i], MAX_EAL_PARAM_LEN);
609 : : }
610 : :
611 : 0 : return new_argc;
612 : : }
613 : :
614 : : int
615 : 0 : main(int argc, char *argv[])
616 : : {
617 : : int ret;
618 : : uint16_t case_nb;
619 : : uint32_t i, nb_lcores;
620 : : pid_t cpid, wpid;
621 : : int wstatus;
622 : : char args[MAX_EAL_PARAM_NB][MAX_EAL_PARAM_LEN];
623 : : char *pargs[MAX_EAL_PARAM_NB];
624 : : char *cfg_path_ptr = NULL;
625 : : char *rst_path_ptr = NULL;
626 : : char rst_path[PATH_MAX];
627 : : int new_argc;
628 : :
629 : : memset(args, 0, sizeof(args));
630 : :
631 : 0 : for (i = 0; i < RTE_DIM(pargs); i++)
632 : 0 : pargs[i] = args[i];
633 : :
634 : 0 : for (i = 0; i < (uint32_t)argc; i++) {
635 : 0 : if (strncmp(argv[i], CMDLINE_CONFIG_ARG, MAX_LONG_OPT_SZ) == 0)
636 : 0 : cfg_path_ptr = argv[i + 1];
637 : 0 : if (strncmp(argv[i], CMDLINE_RESULT_ARG, MAX_LONG_OPT_SZ) == 0)
638 : 0 : rst_path_ptr = argv[i + 1];
639 : : }
640 : 0 : if (cfg_path_ptr == NULL) {
641 : : printf("Config file not assigned.\n");
642 : 0 : return -1;
643 : : }
644 : 0 : if (rst_path_ptr == NULL) {
645 : : strlcpy(rst_path, cfg_path_ptr, PATH_MAX);
646 : 0 : char *token = strtok(basename(rst_path), ".");
647 : 0 : if (token == NULL) {
648 : : printf("Config file error.\n");
649 : 0 : return -1;
650 : : }
651 : : strcat(token, "_result.csv");
652 : : rst_path_ptr = rst_path;
653 : : }
654 : :
655 : 0 : case_nb = load_configs(cfg_path_ptr);
656 : 0 : fd = fopen(rst_path_ptr, "w");
657 : 0 : if (fd == NULL) {
658 : : printf("Open output CSV file error.\n");
659 : 0 : return -1;
660 : : }
661 : 0 : fclose(fd);
662 : :
663 : : printf("Running cases...\n");
664 : 0 : for (i = 0; i < case_nb; i++) {
665 : 0 : if (test_cases[i].is_skip) {
666 : 0 : printf("Test case %d configured to be skipped.\n\n", i + 1);
667 : : snprintf(output_str[0], MAX_OUTPUT_STR_LEN, "Skip the test-case %d\n",
668 : : i + 1);
669 : 0 : if (open_output_csv(rst_path_ptr))
670 : : return 0;
671 : 0 : continue;
672 : : }
673 : :
674 : 0 : if (!test_cases[i].is_valid) {
675 : 0 : printf("Invalid test case %d.\n\n", i + 1);
676 : : snprintf(output_str[0], MAX_OUTPUT_STR_LEN, "Invalid case %d\n", i + 1);
677 : 0 : if (open_output_csv(rst_path_ptr))
678 : : return 0;
679 : 0 : continue;
680 : : }
681 : :
682 : 0 : cpid = fork();
683 : 0 : if (cpid < 0) {
684 : 0 : printf("Fork case %d failed.\n", i + 1);
685 : 0 : exit(EXIT_FAILURE);
686 : 0 : } else if (cpid == 0) {
687 : 0 : printf("\nRunning case %u\n\n", i + 1);
688 : :
689 : 0 : new_argc = append_eal_args(argc, argv, test_cases[i].eal_args, pargs);
690 : 0 : ret = rte_eal_init(new_argc, pargs);
691 : 0 : if (ret < 0)
692 : 0 : rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n");
693 : :
694 : : /* Check lcores. */
695 : 0 : nb_lcores = rte_lcore_count();
696 : 0 : if (nb_lcores < 2)
697 : 0 : rte_exit(EXIT_FAILURE,
698 : : "There should be at least 2 worker lcores.\n");
699 : :
700 : 0 : fd = fopen(rst_path_ptr, "a");
701 : 0 : if (!fd) {
702 : : printf("Open output CSV file error.\n");
703 : 0 : return 0;
704 : : }
705 : :
706 : 0 : output_env_info();
707 : :
708 : 0 : run_test(i + 1, &test_cases[i]);
709 : :
710 : : /* clean up the EAL */
711 : 0 : rte_eal_cleanup();
712 : :
713 : 0 : fclose(fd);
714 : :
715 : : printf("\nCase %u completed.\n\n", i + 1);
716 : :
717 : 0 : exit(EXIT_SUCCESS);
718 : : } else {
719 : 0 : wpid = waitpid(cpid, &wstatus, 0);
720 : 0 : if (wpid == -1) {
721 : : printf("waitpid error.\n");
722 : 0 : exit(EXIT_FAILURE);
723 : : }
724 : :
725 : 0 : if (WIFEXITED(wstatus))
726 : 0 : printf("Case process exited. status %d\n\n",
727 : 0 : WEXITSTATUS(wstatus));
728 : 0 : else if (WIFSIGNALED(wstatus))
729 : : printf("Case process killed by signal %d\n\n",
730 : : WTERMSIG(wstatus));
731 : 0 : else if (WIFSTOPPED(wstatus))
732 : 0 : printf("Case process stopped by signal %d\n\n",
733 : 0 : WSTOPSIG(wstatus));
734 : 0 : else if (WIFCONTINUED(wstatus))
735 : : printf("Case process continued.\n\n");
736 : : else
737 : : printf("Case process unknown terminated.\n\n");
738 : : }
739 : : }
740 : :
741 : : printf("Bye...\n");
742 : 0 : return 0;
743 : : }
|