xref: /dpdk/app/test/test_graph.c (revision d83fb967212efa19d272e7fa65d17c9ad94b17c1)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2020 Marvell International Ltd.
3  */
4 
5 #include "test.h"
6 
7 #include <assert.h>
8 #include <inttypes.h>
9 #include <signal.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <unistd.h>
13 
14 #include <rte_errno.h>
15 
16 #ifdef RTE_EXEC_ENV_WINDOWS
17 static int
18 test_node_list_dump(void)
19 {
20 	printf("node_list_dump not supported on Windows, skipping test\n");
21 	return TEST_SKIPPED;
22 }
23 
24 #else
25 
26 #include <rte_graph.h>
27 #include <rte_graph_worker.h>
28 #include <rte_mbuf.h>
29 #include <rte_mbuf_dyn.h>
30 #include <rte_random.h>
31 
32 static uint16_t test_node_worker_source(struct rte_graph *graph,
33 					struct rte_node *node, void **objs,
34 					uint16_t nb_objs);
35 
36 static uint16_t test_node0_worker(struct rte_graph *graph,
37 				  struct rte_node *node, void **objs,
38 				  uint16_t nb_objs);
39 
40 static uint16_t test_node1_worker(struct rte_graph *graph,
41 				  struct rte_node *node, void **objs,
42 				  uint16_t nb_objs);
43 
44 static uint16_t test_node2_worker(struct rte_graph *graph,
45 				  struct rte_node *node, void **objs,
46 				  uint16_t nb_objs);
47 
48 static uint16_t test_node3_worker(struct rte_graph *graph,
49 				  struct rte_node *node, void **objs,
50 				  uint16_t nb_objs);
51 
52 #define MBUFF_SIZE 512
53 #define MAX_NODES  4
54 
55 typedef uint64_t graph_dynfield_t;
56 static int graph_dynfield_offset = -1;
57 
58 static inline graph_dynfield_t *
59 graph_field(struct rte_mbuf *mbuf)
60 {
61 	return RTE_MBUF_DYNFIELD(mbuf, \
62 			graph_dynfield_offset, graph_dynfield_t *);
63 }
64 
65 static struct rte_mbuf mbuf[MAX_NODES + 1][MBUFF_SIZE];
66 static void *mbuf_p[MAX_NODES + 1][MBUFF_SIZE];
67 static rte_graph_t graph_id;
68 static uint64_t obj_stats[MAX_NODES + 1];
69 static uint64_t fn_calls[MAX_NODES + 1];
70 
71 const char *node_patterns[] = {
72 	"test_node_source1",	   "test_node00",
73 	"test_node00-test_node11", "test_node00-test_node22",
74 	"test_node00-test_node33",
75 };
76 
77 const char *node_names[] = {
78 	"test_node00",
79 	"test_node00-test_node11",
80 	"test_node00-test_node22",
81 	"test_node00-test_node33",
82 };
83 
84 struct test_node_register {
85 	char name[RTE_NODE_NAMESIZE];
86 	rte_node_process_t process;
87 	uint16_t nb_edges;
88 	const char *next_nodes[MAX_NODES];
89 };
90 
91 typedef struct {
92 	uint32_t idx;
93 	struct test_node_register node;
94 } test_node_t;
95 
96 typedef struct {
97 	test_node_t test_node[MAX_NODES];
98 } test_main_t;
99 
100 static test_main_t test_main = {
101 	.test_node = {
102 		{
103 			.node = {
104 					.name = "test_node00",
105 					.process = test_node0_worker,
106 					.nb_edges = 2,
107 					.next_nodes = {"test_node00-"
108 						       "test_node11",
109 						       "test_node00-"
110 						       "test_node22"},
111 				},
112 		},
113 		{
114 			.node = {
115 					.name = "test_node11",
116 					.process = test_node1_worker,
117 					.nb_edges = 1,
118 					.next_nodes = {"test_node00-"
119 						       "test_node22"},
120 				},
121 		},
122 		{
123 			.node = {
124 					.name = "test_node22",
125 					.process = test_node2_worker,
126 					.nb_edges = 1,
127 					.next_nodes = {"test_node00-"
128 						       "test_node33"},
129 				},
130 		},
131 		{
132 			.node = {
133 					.name = "test_node33",
134 					.process = test_node3_worker,
135 					.nb_edges = 1,
136 					.next_nodes = {"test_node00"},
137 				},
138 		},
139 	},
140 };
141 
142 static int
143 node_init(const struct rte_graph *graph, struct rte_node *node)
144 {
145 	RTE_SET_USED(graph);
146 	*(uint32_t *)node->ctx = node->id;
147 
148 	return 0;
149 }
150 
151 static struct rte_node_register test_node_source = {
152 	.name = "test_node_source1",
153 	.process = test_node_worker_source,
154 	.flags = RTE_NODE_SOURCE_F,
155 	.nb_edges = 2,
156 	.init = node_init,
157 	.next_nodes = {"test_node00", "test_node00-test_node11"},
158 };
159 RTE_NODE_REGISTER(test_node_source);
160 
161 static struct rte_node_register test_node0 = {
162 	.name = "test_node00",
163 	.process = test_node0_worker,
164 	.init = node_init,
165 };
166 RTE_NODE_REGISTER(test_node0);
167 
168 uint16_t
169 test_node_worker_source(struct rte_graph *graph, struct rte_node *node,
170 			void **objs, uint16_t nb_objs)
171 {
172 	uint32_t obj_node0 = rte_rand() % 100, obj_node1;
173 	test_main_t *tm = &test_main;
174 	struct rte_mbuf *data;
175 	void **next_stream;
176 	rte_node_t next;
177 	uint32_t i;
178 
179 	RTE_SET_USED(objs);
180 	nb_objs = RTE_GRAPH_BURST_SIZE;
181 
182 	/* Prepare stream for next node 0 */
183 	obj_node0 = nb_objs * obj_node0 * 0.01;
184 	next = 0;
185 	next_stream = rte_node_next_stream_get(graph, node, next, obj_node0);
186 	for (i = 0; i < obj_node0; i++) {
187 		data = &mbuf[0][i];
188 		*graph_field(data) = ((uint64_t)tm->test_node[0].idx << 32) | i;
189 		if ((i + 1) == obj_node0)
190 			*graph_field(data) |= (1 << 16);
191 		next_stream[i] = &mbuf[0][i];
192 	}
193 	rte_node_next_stream_put(graph, node, next, obj_node0);
194 
195 	/* Prepare stream for next node 1 */
196 	obj_node1 = nb_objs - obj_node0;
197 	next = 1;
198 	next_stream = rte_node_next_stream_get(graph, node, next, obj_node1);
199 	for (i = 0; i < obj_node1; i++) {
200 		data = &mbuf[0][obj_node0 + i];
201 		*graph_field(data) = ((uint64_t)tm->test_node[1].idx << 32) | i;
202 		if ((i + 1) == obj_node1)
203 			*graph_field(data) |= (1 << 16);
204 		next_stream[i] = &mbuf[0][obj_node0 + i];
205 	}
206 
207 	rte_node_next_stream_put(graph, node, next, obj_node1);
208 	obj_stats[0] += nb_objs;
209 	fn_calls[0] += 1;
210 	return nb_objs;
211 }
212 
213 uint16_t
214 test_node0_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
215 		  uint16_t nb_objs)
216 {
217 	test_main_t *tm = &test_main;
218 
219 	if (*(uint32_t *)node->ctx == test_node0.id) {
220 		uint32_t obj_node0 = rte_rand() % 100, obj_node1;
221 		struct rte_mbuf *data;
222 		uint8_t second_pass = 0;
223 		uint32_t count = 0;
224 		uint32_t i;
225 
226 		obj_stats[1] += nb_objs;
227 		fn_calls[1] += 1;
228 
229 		for (i = 0; i < nb_objs; i++) {
230 			data = (struct rte_mbuf *)objs[i];
231 			if ((*graph_field(data) >> 32) != tm->test_node[0].idx) {
232 				printf("Data idx miss match at node 0, expected"
233 				       " = %u got = %u\n",
234 				       tm->test_node[0].idx,
235 				       (uint32_t)(*graph_field(data) >> 32));
236 				goto end;
237 			}
238 
239 			if ((*graph_field(data) & 0xffff) != (i - count)) {
240 				printf("Expected buff count miss match at "
241 				       "node 0\n");
242 				goto end;
243 			}
244 
245 			if (*graph_field(data) & (0x1 << 16))
246 				count = i + 1;
247 			if (*graph_field(data) & (0x1 << 17))
248 				second_pass = 1;
249 		}
250 
251 		if (count != i) {
252 			printf("Count mismatch at node 0\n");
253 			goto end;
254 		}
255 
256 		obj_node0 = nb_objs * obj_node0 * 0.01;
257 		for (i = 0; i < obj_node0; i++) {
258 			data = &mbuf[1][i];
259 			*graph_field(data) =
260 				((uint64_t)tm->test_node[1].idx << 32) | i;
261 			if ((i + 1) == obj_node0)
262 				*graph_field(data) |= (1 << 16);
263 			if (second_pass)
264 				*graph_field(data) |= (1 << 17);
265 		}
266 		rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[1][0],
267 				 obj_node0);
268 
269 		obj_node1 = nb_objs - obj_node0;
270 		for (i = 0; i < obj_node1; i++) {
271 			data = &mbuf[1][obj_node0 + i];
272 			*graph_field(data) =
273 				((uint64_t)tm->test_node[2].idx << 32) | i;
274 			if ((i + 1) == obj_node1)
275 				*graph_field(data) |= (1 << 16);
276 			if (second_pass)
277 				*graph_field(data) |= (1 << 17);
278 		}
279 		rte_node_enqueue(graph, node, 1, (void **)&mbuf_p[1][obj_node0],
280 				 obj_node1);
281 
282 	} else if (*(uint32_t *)node->ctx == tm->test_node[1].idx) {
283 		test_node1_worker(graph, node, objs, nb_objs);
284 	} else if (*(uint32_t *)node->ctx == tm->test_node[2].idx) {
285 		test_node2_worker(graph, node, objs, nb_objs);
286 	} else if (*(uint32_t *)node->ctx == tm->test_node[3].idx) {
287 		test_node3_worker(graph, node, objs, nb_objs);
288 	} else {
289 		printf("Unexpected node context\n");
290 	}
291 
292 end:
293 	return nb_objs;
294 }
295 
296 uint16_t
297 test_node1_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
298 		  uint16_t nb_objs)
299 {
300 	test_main_t *tm = &test_main;
301 	uint8_t second_pass = 0;
302 	uint32_t obj_node0 = 0;
303 	struct rte_mbuf *data;
304 	uint32_t count = 0;
305 	uint32_t i;
306 
307 	obj_stats[2] += nb_objs;
308 	fn_calls[2] += 1;
309 	for (i = 0; i < nb_objs; i++) {
310 		data = (struct rte_mbuf *)objs[i];
311 		if ((*graph_field(data) >> 32) != tm->test_node[1].idx) {
312 			printf("Data idx miss match at node 1, expected = %u"
313 			       " got = %u\n",
314 			       tm->test_node[1].idx,
315 			       (uint32_t)(*graph_field(data) >> 32));
316 			goto end;
317 		}
318 
319 		if ((*graph_field(data) & 0xffff) != (i - count)) {
320 			printf("Expected buff count miss match at node 1\n");
321 			goto end;
322 		}
323 
324 		if (*graph_field(data) & (0x1 << 16))
325 			count = i + 1;
326 		if (*graph_field(data) & (0x1 << 17))
327 			second_pass = 1;
328 	}
329 
330 	if (count != i) {
331 		printf("Count mismatch at node 1\n");
332 		goto end;
333 	}
334 
335 	obj_node0 = nb_objs;
336 	for (i = 0; i < obj_node0; i++) {
337 		data = &mbuf[2][i];
338 		*graph_field(data) = ((uint64_t)tm->test_node[2].idx << 32) | i;
339 		if ((i + 1) == obj_node0)
340 			*graph_field(data) |= (1 << 16);
341 		if (second_pass)
342 			*graph_field(data) |= (1 << 17);
343 	}
344 	rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[2][0], obj_node0);
345 
346 end:
347 	return nb_objs;
348 }
349 
350 uint16_t
351 test_node2_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
352 		  uint16_t nb_objs)
353 {
354 	test_main_t *tm = &test_main;
355 	uint8_t second_pass = 0;
356 	struct rte_mbuf *data;
357 	uint32_t count = 0;
358 	uint32_t obj_node0;
359 	uint32_t i;
360 
361 	obj_stats[3] += nb_objs;
362 	fn_calls[3] += 1;
363 	for (i = 0; i < nb_objs; i++) {
364 		data = (struct rte_mbuf *)objs[i];
365 		if ((*graph_field(data) >> 32) != tm->test_node[2].idx) {
366 			printf("Data idx miss match at node 2, expected = %u"
367 			       " got = %u\n",
368 			       tm->test_node[2].idx,
369 			       (uint32_t)(*graph_field(data) >> 32));
370 			goto end;
371 		}
372 
373 		if ((*graph_field(data) & 0xffff) != (i - count)) {
374 			printf("Expected buff count miss match at node 2\n");
375 			goto end;
376 		}
377 
378 		if (*graph_field(data) & (0x1 << 16))
379 			count = i + 1;
380 		if (*graph_field(data) & (0x1 << 17))
381 			second_pass = 1;
382 	}
383 
384 	if (count != i) {
385 		printf("Count mismatch at node 2\n");
386 		goto end;
387 	}
388 
389 	if (!second_pass) {
390 		obj_node0 = nb_objs;
391 		for (i = 0; i < obj_node0; i++) {
392 			data = &mbuf[3][i];
393 			*graph_field(data) =
394 				((uint64_t)tm->test_node[3].idx << 32) | i;
395 			if ((i + 1) == obj_node0)
396 				*graph_field(data) |= (1 << 16);
397 		}
398 		rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[3][0],
399 				 obj_node0);
400 	}
401 
402 end:
403 	return nb_objs;
404 }
405 
406 uint16_t
407 test_node3_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
408 		  uint16_t nb_objs)
409 {
410 	test_main_t *tm = &test_main;
411 	uint8_t second_pass = 0;
412 	struct rte_mbuf *data;
413 	uint32_t count = 0;
414 	uint32_t obj_node0;
415 	uint32_t i;
416 
417 	obj_stats[4] += nb_objs;
418 	fn_calls[4] += 1;
419 	for (i = 0; i < nb_objs; i++) {
420 		data = (struct rte_mbuf *)objs[i];
421 		if ((*graph_field(data) >> 32) != tm->test_node[3].idx) {
422 			printf("Data idx miss match at node 3, expected = %u"
423 			       " got = %u\n",
424 			       tm->test_node[3].idx,
425 			       (uint32_t)(*graph_field(data) >> 32));
426 			goto end;
427 		}
428 
429 		if ((*graph_field(data) & 0xffff) != (i - count)) {
430 			printf("Expected buff count miss match at node 3\n");
431 			goto end;
432 		}
433 
434 		if (*graph_field(data) & (0x1 << 16))
435 			count = i + 1;
436 		if (*graph_field(data) & (0x1 << 17))
437 			second_pass = 1;
438 	}
439 
440 	if (count != i) {
441 		printf("Count mismatch at node 3\n");
442 		goto end;
443 	}
444 
445 	if (second_pass) {
446 		printf("Unexpected buffers are at node 3\n");
447 		goto end;
448 	} else {
449 		obj_node0 = nb_objs * 2;
450 		for (i = 0; i < obj_node0; i++) {
451 			data = &mbuf[4][i];
452 			*graph_field(data) =
453 				((uint64_t)tm->test_node[0].idx << 32) | i;
454 			*graph_field(data) |= (1 << 17);
455 			if ((i + 1) == obj_node0)
456 				*graph_field(data) |= (1 << 16);
457 		}
458 		rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[4][0],
459 				 obj_node0);
460 	}
461 
462 end:
463 	return nb_objs;
464 }
465 
466 static int
467 test_lookup_functions(void)
468 {
469 	test_main_t *tm = &test_main;
470 	int i;
471 
472 	/* Verify the name with ID */
473 	for (i = 1; i < MAX_NODES; i++) {
474 		char *name = rte_node_id_to_name(tm->test_node[i].idx);
475 		if (strcmp(name, node_names[i]) != 0) {
476 			printf("Test node name verify by ID = %d failed "
477 			       "Expected = %s, got %s\n",
478 			       i, node_names[i], name);
479 			return -1;
480 		}
481 	}
482 
483 	/* Verify by name */
484 	for (i = 1; i < MAX_NODES; i++) {
485 		uint32_t idx = rte_node_from_name(node_names[i]);
486 		if (idx != tm->test_node[i].idx) {
487 			printf("Test node ID verify by name = %s failed "
488 			       "Expected = %d, got %d\n",
489 			       node_names[i], tm->test_node[i].idx, idx);
490 			return -1;
491 		}
492 	}
493 
494 	/* Verify edge count */
495 	for (i = 1; i < MAX_NODES; i++) {
496 		uint32_t count = rte_node_edge_count(tm->test_node[i].idx);
497 		if (count != tm->test_node[i].node.nb_edges) {
498 			printf("Test number of edges for node = %s failed Expected = %d, got = %d\n",
499 			       tm->test_node[i].node.name,
500 			       tm->test_node[i].node.nb_edges, count);
501 			return -1;
502 		}
503 	}
504 
505 	/* Verify edge names */
506 	for (i = 1; i < MAX_NODES; i++) {
507 		uint32_t j, count;
508 		char **next_edges;
509 
510 		count = rte_node_edge_get(tm->test_node[i].idx, NULL);
511 		if (count != tm->test_node[i].node.nb_edges * sizeof(char *)) {
512 			printf("Test number of edge count for node = %s failed Expected = %d, got = %d\n",
513 			       tm->test_node[i].node.name,
514 			       tm->test_node[i].node.nb_edges, count);
515 			return -1;
516 		}
517 		next_edges = malloc(count);
518 		count = rte_node_edge_get(tm->test_node[i].idx, next_edges);
519 		if (count != tm->test_node[i].node.nb_edges) {
520 			printf("Test number of edges for node = %s failed Expected = %d, got %d\n",
521 			       tm->test_node[i].node.name,
522 			       tm->test_node[i].node.nb_edges, count);
523 			free(next_edges);
524 			return -1;
525 		}
526 
527 		for (j = 0; j < count; j++) {
528 			if (strcmp(next_edges[j],
529 				   tm->test_node[i].node.next_nodes[j]) != 0) {
530 				printf("Edge name miss match, expected = %s got = %s\n",
531 				       tm->test_node[i].node.next_nodes[j],
532 				       next_edges[j]);
533 				free(next_edges);
534 				return -1;
535 			}
536 		}
537 		free(next_edges);
538 	}
539 
540 	return 0;
541 }
542 
543 static int
544 test_node_clone(void)
545 {
546 	test_main_t *tm = &test_main;
547 	uint32_t node_id, dummy_id;
548 	int i;
549 
550 	node_id = rte_node_from_name("test_node00");
551 	tm->test_node[0].idx = node_id;
552 
553 	dummy_id = rte_node_clone(node_id, "test_node00");
554 	if (rte_node_is_invalid(dummy_id)) {
555 		printf("Got invalid id when clone, Expecting fail\n");
556 		return -1;
557 	}
558 
559 	/* Clone with same name, should fail */
560 	dummy_id = rte_node_clone(node_id, "test_node00");
561 	if (!rte_node_is_invalid(dummy_id)) {
562 		printf("Got valid id when clone with same name, Expecting fail\n");
563 		return -1;
564 	}
565 
566 	for (i = 1; i < MAX_NODES; i++) {
567 		tm->test_node[i].idx =
568 			rte_node_clone(node_id, tm->test_node[i].node.name);
569 		if (rte_node_is_invalid(tm->test_node[i].idx)) {
570 			printf("Got invalid node id\n");
571 			return -1;
572 		}
573 	}
574 
575 	/* Clone from cloned node should fail */
576 	dummy_id = rte_node_clone(tm->test_node[1].idx, "dummy_node");
577 	if (!rte_node_is_invalid(dummy_id)) {
578 		printf("Got valid node id when cloning from cloned node, expected fail\n");
579 		return -1;
580 	}
581 
582 	return 0;
583 }
584 
585 static int
586 test_update_edges(void)
587 {
588 	test_main_t *tm = &test_main;
589 	uint32_t node_id;
590 	uint16_t count;
591 	int i;
592 
593 	node_id = rte_node_from_name("test_node00");
594 	count = rte_node_edge_update(node_id, 0,
595 				     tm->test_node[0].node.next_nodes,
596 				     tm->test_node[0].node.nb_edges);
597 	if (count != tm->test_node[0].node.nb_edges) {
598 		printf("Update edges failed expected: %d got = %d\n",
599 		       tm->test_node[0].node.nb_edges, count);
600 		return -1;
601 	}
602 
603 	for (i = 1; i < MAX_NODES; i++) {
604 		count = rte_node_edge_update(tm->test_node[i].idx, 0,
605 					     tm->test_node[i].node.next_nodes,
606 					     tm->test_node[i].node.nb_edges);
607 		if (count != tm->test_node[i].node.nb_edges) {
608 			printf("Update edges failed expected: %d got = %d\n",
609 			       tm->test_node[i].node.nb_edges, count);
610 			return -1;
611 		}
612 
613 		count = rte_node_edge_shrink(tm->test_node[i].idx,
614 					     tm->test_node[i].node.nb_edges);
615 		if (count != tm->test_node[i].node.nb_edges) {
616 			printf("Shrink edges failed\n");
617 			return -1;
618 		}
619 	}
620 
621 	return 0;
622 }
623 
624 static int
625 test_create_graph(void)
626 {
627 	static const char *node_patterns_dummy[] = {
628 		"test_node_source1",	   "test_node00",
629 		"test_node00-test_node11", "test_node00-test_node22",
630 		"test_node00-test_node33", "test_node00-dummy_node",
631 	};
632 	struct rte_graph_param gconf = {
633 		.socket_id = SOCKET_ID_ANY,
634 		.nb_node_patterns = 6,
635 		.node_patterns = node_patterns_dummy,
636 	};
637 	uint32_t dummy_node_id;
638 	uint32_t node_id;
639 
640 	node_id = rte_node_from_name("test_node00");
641 	dummy_node_id = rte_node_clone(node_id, "dummy_node");
642 	if (rte_node_is_invalid(dummy_node_id)) {
643 		printf("Got invalid node id\n");
644 		return -1;
645 	}
646 
647 	graph_id = rte_graph_create("worker0", &gconf);
648 	if (graph_id != RTE_GRAPH_ID_INVALID) {
649 		printf("Graph creation success with isolated node, expected graph creation fail\n");
650 		return -1;
651 	}
652 
653 	gconf.nb_node_patterns = 5;
654 	gconf.node_patterns = node_patterns;
655 	graph_id = rte_graph_create("worker0", &gconf);
656 	if (graph_id == RTE_GRAPH_ID_INVALID) {
657 		printf("Graph creation failed with error = %d\n", rte_errno);
658 		return -1;
659 	}
660 	return 0;
661 }
662 
663 static int
664 test_graph_clone(void)
665 {
666 	rte_graph_t cloned_graph_id = RTE_GRAPH_ID_INVALID;
667 	rte_graph_t main_graph_id = RTE_GRAPH_ID_INVALID;
668 	struct rte_graph_param graph_conf = {0};
669 	int ret = 0;
670 
671 	main_graph_id = rte_graph_from_name("worker0");
672 	if (main_graph_id == RTE_GRAPH_ID_INVALID) {
673 		printf("Must create main graph first\n");
674 		ret = -1;
675 	}
676 
677 	graph_conf.dispatch.mp_capacity = 1024;
678 	graph_conf.dispatch.wq_size_max = 32;
679 
680 	cloned_graph_id = rte_graph_clone(main_graph_id, "cloned-test0", &graph_conf);
681 
682 	if (cloned_graph_id == RTE_GRAPH_ID_INVALID) {
683 		printf("Graph creation failed with error = %d\n", rte_errno);
684 		ret = -1;
685 	}
686 
687 	if (strcmp(rte_graph_id_to_name(cloned_graph_id), "worker0-cloned-test0")) {
688 		printf("Cloned graph should name as %s but get %s\n", "worker0-cloned-test",
689 		       rte_graph_id_to_name(cloned_graph_id));
690 		ret = -1;
691 	}
692 
693 	rte_graph_destroy(cloned_graph_id);
694 
695 	return ret;
696 }
697 
698 static int
699 test_graph_model_mcore_dispatch_node_lcore_affinity_set(void)
700 {
701 	rte_graph_t cloned_graph_id = RTE_GRAPH_ID_INVALID;
702 	unsigned int worker_lcore = RTE_MAX_LCORE;
703 	struct rte_graph_param graph_conf = {0};
704 	rte_node_t nid = RTE_NODE_ID_INVALID;
705 	char node_name[64] = "test_node00";
706 	struct rte_node *node;
707 	int ret = 0;
708 
709 	worker_lcore = rte_get_next_lcore(worker_lcore, true, 1);
710 	ret = rte_graph_model_mcore_dispatch_node_lcore_affinity_set(node_name, worker_lcore);
711 	if (ret == 0)
712 		printf("Set node %s affinity to lcore %u\n", node_name, worker_lcore);
713 
714 	nid = rte_node_from_name(node_name);
715 	cloned_graph_id = rte_graph_clone(graph_id, "cloned-test1", &graph_conf);
716 	node = rte_graph_node_get(cloned_graph_id, nid);
717 
718 	if (node->dispatch.lcore_id != worker_lcore) {
719 		printf("set node affinity failed\n");
720 		ret = -1;
721 	}
722 
723 	rte_graph_destroy(cloned_graph_id);
724 
725 	return ret;
726 }
727 
728 static int
729 test_graph_model_mcore_dispatch_core_bind_unbind(void)
730 {
731 	rte_graph_t cloned_graph_id = RTE_GRAPH_ID_INVALID;
732 	unsigned int worker_lcore = RTE_MAX_LCORE;
733 	struct rte_graph_param graph_conf = {0};
734 	struct rte_graph *graph;
735 	int ret = 0;
736 
737 	worker_lcore = rte_get_next_lcore(worker_lcore, true, 1);
738 	cloned_graph_id = rte_graph_clone(graph_id, "cloned-test2", &graph_conf);
739 
740 	ret = rte_graph_worker_model_set(RTE_GRAPH_MODEL_MCORE_DISPATCH);
741 	if (ret != 0) {
742 		printf("Set graph mcore dispatch model failed\n");
743 		ret = -1;
744 	}
745 
746 	ret = rte_graph_model_mcore_dispatch_core_bind(cloned_graph_id, worker_lcore);
747 	if (ret != 0) {
748 		printf("bind graph %d to lcore %u failed\n", graph_id, worker_lcore);
749 		ret = -1;
750 	}
751 
752 	graph = rte_graph_lookup("worker0-cloned-test2");
753 
754 	if (graph->dispatch.lcore_id != worker_lcore) {
755 		printf("bind graph %s(id:%d) with lcore %u failed\n",
756 		       graph->name, graph->id, worker_lcore);
757 		ret = -1;
758 	}
759 
760 	rte_graph_model_mcore_dispatch_core_unbind(cloned_graph_id);
761 	if (graph->dispatch.lcore_id != RTE_MAX_LCORE) {
762 		printf("unbind graph %s(id:%d) failed %d\n",
763 		       graph->name, graph->id, graph->dispatch.lcore_id);
764 		ret = -1;
765 	}
766 
767 	rte_graph_destroy(cloned_graph_id);
768 
769 	return ret;
770 }
771 
772 static int
773 test_graph_worker_model_set_get(void)
774 {
775 	rte_graph_t cloned_graph_id = RTE_GRAPH_ID_INVALID;
776 	struct rte_graph_param graph_conf = {0};
777 	struct rte_graph *graph;
778 	int ret = 0;
779 
780 	cloned_graph_id = rte_graph_clone(graph_id, "cloned-test3", &graph_conf);
781 	ret = rte_graph_worker_model_set(RTE_GRAPH_MODEL_MCORE_DISPATCH);
782 	if (ret != 0) {
783 		printf("Set graph mcore dispatch model failed\n");
784 		ret = -1;
785 	}
786 
787 	graph = rte_graph_lookup("worker0-cloned-test3");
788 	if (rte_graph_worker_model_get(graph) != RTE_GRAPH_MODEL_MCORE_DISPATCH) {
789 		printf("Get graph worker model failed\n");
790 		ret = -1;
791 	}
792 
793 	rte_graph_destroy(cloned_graph_id);
794 
795 	return 0;
796 }
797 
798 static int
799 test_graph_walk(void)
800 {
801 	struct rte_graph *graph = rte_graph_lookup("worker0");
802 	int i;
803 
804 	if (!graph) {
805 		printf("Graph lookup failed\n");
806 		return -1;
807 	}
808 
809 	for (i = 0; i < 5; i++)
810 		rte_graph_walk(graph);
811 	return 0;
812 }
813 
814 static int
815 test_graph_lookup_functions(void)
816 {
817 	test_main_t *tm = &test_main;
818 	struct rte_node *node;
819 	int i;
820 
821 	for (i = 0; i < MAX_NODES; i++) {
822 		node = rte_graph_node_get(graph_id, tm->test_node[i].idx);
823 		if (!node) {
824 			printf("rte_graph_node_get, failed for node = %d\n",
825 			       tm->test_node[i].idx);
826 			return -1;
827 		}
828 
829 		if (tm->test_node[i].idx != node->id) {
830 			printf("Node id didn't match, expected = %d got = %d\n",
831 			       tm->test_node[i].idx, node->id);
832 			return 0;
833 		}
834 
835 		if (strncmp(node->name, node_names[i], RTE_NODE_NAMESIZE)) {
836 			printf("Node name didn't match, expected = %s got %s\n",
837 			       node_names[i], node->name);
838 			return -1;
839 		}
840 	}
841 
842 	for (i = 0; i < MAX_NODES; i++) {
843 		node = rte_graph_node_get_by_name("worker0", node_names[i]);
844 		if (!node) {
845 			printf("rte_graph_node_get, failed for node = %d\n",
846 			       tm->test_node[i].idx);
847 			return -1;
848 		}
849 
850 		if (tm->test_node[i].idx != node->id) {
851 			printf("Node id didn't match, expected = %d got = %d\n",
852 			       tm->test_node[i].idx, node->id);
853 			return 0;
854 		}
855 
856 		if (strncmp(node->name, node_names[i], RTE_NODE_NAMESIZE)) {
857 			printf("Node name didn't match, expected = %s got %s\n",
858 			       node_names[i], node->name);
859 			return -1;
860 		}
861 	}
862 
863 	return 0;
864 }
865 
866 static int
867 graph_cluster_stats_cb_t(bool is_first, bool is_last, void *cookie,
868 			 const struct rte_graph_cluster_node_stats *st)
869 {
870 	int i;
871 
872 	RTE_SET_USED(is_first);
873 	RTE_SET_USED(is_last);
874 	RTE_SET_USED(cookie);
875 
876 	for (i = 0; i < MAX_NODES + 1; i++) {
877 		rte_node_t id = rte_node_from_name(node_patterns[i]);
878 		if (id == st->id) {
879 			if (obj_stats[i] != st->objs) {
880 				printf("Obj count miss match for node = %s expected = %"PRId64", got=%"PRId64"\n",
881 				       node_patterns[i], obj_stats[i],
882 				       st->objs);
883 				return -1;
884 			}
885 
886 			if (fn_calls[i] != st->calls) {
887 				printf("Func call miss match for node = %s expected = %"PRId64", got = %"PRId64"\n",
888 				       node_patterns[i], fn_calls[i],
889 				       st->calls);
890 				return -1;
891 			}
892 		}
893 	}
894 	return 0;
895 }
896 
897 static int
898 test_print_stats(void)
899 {
900 	struct rte_graph_cluster_stats_param s_param;
901 	struct rte_graph_cluster_stats *stats;
902 	const char *pattern = "worker0";
903 
904 	if (!rte_graph_has_stats_feature())
905 		return 0;
906 
907 	/* Prepare stats object */
908 	memset(&s_param, 0, sizeof(s_param));
909 	s_param.f = stdout;
910 	s_param.socket_id = SOCKET_ID_ANY;
911 	s_param.graph_patterns = &pattern;
912 	s_param.nb_graph_patterns = 1;
913 	s_param.fn = graph_cluster_stats_cb_t;
914 
915 	stats = rte_graph_cluster_stats_create(&s_param);
916 	if (stats == NULL) {
917 		printf("Unable to get stats\n");
918 		return -1;
919 	}
920 	/* Clear screen and move to top left */
921 	rte_graph_cluster_stats_get(stats, 0);
922 	rte_graph_cluster_stats_destroy(stats);
923 
924 	return 0;
925 }
926 
927 static int
928 graph_setup(void)
929 {
930 	int i, j;
931 
932 	static const struct rte_mbuf_dynfield graph_dynfield_desc = {
933 		.name = "test_graph_dynfield",
934 		.size = sizeof(graph_dynfield_t),
935 		.align = __alignof__(graph_dynfield_t),
936 	};
937 	graph_dynfield_offset =
938 		rte_mbuf_dynfield_register(&graph_dynfield_desc);
939 	if (graph_dynfield_offset < 0) {
940 		printf("Cannot register mbuf field\n");
941 		return TEST_FAILED;
942 	}
943 
944 	for (i = 0; i <= MAX_NODES; i++) {
945 		for (j = 0; j < MBUFF_SIZE; j++)
946 			mbuf_p[i][j] = &mbuf[i][j];
947 	}
948 	if (test_node_clone()) {
949 		printf("test_node_clone: fail\n");
950 		return -1;
951 	}
952 	printf("test_node_clone: pass\n");
953 
954 	return 0;
955 }
956 
957 static void
958 graph_teardown(void)
959 {
960 	int id;
961 
962 	id = rte_graph_destroy(rte_graph_from_name("worker0"));
963 	if (id)
964 		printf("Graph Destroy failed\n");
965 }
966 
967 static struct unit_test_suite graph_testsuite = {
968 	.suite_name = "Graph library test suite",
969 	.setup = graph_setup,
970 	.teardown = graph_teardown,
971 	.unit_test_cases = {
972 		TEST_CASE(test_update_edges),
973 		TEST_CASE(test_lookup_functions),
974 		TEST_CASE(test_create_graph),
975 		TEST_CASE(test_graph_clone),
976 		TEST_CASE(test_graph_model_mcore_dispatch_node_lcore_affinity_set),
977 		TEST_CASE(test_graph_model_mcore_dispatch_core_bind_unbind),
978 		TEST_CASE(test_graph_worker_model_set_get),
979 		TEST_CASE(test_graph_lookup_functions),
980 		TEST_CASE(test_graph_walk),
981 		TEST_CASE(test_print_stats),
982 		TEST_CASES_END(), /**< NULL terminate unit test array */
983 	},
984 };
985 
986 static int
987 graph_autotest_fn(void)
988 {
989 	return unit_test_suite_runner(&graph_testsuite);
990 }
991 
992 REGISTER_FAST_TEST(graph_autotest, true, true, graph_autotest_fn);
993 
994 static int
995 test_node_list_dump(void)
996 {
997 	rte_node_list_dump(stdout);
998 
999 	return TEST_SUCCESS;
1000 }
1001 
1002 #endif /* !RTE_EXEC_ENV_WINDOWS */
1003 
1004 REGISTER_FAST_TEST(node_list_dump, true, true, test_node_list_dump);
1005