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