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