1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(C) 2020 Marvell International Ltd.
11 #include <rte_errno.h>
12 #include <rte_graph.h>
13 #include <rte_graph_worker.h>
15 #include <rte_mbuf_dyn.h>
16 #include <rte_random.h>
20 static uint16_t test_node_worker_source(struct rte_graph *graph,
21 struct rte_node *node, void **objs,
24 static uint16_t test_node0_worker(struct rte_graph *graph,
25 struct rte_node *node, void **objs,
28 static uint16_t test_node1_worker(struct rte_graph *graph,
29 struct rte_node *node, void **objs,
32 static uint16_t test_node2_worker(struct rte_graph *graph,
33 struct rte_node *node, void **objs,
36 static uint16_t test_node3_worker(struct rte_graph *graph,
37 struct rte_node *node, void **objs,
40 #define MBUFF_SIZE 512
43 typedef uint64_t graph_dynfield_t;
44 static int graph_dynfield_offset = -1;
46 static inline graph_dynfield_t *
47 graph_field(struct rte_mbuf *mbuf)
49 return RTE_MBUF_DYNFIELD(mbuf, \
50 graph_dynfield_offset, graph_dynfield_t *);
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];
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",
65 const char *node_names[] = {
67 "test_node00-test_node11",
68 "test_node00-test_node22",
69 "test_node00-test_node33",
72 struct test_node_register {
73 char name[RTE_NODE_NAMESIZE];
74 rte_node_process_t process;
76 const char *next_nodes[MAX_NODES];
81 struct test_node_register node;
85 test_node_t test_node[MAX_NODES];
88 static test_main_t test_main = {
92 .name = "test_node00",
93 .process = test_node0_worker,
95 .next_nodes = {"test_node00-"
103 .name = "test_node11",
104 .process = test_node1_worker,
106 .next_nodes = {"test_node00-"
112 .name = "test_node22",
113 .process = test_node2_worker,
115 .next_nodes = {"test_node00-"
121 .name = "test_node33",
122 .process = test_node3_worker,
124 .next_nodes = {"test_node00"},
131 node_init(const struct rte_graph *graph, struct rte_node *node)
134 *(uint32_t *)node->ctx = node->id;
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,
145 .next_nodes = {"test_node00", "test_node00-test_node11"},
147 RTE_NODE_REGISTER(test_node_source);
149 static struct rte_node_register test_node0 = {
150 .name = "test_node00",
151 .process = test_node0_worker,
154 RTE_NODE_REGISTER(test_node0);
157 test_node_worker_source(struct rte_graph *graph, struct rte_node *node,
158 void **objs, uint16_t nb_objs)
160 uint32_t obj_node0 = rte_rand() % 100, obj_node1;
161 test_main_t *tm = &test_main;
162 struct rte_mbuf *data;
168 nb_objs = RTE_GRAPH_BURST_SIZE;
170 /* Prepare stream for next node 0 */
171 obj_node0 = nb_objs * obj_node0 * 0.01;
173 next_stream = rte_node_next_stream_get(graph, node, next, obj_node0);
174 for (i = 0; i < obj_node0; 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];
181 rte_node_next_stream_put(graph, node, next, obj_node0);
183 /* Prepare stream for next node 1 */
184 obj_node1 = nb_objs - obj_node0;
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];
195 rte_node_next_stream_put(graph, node, next, obj_node1);
196 obj_stats[0] += nb_objs;
202 test_node0_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
205 test_main_t *tm = &test_main;
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;
214 obj_stats[1] += nb_objs;
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"
222 tm->test_node[0].idx,
223 (uint32_t)(*graph_field(data) >> 32));
227 if ((*graph_field(data) & 0xffff) != (i - count)) {
228 printf("Expected buff count miss match at "
233 if (*graph_field(data) & (0x1 << 16))
235 if (*graph_field(data) & (0x1 << 17))
240 printf("Count mismatch at node 0\n");
244 obj_node0 = nb_objs * obj_node0 * 0.01;
245 for (i = 0; i < obj_node0; i++) {
248 ((uint64_t)tm->test_node[1].idx << 32) | i;
249 if ((i + 1) == obj_node0)
250 *graph_field(data) |= (1 << 16);
252 *graph_field(data) |= (1 << 17);
254 rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[1][0],
257 obj_node1 = nb_objs - obj_node0;
258 for (i = 0; i < obj_node1; i++) {
259 data = &mbuf[1][obj_node0 + i];
261 ((uint64_t)tm->test_node[2].idx << 32) | i;
262 if ((i + 1) == obj_node1)
263 *graph_field(data) |= (1 << 16);
265 *graph_field(data) |= (1 << 17);
267 rte_node_enqueue(graph, node, 1, (void **)&mbuf_p[1][obj_node0],
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);
277 printf("Unexpected node context\n");
285 test_node1_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
288 test_main_t *tm = &test_main;
289 uint8_t second_pass = 0;
290 uint32_t obj_node0 = 0;
291 struct rte_mbuf *data;
295 obj_stats[2] += nb_objs;
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"
302 tm->test_node[1].idx,
303 (uint32_t)(*graph_field(data) >> 32));
307 if ((*graph_field(data) & 0xffff) != (i - count)) {
308 printf("Expected buff count miss match at node 1\n");
312 if (*graph_field(data) & (0x1 << 16))
314 if (*graph_field(data) & (0x1 << 17))
319 printf("Count mismatch at node 1\n");
324 for (i = 0; i < obj_node0; 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);
330 *graph_field(data) |= (1 << 17);
332 rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[2][0], obj_node0);
339 test_node2_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
342 test_main_t *tm = &test_main;
343 uint8_t second_pass = 0;
344 struct rte_mbuf *data;
349 obj_stats[3] += nb_objs;
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"
356 tm->test_node[2].idx,
357 (uint32_t)(*graph_field(data) >> 32));
361 if ((*graph_field(data) & 0xffff) != (i - count)) {
362 printf("Expected buff count miss match at node 2\n");
366 if (*graph_field(data) & (0x1 << 16))
368 if (*graph_field(data) & (0x1 << 17))
373 printf("Count mismatch at node 2\n");
379 for (i = 0; i < obj_node0; i++) {
382 ((uint64_t)tm->test_node[3].idx << 32) | i;
383 if ((i + 1) == obj_node0)
384 *graph_field(data) |= (1 << 16);
386 rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[3][0],
395 test_node3_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
398 test_main_t *tm = &test_main;
399 uint8_t second_pass = 0;
400 struct rte_mbuf *data;
405 obj_stats[4] += nb_objs;
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"
412 tm->test_node[3].idx,
413 (uint32_t)(*graph_field(data) >> 32));
417 if ((*graph_field(data) & 0xffff) != (i - count)) {
418 printf("Expected buff count miss match at node 3\n");
422 if (*graph_field(data) & (0x1 << 16))
424 if (*graph_field(data) & (0x1 << 17))
429 printf("Count mismatch at node 3\n");
434 printf("Unexpected buffers are at node 3\n");
437 obj_node0 = nb_objs * 2;
438 for (i = 0; i < obj_node0; i++) {
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);
446 rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[4][0],
455 test_lookup_functions(void)
457 test_main_t *tm = &test_main;
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);
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);
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);
493 /* Verify edge names */
494 for (i = 1; i < MAX_NODES; i++) {
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);
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);
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],
532 test_node_clone(void)
534 test_main_t *tm = &test_main;
535 uint32_t node_id, dummy_id;
538 node_id = rte_node_from_name("test_node00");
539 tm->test_node[0].idx = node_id;
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");
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");
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");
568 test_update_edges(void)
570 test_main_t *tm = &test_main;
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);
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);
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");
607 test_create_graph(void)
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",
614 struct rte_graph_param gconf = {
615 .socket_id = SOCKET_ID_ANY,
616 .nb_node_patterns = 6,
617 .node_patterns = node_patterns_dummy,
619 uint32_t dummy_node_id;
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");
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");
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);
646 test_graph_walk(void)
648 struct rte_graph *graph = rte_graph_lookup("worker0");
652 printf("Graph lookup failed\n");
656 for (i = 0; i < 5; i++)
657 rte_graph_walk(graph);
662 test_graph_lookup_functions(void)
664 test_main_t *tm = &test_main;
665 struct rte_node *node;
668 for (i = 0; i < MAX_NODES; i++) {
669 node = rte_graph_node_get(graph_id, tm->test_node[i].idx);
671 printf("rte_graph_node_get, failed for node = %d\n",
672 tm->test_node[i].idx);
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);
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);
689 for (i = 0; i < MAX_NODES; i++) {
690 node = rte_graph_node_get_by_name("worker0", node_names[i]);
692 printf("rte_graph_node_get, failed for node = %d\n",
693 tm->test_node[i].idx);
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);
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);
714 graph_cluster_stats_cb_t(bool is_first, bool is_last, void *cookie,
715 const struct rte_graph_cluster_node_stats *st)
719 RTE_SET_USED(is_first);
720 RTE_SET_USED(is_last);
721 RTE_SET_USED(cookie);
723 for (i = 0; i < MAX_NODES + 1; i++) {
724 rte_node_t id = rte_node_from_name(node_patterns[i]);
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],
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],
745 test_print_stats(void)
747 struct rte_graph_cluster_stats_param s_param;
748 struct rte_graph_cluster_stats *stats;
749 const char *pattern = "worker0";
751 if (!rte_graph_has_stats_feature())
754 /* Prepare stats object */
755 memset(&s_param, 0, sizeof(s_param));
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;
762 stats = rte_graph_cluster_stats_create(&s_param);
764 printf("Unable to get stats\n");
767 /* Clear screen and move to top left */
768 rte_graph_cluster_stats_get(stats, 0);
769 rte_graph_cluster_stats_destroy(stats);
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),
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");
791 for (i = 0; i <= MAX_NODES; i++) {
792 for (j = 0; j < MBUFF_SIZE; j++)
793 mbuf_p[i][j] = &mbuf[i][j];
795 if (test_node_clone()) {
796 printf("test_node_clone: fail\n");
799 printf("test_node_clone: pass\n");
809 id = rte_graph_destroy(rte_graph_from_name("worker0"));
811 printf("Graph Destroy failed\n");
814 static struct unit_test_suite graph_testsuite = {
815 .suite_name = "Graph library test suite",
816 .setup = graph_setup,
817 .teardown = graph_teardown,
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 */
830 graph_autotest_fn(void)
832 return unit_test_suite_runner(&graph_testsuite);
835 REGISTER_TEST_COMMAND(graph_autotest, graph_autotest_fn);
838 test_node_list_dump(void)
840 rte_node_list_dump(stdout);
844 REGISTER_TEST_COMMAND(node_list_dump, test_node_list_dump);