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>
18 static uint16_t test_node_worker_source(struct rte_graph *graph,
19 struct rte_node *node, void **objs,
22 static uint16_t test_node0_worker(struct rte_graph *graph,
23 struct rte_node *node, void **objs,
26 static uint16_t test_node1_worker(struct rte_graph *graph,
27 struct rte_node *node, void **objs,
30 static uint16_t test_node2_worker(struct rte_graph *graph,
31 struct rte_node *node, void **objs,
34 static uint16_t test_node3_worker(struct rte_graph *graph,
35 struct rte_node *node, void **objs,
38 #define MBUFF_SIZE 512
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];
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",
53 const char *node_names[] = {
55 "test_node00-test_node11",
56 "test_node00-test_node22",
57 "test_node00-test_node33",
60 struct test_node_register {
61 char name[RTE_NODE_NAMESIZE];
62 rte_node_process_t process;
64 const char *next_nodes[MAX_NODES];
69 struct test_node_register node;
73 test_node_t test_node[MAX_NODES];
76 static test_main_t test_main = {
80 .name = "test_node00",
81 .process = test_node0_worker,
83 .next_nodes = {"test_node00-"
91 .name = "test_node11",
92 .process = test_node1_worker,
94 .next_nodes = {"test_node00-"
100 .name = "test_node22",
101 .process = test_node2_worker,
103 .next_nodes = {"test_node00-"
109 .name = "test_node33",
110 .process = test_node3_worker,
112 .next_nodes = {"test_node00"},
119 node_init(const struct rte_graph *graph, struct rte_node *node)
122 *(uint32_t *)node->ctx = node->id;
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,
133 .next_nodes = {"test_node00", "test_node00-test_node11"},
135 RTE_NODE_REGISTER(test_node_source);
137 static struct rte_node_register test_node0 = {
138 .name = "test_node00",
139 .process = test_node0_worker,
142 RTE_NODE_REGISTER(test_node0);
145 test_node_worker_source(struct rte_graph *graph, struct rte_node *node,
146 void **objs, uint16_t nb_objs)
148 uint32_t obj_node0 = rand() % 100, obj_node1;
149 test_main_t *tm = &test_main;
150 struct rte_mbuf *data;
156 nb_objs = RTE_GRAPH_BURST_SIZE;
158 /* Prepare stream for next node 0 */
159 obj_node0 = nb_objs * obj_node0 * 0.01;
161 next_stream = rte_node_next_stream_get(graph, node, next, obj_node0);
162 for (i = 0; i < obj_node0; 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];
169 rte_node_next_stream_put(graph, node, next, obj_node0);
171 /* Prepare stream for next node 1 */
172 obj_node1 = nb_objs - obj_node0;
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];
183 rte_node_next_stream_put(graph, node, next, obj_node1);
184 obj_stats[0] += nb_objs;
190 test_node0_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
193 test_main_t *tm = &test_main;
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;
202 obj_stats[1] += nb_objs;
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"
210 tm->test_node[0].idx,
211 (uint32_t)(data->udata64 >> 32));
215 if ((data->udata64 & 0xffff) != (i - count)) {
216 printf("Expected buff count miss match at "
221 if (data->udata64 & (0x1 << 16))
223 if (data->udata64 & (0x1 << 17))
228 printf("Count mismatch at node 0\n");
232 obj_node0 = nb_objs * obj_node0 * 0.01;
233 for (i = 0; i < obj_node0; i++) {
236 ((uint64_t)tm->test_node[1].idx << 32) | i;
237 if ((i + 1) == obj_node0)
238 data->udata64 |= (1 << 16);
240 data->udata64 |= (1 << 17);
242 rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[1][0],
245 obj_node1 = nb_objs - obj_node0;
246 for (i = 0; i < obj_node1; i++) {
247 data = &mbuf[1][obj_node0 + i];
249 ((uint64_t)tm->test_node[2].idx << 32) | i;
250 if ((i + 1) == obj_node1)
251 data->udata64 |= (1 << 16);
253 data->udata64 |= (1 << 17);
255 rte_node_enqueue(graph, node, 1, (void **)&mbuf_p[1][obj_node0],
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);
265 printf("Unexpected node context\n");
273 test_node1_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
276 test_main_t *tm = &test_main;
277 uint8_t second_pass = 0;
278 uint32_t obj_node0 = 0;
279 struct rte_mbuf *data;
283 obj_stats[2] += nb_objs;
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"
290 tm->test_node[1].idx,
291 (uint32_t)(data->udata64 >> 32));
295 if ((data->udata64 & 0xffff) != (i - count)) {
296 printf("Expected buff count miss match at node 1\n");
300 if (data->udata64 & (0x1 << 16))
302 if (data->udata64 & (0x1 << 17))
307 printf("Count mismatch at node 1\n");
312 for (i = 0; i < obj_node0; i++) {
314 data->udata64 = ((uint64_t)tm->test_node[2].idx << 32) | i;
315 if ((i + 1) == obj_node0)
316 data->udata64 |= (1 << 16);
318 data->udata64 |= (1 << 17);
320 rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[2][0], obj_node0);
327 test_node2_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
330 test_main_t *tm = &test_main;
331 uint8_t second_pass = 0;
332 struct rte_mbuf *data;
337 obj_stats[3] += nb_objs;
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"
344 tm->test_node[2].idx,
345 (uint32_t)(data->udata64 >> 32));
349 if ((data->udata64 & 0xffff) != (i - count)) {
350 printf("Expected buff count miss match at node 2\n");
354 if (data->udata64 & (0x1 << 16))
356 if (data->udata64 & (0x1 << 17))
361 printf("Count mismatch at node 2\n");
367 for (i = 0; i < obj_node0; i++) {
370 ((uint64_t)tm->test_node[3].idx << 32) | i;
371 if ((i + 1) == obj_node0)
372 data->udata64 |= (1 << 16);
374 rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[3][0],
383 test_node3_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
386 test_main_t *tm = &test_main;
387 uint8_t second_pass = 0;
388 struct rte_mbuf *data;
393 obj_stats[4] += nb_objs;
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"
400 tm->test_node[3].idx,
401 (uint32_t)(data->udata64 >> 32));
405 if ((data->udata64 & 0xffff) != (i - count)) {
406 printf("Expected buff count miss match at node 3\n");
410 if (data->udata64 & (0x1 << 16))
412 if (data->udata64 & (0x1 << 17))
417 printf("Count mismatch at node 3\n");
422 printf("Unexpected buffers are at node 3\n");
425 obj_node0 = nb_objs * 2;
426 for (i = 0; i < obj_node0; i++) {
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);
434 rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[4][0],
443 test_lookup_functions(void)
445 test_main_t *tm = &test_main;
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);
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);
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);
481 /* Verify edge names */
482 for (i = 1; i < MAX_NODES; i++) {
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);
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);
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],
518 test_node_clone(void)
520 test_main_t *tm = &test_main;
521 uint32_t node_id, dummy_id;
524 node_id = rte_node_from_name("test_node00");
525 tm->test_node[0].idx = node_id;
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");
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");
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");
554 test_update_edges(void)
556 test_main_t *tm = &test_main;
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);
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);
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");
593 test_create_graph(void)
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",
600 struct rte_graph_param gconf = {
601 .socket_id = SOCKET_ID_ANY,
602 .nb_node_patterns = 6,
603 .node_patterns = node_patterns_dummy,
605 uint32_t dummy_node_id;
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");
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");
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);
632 test_graph_walk(void)
634 struct rte_graph *graph = rte_graph_lookup("worker0");
638 printf("Graph lookup failed\n");
642 for (i = 0; i < 5; i++)
643 rte_graph_walk(graph);
648 test_graph_lookup_functions(void)
650 test_main_t *tm = &test_main;
651 struct rte_node *node;
654 for (i = 0; i < MAX_NODES; i++) {
655 node = rte_graph_node_get(graph_id, tm->test_node[i].idx);
657 printf("rte_graph_node_get, failed for node = %d\n",
658 tm->test_node[i].idx);
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);
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);
675 for (i = 0; i < MAX_NODES; i++) {
676 node = rte_graph_node_get_by_name("worker0", node_names[i]);
678 printf("rte_graph_node_get, failed for node = %d\n",
679 tm->test_node[i].idx);
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);
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);
700 graph_cluster_stats_cb_t(bool is_first, bool is_last, void *cookie,
701 const struct rte_graph_cluster_node_stats *st)
705 RTE_SET_USED(is_first);
706 RTE_SET_USED(is_last);
707 RTE_SET_USED(cookie);
709 for (i = 0; i < MAX_NODES + 1; i++) {
710 rte_node_t id = rte_node_from_name(node_patterns[i]);
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],
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],
731 test_print_stats(void)
733 struct rte_graph_cluster_stats_param s_param;
734 struct rte_graph_cluster_stats *stats;
735 const char *pattern = "worker0";
737 if (!rte_graph_has_stats_feature())
740 /* Prepare stats object */
741 memset(&s_param, 0, sizeof(s_param));
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;
748 stats = rte_graph_cluster_stats_create(&s_param);
750 printf("Unable to get stats\n");
753 /* Clear screen and move to top left */
754 rte_graph_cluster_stats_get(stats, 0);
755 rte_graph_cluster_stats_destroy(stats);
765 for (i = 0; i <= MAX_NODES; i++) {
766 for (j = 0; j < MBUFF_SIZE; j++)
767 mbuf_p[i][j] = &mbuf[i][j];
769 if (test_node_clone()) {
770 printf("test_node_clone: fail\n");
773 printf("test_node_clone: pass\n");
783 id = rte_graph_destroy(rte_graph_from_name("worker0"));
785 printf("Graph Destroy failed\n");
788 static struct unit_test_suite graph_testsuite = {
789 .suite_name = "Graph library test suite",
790 .setup = graph_setup,
791 .teardown = graph_teardown,
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 */
804 graph_autotest_fn(void)
806 return unit_test_suite_runner(&graph_testsuite);
809 REGISTER_TEST_COMMAND(graph_autotest, graph_autotest_fn);
812 test_node_list_dump(void)
814 rte_node_list_dump(stdout);
818 REGISTER_TEST_COMMAND(node_list_dump, test_node_list_dump);