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