test/graph: use better randomness
[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                         return -1;
501                 }
502
503                 for (j = 0; j < count; j++) {
504                         if (strcmp(next_edges[j],
505                                    tm->test_node[i].node.next_nodes[j]) != 0) {
506                                 printf("Edge name miss match, expected = %s got = %s\n",
507                                        tm->test_node[i].node.next_nodes[j],
508                                        next_edges[j]);
509                                 return -1;
510                         }
511                 }
512                 free(next_edges);
513         }
514
515         return 0;
516 }
517
518 static int
519 test_node_clone(void)
520 {
521         test_main_t *tm = &test_main;
522         uint32_t node_id, dummy_id;
523         int i;
524
525         node_id = rte_node_from_name("test_node00");
526         tm->test_node[0].idx = node_id;
527
528         /* Clone with same name, should fail */
529         dummy_id = rte_node_clone(node_id, "test_node00");
530         if (!rte_node_is_invalid(dummy_id)) {
531                 printf("Got valid id when clone with same name, Expecting fail\n");
532                 return -1;
533         }
534
535         for (i = 1; i < MAX_NODES; i++) {
536                 tm->test_node[i].idx =
537                         rte_node_clone(node_id, tm->test_node[i].node.name);
538                 if (rte_node_is_invalid(tm->test_node[i].idx)) {
539                         printf("Got invalid node id\n");
540                         return -1;
541                 }
542         }
543
544         /* Clone from cloned node should fail */
545         dummy_id = rte_node_clone(tm->test_node[1].idx, "dummy_node");
546         if (!rte_node_is_invalid(dummy_id)) {
547                 printf("Got valid node id when cloning from cloned node, expected fail\n");
548                 return -1;
549         }
550
551         return 0;
552 }
553
554 static int
555 test_update_edges(void)
556 {
557         test_main_t *tm = &test_main;
558         uint32_t node_id;
559         uint16_t count;
560         int i;
561
562         node_id = rte_node_from_name("test_node00");
563         count = rte_node_edge_update(node_id, 0,
564                                      tm->test_node[0].node.next_nodes,
565                                      tm->test_node[0].node.nb_edges);
566         if (count != tm->test_node[0].node.nb_edges) {
567                 printf("Update edges failed expected: %d got = %d\n",
568                        tm->test_node[0].node.nb_edges, count);
569                 return -1;
570         }
571
572         for (i = 1; i < MAX_NODES; i++) {
573                 count = rte_node_edge_update(tm->test_node[i].idx, 0,
574                                              tm->test_node[i].node.next_nodes,
575                                              tm->test_node[i].node.nb_edges);
576                 if (count != tm->test_node[i].node.nb_edges) {
577                         printf("Update edges failed expected: %d got = %d\n",
578                                tm->test_node[i].node.nb_edges, count);
579                         return -1;
580                 }
581
582                 count = rte_node_edge_shrink(tm->test_node[i].idx,
583                                              tm->test_node[i].node.nb_edges);
584                 if (count != tm->test_node[i].node.nb_edges) {
585                         printf("Shrink edges failed\n");
586                         return -1;
587                 }
588         }
589
590         return 0;
591 }
592
593 static int
594 test_create_graph(void)
595 {
596         static const char *node_patterns_dummy[] = {
597                 "test_node_source1",       "test_node00",
598                 "test_node00-test_node11", "test_node00-test_node22",
599                 "test_node00-test_node33", "test_node00-dummy_node",
600         };
601         struct rte_graph_param gconf = {
602                 .socket_id = SOCKET_ID_ANY,
603                 .nb_node_patterns = 6,
604                 .node_patterns = node_patterns_dummy,
605         };
606         uint32_t dummy_node_id;
607         uint32_t node_id;
608
609         node_id = rte_node_from_name("test_node00");
610         dummy_node_id = rte_node_clone(node_id, "dummy_node");
611         if (rte_node_is_invalid(dummy_node_id)) {
612                 printf("Got invalid node id\n");
613                 return -1;
614         }
615
616         graph_id = rte_graph_create("worker0", &gconf);
617         if (graph_id != RTE_GRAPH_ID_INVALID) {
618                 printf("Graph creation success with isolated node, expected graph creation fail\n");
619                 return -1;
620         }
621
622         gconf.nb_node_patterns = 5;
623         gconf.node_patterns = node_patterns;
624         graph_id = rte_graph_create("worker0", &gconf);
625         if (graph_id == RTE_GRAPH_ID_INVALID) {
626                 printf("Graph creation failed with error = %d\n", rte_errno);
627                 return -1;
628         }
629         return 0;
630 }
631
632 static int
633 test_graph_walk(void)
634 {
635         struct rte_graph *graph = rte_graph_lookup("worker0");
636         int i;
637
638         if (!graph) {
639                 printf("Graph lookup failed\n");
640                 return -1;
641         }
642
643         for (i = 0; i < 5; i++)
644                 rte_graph_walk(graph);
645         return 0;
646 }
647
648 static int
649 test_graph_lookup_functions(void)
650 {
651         test_main_t *tm = &test_main;
652         struct rte_node *node;
653         int i;
654
655         for (i = 0; i < MAX_NODES; i++) {
656                 node = rte_graph_node_get(graph_id, tm->test_node[i].idx);
657                 if (!node) {
658                         printf("rte_graph_node_get, failed for node = %d\n",
659                                tm->test_node[i].idx);
660                         return -1;
661                 }
662
663                 if (tm->test_node[i].idx != node->id) {
664                         printf("Node id didn't match, expected = %d got = %d\n",
665                                tm->test_node[i].idx, node->id);
666                         return 0;
667                 }
668
669                 if (strncmp(node->name, node_names[i], RTE_NODE_NAMESIZE)) {
670                         printf("Node name didn't match, expected = %s got %s\n",
671                                node_names[i], node->name);
672                         return -1;
673                 }
674         }
675
676         for (i = 0; i < MAX_NODES; i++) {
677                 node = rte_graph_node_get_by_name("worker0", node_names[i]);
678                 if (!node) {
679                         printf("rte_graph_node_get, failed for node = %d\n",
680                                tm->test_node[i].idx);
681                         return -1;
682                 }
683
684                 if (tm->test_node[i].idx != node->id) {
685                         printf("Node id didn't match, expected = %d got = %d\n",
686                                tm->test_node[i].idx, node->id);
687                         return 0;
688                 }
689
690                 if (strncmp(node->name, node_names[i], RTE_NODE_NAMESIZE)) {
691                         printf("Node name didn't match, expected = %s got %s\n",
692                                node_names[i], node->name);
693                         return -1;
694                 }
695         }
696
697         return 0;
698 }
699
700 static int
701 graph_cluster_stats_cb_t(bool is_first, bool is_last, void *cookie,
702                          const struct rte_graph_cluster_node_stats *st)
703 {
704         int i;
705
706         RTE_SET_USED(is_first);
707         RTE_SET_USED(is_last);
708         RTE_SET_USED(cookie);
709
710         for (i = 0; i < MAX_NODES + 1; i++) {
711                 rte_node_t id = rte_node_from_name(node_patterns[i]);
712                 if (id == st->id) {
713                         if (obj_stats[i] != st->objs) {
714                                 printf("Obj count miss match for node = %s expected = %"PRId64", got=%"PRId64"\n",
715                                        node_patterns[i], obj_stats[i],
716                                        st->objs);
717                                 return -1;
718                         }
719
720                         if (fn_calls[i] != st->calls) {
721                                 printf("Func call miss match for node = %s expected = %"PRId64", got = %"PRId64"\n",
722                                        node_patterns[i], fn_calls[i],
723                                        st->calls);
724                                 return -1;
725                         }
726                 }
727         }
728         return 0;
729 }
730
731 static int
732 test_print_stats(void)
733 {
734         struct rte_graph_cluster_stats_param s_param;
735         struct rte_graph_cluster_stats *stats;
736         const char *pattern = "worker0";
737
738         if (!rte_graph_has_stats_feature())
739                 return 0;
740
741         /* Prepare stats object */
742         memset(&s_param, 0, sizeof(s_param));
743         s_param.f = stdout;
744         s_param.socket_id = SOCKET_ID_ANY;
745         s_param.graph_patterns = &pattern;
746         s_param.nb_graph_patterns = 1;
747         s_param.fn = graph_cluster_stats_cb_t;
748
749         stats = rte_graph_cluster_stats_create(&s_param);
750         if (stats == NULL) {
751                 printf("Unable to get stats\n");
752                 return -1;
753         }
754         /* Clear screen and move to top left */
755         rte_graph_cluster_stats_get(stats, 0);
756         rte_graph_cluster_stats_destroy(stats);
757
758         return 0;
759 }
760
761 static int
762 graph_setup(void)
763 {
764         int i, j;
765
766         for (i = 0; i <= MAX_NODES; i++) {
767                 for (j = 0; j < MBUFF_SIZE; j++)
768                         mbuf_p[i][j] = &mbuf[i][j];
769         }
770         if (test_node_clone()) {
771                 printf("test_node_clone: fail\n");
772                 return -1;
773         }
774         printf("test_node_clone: pass\n");
775
776         return 0;
777 }
778
779 static void
780 graph_teardown(void)
781 {
782         int id;
783
784         id = rte_graph_destroy(rte_graph_from_name("worker0"));
785         if (id)
786                 printf("Graph Destroy failed\n");
787 }
788
789 static struct unit_test_suite graph_testsuite = {
790         .suite_name = "Graph library test suite",
791         .setup = graph_setup,
792         .teardown = graph_teardown,
793         .unit_test_cases = {
794                 TEST_CASE(test_update_edges),
795                 TEST_CASE(test_lookup_functions),
796                 TEST_CASE(test_create_graph),
797                 TEST_CASE(test_graph_lookup_functions),
798                 TEST_CASE(test_graph_walk),
799                 TEST_CASE(test_print_stats),
800                 TEST_CASES_END(), /**< NULL terminate unit test array */
801         },
802 };
803
804 static int
805 graph_autotest_fn(void)
806 {
807         return unit_test_suite_runner(&graph_testsuite);
808 }
809
810 REGISTER_TEST_COMMAND(graph_autotest, graph_autotest_fn);
811
812 static int
813 test_node_list_dump(void)
814 {
815         rte_node_list_dump(stdout);
816
817         return TEST_SUCCESS;
818 }
819 REGISTER_TEST_COMMAND(node_list_dump, test_node_list_dump);