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_random.h>
19 static uint16_t test_node_worker_source(struct rte_graph *graph,
20 struct rte_node *node, void **objs,
23 static uint16_t test_node0_worker(struct rte_graph *graph,
24 struct rte_node *node, void **objs,
27 static uint16_t test_node1_worker(struct rte_graph *graph,
28 struct rte_node *node, void **objs,
31 static uint16_t test_node2_worker(struct rte_graph *graph,
32 struct rte_node *node, void **objs,
35 static uint16_t test_node3_worker(struct rte_graph *graph,
36 struct rte_node *node, void **objs,
39 #define MBUFF_SIZE 512
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];
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",
54 const char *node_names[] = {
56 "test_node00-test_node11",
57 "test_node00-test_node22",
58 "test_node00-test_node33",
61 struct test_node_register {
62 char name[RTE_NODE_NAMESIZE];
63 rte_node_process_t process;
65 const char *next_nodes[MAX_NODES];
70 struct test_node_register node;
74 test_node_t test_node[MAX_NODES];
77 static test_main_t test_main = {
81 .name = "test_node00",
82 .process = test_node0_worker,
84 .next_nodes = {"test_node00-"
92 .name = "test_node11",
93 .process = test_node1_worker,
95 .next_nodes = {"test_node00-"
101 .name = "test_node22",
102 .process = test_node2_worker,
104 .next_nodes = {"test_node00-"
110 .name = "test_node33",
111 .process = test_node3_worker,
113 .next_nodes = {"test_node00"},
120 node_init(const struct rte_graph *graph, struct rte_node *node)
123 *(uint32_t *)node->ctx = node->id;
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,
134 .next_nodes = {"test_node00", "test_node00-test_node11"},
136 RTE_NODE_REGISTER(test_node_source);
138 static struct rte_node_register test_node0 = {
139 .name = "test_node00",
140 .process = test_node0_worker,
143 RTE_NODE_REGISTER(test_node0);
146 test_node_worker_source(struct rte_graph *graph, struct rte_node *node,
147 void **objs, uint16_t nb_objs)
149 uint32_t obj_node0 = rte_rand() % 100, obj_node1;
150 test_main_t *tm = &test_main;
151 struct rte_mbuf *data;
157 nb_objs = RTE_GRAPH_BURST_SIZE;
159 /* Prepare stream for next node 0 */
160 obj_node0 = nb_objs * obj_node0 * 0.01;
162 next_stream = rte_node_next_stream_get(graph, node, next, obj_node0);
163 for (i = 0; i < obj_node0; 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];
170 rte_node_next_stream_put(graph, node, next, obj_node0);
172 /* Prepare stream for next node 1 */
173 obj_node1 = nb_objs - obj_node0;
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];
184 rte_node_next_stream_put(graph, node, next, obj_node1);
185 obj_stats[0] += nb_objs;
191 test_node0_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
194 test_main_t *tm = &test_main;
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;
203 obj_stats[1] += nb_objs;
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"
211 tm->test_node[0].idx,
212 (uint32_t)(data->udata64 >> 32));
216 if ((data->udata64 & 0xffff) != (i - count)) {
217 printf("Expected buff count miss match at "
222 if (data->udata64 & (0x1 << 16))
224 if (data->udata64 & (0x1 << 17))
229 printf("Count mismatch at node 0\n");
233 obj_node0 = nb_objs * obj_node0 * 0.01;
234 for (i = 0; i < obj_node0; i++) {
237 ((uint64_t)tm->test_node[1].idx << 32) | i;
238 if ((i + 1) == obj_node0)
239 data->udata64 |= (1 << 16);
241 data->udata64 |= (1 << 17);
243 rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[1][0],
246 obj_node1 = nb_objs - obj_node0;
247 for (i = 0; i < obj_node1; i++) {
248 data = &mbuf[1][obj_node0 + i];
250 ((uint64_t)tm->test_node[2].idx << 32) | i;
251 if ((i + 1) == obj_node1)
252 data->udata64 |= (1 << 16);
254 data->udata64 |= (1 << 17);
256 rte_node_enqueue(graph, node, 1, (void **)&mbuf_p[1][obj_node0],
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);
266 printf("Unexpected node context\n");
274 test_node1_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
277 test_main_t *tm = &test_main;
278 uint8_t second_pass = 0;
279 uint32_t obj_node0 = 0;
280 struct rte_mbuf *data;
284 obj_stats[2] += nb_objs;
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"
291 tm->test_node[1].idx,
292 (uint32_t)(data->udata64 >> 32));
296 if ((data->udata64 & 0xffff) != (i - count)) {
297 printf("Expected buff count miss match at node 1\n");
301 if (data->udata64 & (0x1 << 16))
303 if (data->udata64 & (0x1 << 17))
308 printf("Count mismatch at node 1\n");
313 for (i = 0; i < obj_node0; i++) {
315 data->udata64 = ((uint64_t)tm->test_node[2].idx << 32) | i;
316 if ((i + 1) == obj_node0)
317 data->udata64 |= (1 << 16);
319 data->udata64 |= (1 << 17);
321 rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[2][0], obj_node0);
328 test_node2_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
331 test_main_t *tm = &test_main;
332 uint8_t second_pass = 0;
333 struct rte_mbuf *data;
338 obj_stats[3] += nb_objs;
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"
345 tm->test_node[2].idx,
346 (uint32_t)(data->udata64 >> 32));
350 if ((data->udata64 & 0xffff) != (i - count)) {
351 printf("Expected buff count miss match at node 2\n");
355 if (data->udata64 & (0x1 << 16))
357 if (data->udata64 & (0x1 << 17))
362 printf("Count mismatch at node 2\n");
368 for (i = 0; i < obj_node0; i++) {
371 ((uint64_t)tm->test_node[3].idx << 32) | i;
372 if ((i + 1) == obj_node0)
373 data->udata64 |= (1 << 16);
375 rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[3][0],
384 test_node3_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
387 test_main_t *tm = &test_main;
388 uint8_t second_pass = 0;
389 struct rte_mbuf *data;
394 obj_stats[4] += nb_objs;
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"
401 tm->test_node[3].idx,
402 (uint32_t)(data->udata64 >> 32));
406 if ((data->udata64 & 0xffff) != (i - count)) {
407 printf("Expected buff count miss match at node 3\n");
411 if (data->udata64 & (0x1 << 16))
413 if (data->udata64 & (0x1 << 17))
418 printf("Count mismatch at node 3\n");
423 printf("Unexpected buffers are at node 3\n");
426 obj_node0 = nb_objs * 2;
427 for (i = 0; i < obj_node0; i++) {
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);
435 rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[4][0],
444 test_lookup_functions(void)
446 test_main_t *tm = &test_main;
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);
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);
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);
482 /* Verify edge names */
483 for (i = 1; i < MAX_NODES; i++) {
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);
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);
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],
521 test_node_clone(void)
523 test_main_t *tm = &test_main;
524 uint32_t node_id, dummy_id;
527 node_id = rte_node_from_name("test_node00");
528 tm->test_node[0].idx = node_id;
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");
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");
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");
557 test_update_edges(void)
559 test_main_t *tm = &test_main;
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);
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);
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");
596 test_create_graph(void)
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",
603 struct rte_graph_param gconf = {
604 .socket_id = SOCKET_ID_ANY,
605 .nb_node_patterns = 6,
606 .node_patterns = node_patterns_dummy,
608 uint32_t dummy_node_id;
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");
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");
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);
635 test_graph_walk(void)
637 struct rte_graph *graph = rte_graph_lookup("worker0");
641 printf("Graph lookup failed\n");
645 for (i = 0; i < 5; i++)
646 rte_graph_walk(graph);
651 test_graph_lookup_functions(void)
653 test_main_t *tm = &test_main;
654 struct rte_node *node;
657 for (i = 0; i < MAX_NODES; i++) {
658 node = rte_graph_node_get(graph_id, tm->test_node[i].idx);
660 printf("rte_graph_node_get, failed for node = %d\n",
661 tm->test_node[i].idx);
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);
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);
678 for (i = 0; i < MAX_NODES; i++) {
679 node = rte_graph_node_get_by_name("worker0", node_names[i]);
681 printf("rte_graph_node_get, failed for node = %d\n",
682 tm->test_node[i].idx);
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);
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);
703 graph_cluster_stats_cb_t(bool is_first, bool is_last, void *cookie,
704 const struct rte_graph_cluster_node_stats *st)
708 RTE_SET_USED(is_first);
709 RTE_SET_USED(is_last);
710 RTE_SET_USED(cookie);
712 for (i = 0; i < MAX_NODES + 1; i++) {
713 rte_node_t id = rte_node_from_name(node_patterns[i]);
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],
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],
734 test_print_stats(void)
736 struct rte_graph_cluster_stats_param s_param;
737 struct rte_graph_cluster_stats *stats;
738 const char *pattern = "worker0";
740 if (!rte_graph_has_stats_feature())
743 /* Prepare stats object */
744 memset(&s_param, 0, sizeof(s_param));
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;
751 stats = rte_graph_cluster_stats_create(&s_param);
753 printf("Unable to get stats\n");
756 /* Clear screen and move to top left */
757 rte_graph_cluster_stats_get(stats, 0);
758 rte_graph_cluster_stats_destroy(stats);
768 for (i = 0; i <= MAX_NODES; i++) {
769 for (j = 0; j < MBUFF_SIZE; j++)
770 mbuf_p[i][j] = &mbuf[i][j];
772 if (test_node_clone()) {
773 printf("test_node_clone: fail\n");
776 printf("test_node_clone: pass\n");
786 id = rte_graph_destroy(rte_graph_from_name("worker0"));
788 printf("Graph Destroy failed\n");
791 static struct unit_test_suite graph_testsuite = {
792 .suite_name = "Graph library test suite",
793 .setup = graph_setup,
794 .teardown = graph_teardown,
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 */
807 graph_autotest_fn(void)
809 return unit_test_suite_runner(&graph_testsuite);
812 REGISTER_TEST_COMMAND(graph_autotest, graph_autotest_fn);
815 test_node_list_dump(void)
817 rte_node_list_dump(stdout);
821 REGISTER_TEST_COMMAND(node_list_dump, test_node_list_dump);