numam-dpdk/app/test/test_graph.c
Haiyue Wang 6eccb0c9ee graph: remove useless duplicate name check
The node clone API parameter 'name' is the new node's postfix name, not
the final node name, so it makes no sense to check it. And the new name
will be checked duplicate when calling API '__rte_node_register'.

And update the test case to call clone API twice to check the real name
duplicate.

Signed-off-by: Haiyue Wang <haiyue.wang@intel.com>
Acked-by: Jerin Jacob <jerinj@marvell.com>
2022-03-07 20:31:14 +01:00

866 lines
20 KiB
C

/* SPDX-License-Identifier: BSD-3-Clause
* Copyright(C) 2020 Marvell International Ltd.
*/
#include "test.h"
#include <assert.h>
#include <inttypes.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <rte_errno.h>
#ifdef RTE_EXEC_ENV_WINDOWS
static int
test_node_list_dump(void)
{
printf("node_list_dump not supported on Windows, skipping test\n");
return TEST_SKIPPED;
}
#else
#include <rte_graph.h>
#include <rte_graph_worker.h>
#include <rte_mbuf.h>
#include <rte_mbuf_dyn.h>
#include <rte_random.h>
static uint16_t test_node_worker_source(struct rte_graph *graph,
struct rte_node *node, void **objs,
uint16_t nb_objs);
static uint16_t test_node0_worker(struct rte_graph *graph,
struct rte_node *node, void **objs,
uint16_t nb_objs);
static uint16_t test_node1_worker(struct rte_graph *graph,
struct rte_node *node, void **objs,
uint16_t nb_objs);
static uint16_t test_node2_worker(struct rte_graph *graph,
struct rte_node *node, void **objs,
uint16_t nb_objs);
static uint16_t test_node3_worker(struct rte_graph *graph,
struct rte_node *node, void **objs,
uint16_t nb_objs);
#define MBUFF_SIZE 512
#define MAX_NODES 4
typedef uint64_t graph_dynfield_t;
static int graph_dynfield_offset = -1;
static inline graph_dynfield_t *
graph_field(struct rte_mbuf *mbuf)
{
return RTE_MBUF_DYNFIELD(mbuf, \
graph_dynfield_offset, graph_dynfield_t *);
}
static struct rte_mbuf mbuf[MAX_NODES + 1][MBUFF_SIZE];
static void *mbuf_p[MAX_NODES + 1][MBUFF_SIZE];
static rte_graph_t graph_id;
static uint64_t obj_stats[MAX_NODES + 1];
static uint64_t fn_calls[MAX_NODES + 1];
const char *node_patterns[] = {
"test_node_source1", "test_node00",
"test_node00-test_node11", "test_node00-test_node22",
"test_node00-test_node33",
};
const char *node_names[] = {
"test_node00",
"test_node00-test_node11",
"test_node00-test_node22",
"test_node00-test_node33",
};
struct test_node_register {
char name[RTE_NODE_NAMESIZE];
rte_node_process_t process;
uint16_t nb_edges;
const char *next_nodes[MAX_NODES];
};
typedef struct {
uint32_t idx;
struct test_node_register node;
} test_node_t;
typedef struct {
test_node_t test_node[MAX_NODES];
} test_main_t;
static test_main_t test_main = {
.test_node = {
{
.node = {
.name = "test_node00",
.process = test_node0_worker,
.nb_edges = 2,
.next_nodes = {"test_node00-"
"test_node11",
"test_node00-"
"test_node22"},
},
},
{
.node = {
.name = "test_node11",
.process = test_node1_worker,
.nb_edges = 1,
.next_nodes = {"test_node00-"
"test_node22"},
},
},
{
.node = {
.name = "test_node22",
.process = test_node2_worker,
.nb_edges = 1,
.next_nodes = {"test_node00-"
"test_node33"},
},
},
{
.node = {
.name = "test_node33",
.process = test_node3_worker,
.nb_edges = 1,
.next_nodes = {"test_node00"},
},
},
},
};
static int
node_init(const struct rte_graph *graph, struct rte_node *node)
{
RTE_SET_USED(graph);
*(uint32_t *)node->ctx = node->id;
return 0;
}
static struct rte_node_register test_node_source = {
.name = "test_node_source1",
.process = test_node_worker_source,
.flags = RTE_NODE_SOURCE_F,
.nb_edges = 2,
.init = node_init,
.next_nodes = {"test_node00", "test_node00-test_node11"},
};
RTE_NODE_REGISTER(test_node_source);
static struct rte_node_register test_node0 = {
.name = "test_node00",
.process = test_node0_worker,
.init = node_init,
};
RTE_NODE_REGISTER(test_node0);
uint16_t
test_node_worker_source(struct rte_graph *graph, struct rte_node *node,
void **objs, uint16_t nb_objs)
{
uint32_t obj_node0 = rte_rand() % 100, obj_node1;
test_main_t *tm = &test_main;
struct rte_mbuf *data;
void **next_stream;
rte_node_t next;
uint32_t i;
RTE_SET_USED(objs);
nb_objs = RTE_GRAPH_BURST_SIZE;
/* Prepare stream for next node 0 */
obj_node0 = nb_objs * obj_node0 * 0.01;
next = 0;
next_stream = rte_node_next_stream_get(graph, node, next, obj_node0);
for (i = 0; i < obj_node0; i++) {
data = &mbuf[0][i];
*graph_field(data) = ((uint64_t)tm->test_node[0].idx << 32) | i;
if ((i + 1) == obj_node0)
*graph_field(data) |= (1 << 16);
next_stream[i] = &mbuf[0][i];
}
rte_node_next_stream_put(graph, node, next, obj_node0);
/* Prepare stream for next node 1 */
obj_node1 = nb_objs - obj_node0;
next = 1;
next_stream = rte_node_next_stream_get(graph, node, next, obj_node1);
for (i = 0; i < obj_node1; i++) {
data = &mbuf[0][obj_node0 + i];
*graph_field(data) = ((uint64_t)tm->test_node[1].idx << 32) | i;
if ((i + 1) == obj_node1)
*graph_field(data) |= (1 << 16);
next_stream[i] = &mbuf[0][obj_node0 + i];
}
rte_node_next_stream_put(graph, node, next, obj_node1);
obj_stats[0] += nb_objs;
fn_calls[0] += 1;
return nb_objs;
}
uint16_t
test_node0_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
uint16_t nb_objs)
{
test_main_t *tm = &test_main;
if (*(uint32_t *)node->ctx == test_node0.id) {
uint32_t obj_node0 = rte_rand() % 100, obj_node1;
struct rte_mbuf *data;
uint8_t second_pass = 0;
uint32_t count = 0;
uint32_t i;
obj_stats[1] += nb_objs;
fn_calls[1] += 1;
for (i = 0; i < nb_objs; i++) {
data = (struct rte_mbuf *)objs[i];
if ((*graph_field(data) >> 32) != tm->test_node[0].idx) {
printf("Data idx miss match at node 0, expected"
" = %u got = %u\n",
tm->test_node[0].idx,
(uint32_t)(*graph_field(data) >> 32));
goto end;
}
if ((*graph_field(data) & 0xffff) != (i - count)) {
printf("Expected buff count miss match at "
"node 0\n");
goto end;
}
if (*graph_field(data) & (0x1 << 16))
count = i + 1;
if (*graph_field(data) & (0x1 << 17))
second_pass = 1;
}
if (count != i) {
printf("Count mismatch at node 0\n");
goto end;
}
obj_node0 = nb_objs * obj_node0 * 0.01;
for (i = 0; i < obj_node0; i++) {
data = &mbuf[1][i];
*graph_field(data) =
((uint64_t)tm->test_node[1].idx << 32) | i;
if ((i + 1) == obj_node0)
*graph_field(data) |= (1 << 16);
if (second_pass)
*graph_field(data) |= (1 << 17);
}
rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[1][0],
obj_node0);
obj_node1 = nb_objs - obj_node0;
for (i = 0; i < obj_node1; i++) {
data = &mbuf[1][obj_node0 + i];
*graph_field(data) =
((uint64_t)tm->test_node[2].idx << 32) | i;
if ((i + 1) == obj_node1)
*graph_field(data) |= (1 << 16);
if (second_pass)
*graph_field(data) |= (1 << 17);
}
rte_node_enqueue(graph, node, 1, (void **)&mbuf_p[1][obj_node0],
obj_node1);
} else if (*(uint32_t *)node->ctx == tm->test_node[1].idx) {
test_node1_worker(graph, node, objs, nb_objs);
} else if (*(uint32_t *)node->ctx == tm->test_node[2].idx) {
test_node2_worker(graph, node, objs, nb_objs);
} else if (*(uint32_t *)node->ctx == tm->test_node[3].idx) {
test_node3_worker(graph, node, objs, nb_objs);
} else {
printf("Unexpected node context\n");
}
end:
return nb_objs;
}
uint16_t
test_node1_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
uint16_t nb_objs)
{
test_main_t *tm = &test_main;
uint8_t second_pass = 0;
uint32_t obj_node0 = 0;
struct rte_mbuf *data;
uint32_t count = 0;
uint32_t i;
obj_stats[2] += nb_objs;
fn_calls[2] += 1;
for (i = 0; i < nb_objs; i++) {
data = (struct rte_mbuf *)objs[i];
if ((*graph_field(data) >> 32) != tm->test_node[1].idx) {
printf("Data idx miss match at node 1, expected = %u"
" got = %u\n",
tm->test_node[1].idx,
(uint32_t)(*graph_field(data) >> 32));
goto end;
}
if ((*graph_field(data) & 0xffff) != (i - count)) {
printf("Expected buff count miss match at node 1\n");
goto end;
}
if (*graph_field(data) & (0x1 << 16))
count = i + 1;
if (*graph_field(data) & (0x1 << 17))
second_pass = 1;
}
if (count != i) {
printf("Count mismatch at node 1\n");
goto end;
}
obj_node0 = nb_objs;
for (i = 0; i < obj_node0; i++) {
data = &mbuf[2][i];
*graph_field(data) = ((uint64_t)tm->test_node[2].idx << 32) | i;
if ((i + 1) == obj_node0)
*graph_field(data) |= (1 << 16);
if (second_pass)
*graph_field(data) |= (1 << 17);
}
rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[2][0], obj_node0);
end:
return nb_objs;
}
uint16_t
test_node2_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
uint16_t nb_objs)
{
test_main_t *tm = &test_main;
uint8_t second_pass = 0;
struct rte_mbuf *data;
uint32_t count = 0;
uint32_t obj_node0;
uint32_t i;
obj_stats[3] += nb_objs;
fn_calls[3] += 1;
for (i = 0; i < nb_objs; i++) {
data = (struct rte_mbuf *)objs[i];
if ((*graph_field(data) >> 32) != tm->test_node[2].idx) {
printf("Data idx miss match at node 2, expected = %u"
" got = %u\n",
tm->test_node[2].idx,
(uint32_t)(*graph_field(data) >> 32));
goto end;
}
if ((*graph_field(data) & 0xffff) != (i - count)) {
printf("Expected buff count miss match at node 2\n");
goto end;
}
if (*graph_field(data) & (0x1 << 16))
count = i + 1;
if (*graph_field(data) & (0x1 << 17))
second_pass = 1;
}
if (count != i) {
printf("Count mismatch at node 2\n");
goto end;
}
if (!second_pass) {
obj_node0 = nb_objs;
for (i = 0; i < obj_node0; i++) {
data = &mbuf[3][i];
*graph_field(data) =
((uint64_t)tm->test_node[3].idx << 32) | i;
if ((i + 1) == obj_node0)
*graph_field(data) |= (1 << 16);
}
rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[3][0],
obj_node0);
}
end:
return nb_objs;
}
uint16_t
test_node3_worker(struct rte_graph *graph, struct rte_node *node, void **objs,
uint16_t nb_objs)
{
test_main_t *tm = &test_main;
uint8_t second_pass = 0;
struct rte_mbuf *data;
uint32_t count = 0;
uint32_t obj_node0;
uint32_t i;
obj_stats[4] += nb_objs;
fn_calls[4] += 1;
for (i = 0; i < nb_objs; i++) {
data = (struct rte_mbuf *)objs[i];
if ((*graph_field(data) >> 32) != tm->test_node[3].idx) {
printf("Data idx miss match at node 3, expected = %u"
" got = %u\n",
tm->test_node[3].idx,
(uint32_t)(*graph_field(data) >> 32));
goto end;
}
if ((*graph_field(data) & 0xffff) != (i - count)) {
printf("Expected buff count miss match at node 3\n");
goto end;
}
if (*graph_field(data) & (0x1 << 16))
count = i + 1;
if (*graph_field(data) & (0x1 << 17))
second_pass = 1;
}
if (count != i) {
printf("Count mismatch at node 3\n");
goto end;
}
if (second_pass) {
printf("Unexpected buffers are at node 3\n");
goto end;
} else {
obj_node0 = nb_objs * 2;
for (i = 0; i < obj_node0; i++) {
data = &mbuf[4][i];
*graph_field(data) =
((uint64_t)tm->test_node[0].idx << 32) | i;
*graph_field(data) |= (1 << 17);
if ((i + 1) == obj_node0)
*graph_field(data) |= (1 << 16);
}
rte_node_enqueue(graph, node, 0, (void **)&mbuf_p[4][0],
obj_node0);
}
end:
return nb_objs;
}
static int
test_lookup_functions(void)
{
test_main_t *tm = &test_main;
int i;
/* Verify the name with ID */
for (i = 1; i < MAX_NODES; i++) {
char *name = rte_node_id_to_name(tm->test_node[i].idx);
if (strcmp(name, node_names[i]) != 0) {
printf("Test node name verify by ID = %d failed "
"Expected = %s, got %s\n",
i, node_names[i], name);
return -1;
}
}
/* Verify by name */
for (i = 1; i < MAX_NODES; i++) {
uint32_t idx = rte_node_from_name(node_names[i]);
if (idx != tm->test_node[i].idx) {
printf("Test node ID verify by name = %s failed "
"Expected = %d, got %d\n",
node_names[i], tm->test_node[i].idx, idx);
return -1;
}
}
/* Verify edge count */
for (i = 1; i < MAX_NODES; i++) {
uint32_t count = rte_node_edge_count(tm->test_node[i].idx);
if (count != tm->test_node[i].node.nb_edges) {
printf("Test number of edges for node = %s failed Expected = %d, got = %d\n",
tm->test_node[i].node.name,
tm->test_node[i].node.nb_edges, count);
return -1;
}
}
/* Verify edge names */
for (i = 1; i < MAX_NODES; i++) {
uint32_t j, count;
char **next_edges;
count = rte_node_edge_get(tm->test_node[i].idx, NULL);
if (count != tm->test_node[i].node.nb_edges * sizeof(char *)) {
printf("Test number of edge count for node = %s failed Expected = %d, got = %d\n",
tm->test_node[i].node.name,
tm->test_node[i].node.nb_edges, count);
return -1;
}
next_edges = malloc(count);
count = rte_node_edge_get(tm->test_node[i].idx, next_edges);
if (count != tm->test_node[i].node.nb_edges) {
printf("Test number of edges for node = %s failed Expected = %d, got %d\n",
tm->test_node[i].node.name,
tm->test_node[i].node.nb_edges, count);
free(next_edges);
return -1;
}
for (j = 0; j < count; j++) {
if (strcmp(next_edges[j],
tm->test_node[i].node.next_nodes[j]) != 0) {
printf("Edge name miss match, expected = %s got = %s\n",
tm->test_node[i].node.next_nodes[j],
next_edges[j]);
free(next_edges);
return -1;
}
}
free(next_edges);
}
return 0;
}
static int
test_node_clone(void)
{
test_main_t *tm = &test_main;
uint32_t node_id, dummy_id;
int i;
node_id = rte_node_from_name("test_node00");
tm->test_node[0].idx = node_id;
dummy_id = rte_node_clone(node_id, "test_node00");
if (rte_node_is_invalid(dummy_id)) {
printf("Got invalid id when clone, Expecting fail\n");
return -1;
}
/* Clone with same name, should fail */
dummy_id = rte_node_clone(node_id, "test_node00");
if (!rte_node_is_invalid(dummy_id)) {
printf("Got valid id when clone with same name, Expecting fail\n");
return -1;
}
for (i = 1; i < MAX_NODES; i++) {
tm->test_node[i].idx =
rte_node_clone(node_id, tm->test_node[i].node.name);
if (rte_node_is_invalid(tm->test_node[i].idx)) {
printf("Got invalid node id\n");
return -1;
}
}
/* Clone from cloned node should fail */
dummy_id = rte_node_clone(tm->test_node[1].idx, "dummy_node");
if (!rte_node_is_invalid(dummy_id)) {
printf("Got valid node id when cloning from cloned node, expected fail\n");
return -1;
}
return 0;
}
static int
test_update_edges(void)
{
test_main_t *tm = &test_main;
uint32_t node_id;
uint16_t count;
int i;
node_id = rte_node_from_name("test_node00");
count = rte_node_edge_update(node_id, 0,
tm->test_node[0].node.next_nodes,
tm->test_node[0].node.nb_edges);
if (count != tm->test_node[0].node.nb_edges) {
printf("Update edges failed expected: %d got = %d\n",
tm->test_node[0].node.nb_edges, count);
return -1;
}
for (i = 1; i < MAX_NODES; i++) {
count = rte_node_edge_update(tm->test_node[i].idx, 0,
tm->test_node[i].node.next_nodes,
tm->test_node[i].node.nb_edges);
if (count != tm->test_node[i].node.nb_edges) {
printf("Update edges failed expected: %d got = %d\n",
tm->test_node[i].node.nb_edges, count);
return -1;
}
count = rte_node_edge_shrink(tm->test_node[i].idx,
tm->test_node[i].node.nb_edges);
if (count != tm->test_node[i].node.nb_edges) {
printf("Shrink edges failed\n");
return -1;
}
}
return 0;
}
static int
test_create_graph(void)
{
static const char *node_patterns_dummy[] = {
"test_node_source1", "test_node00",
"test_node00-test_node11", "test_node00-test_node22",
"test_node00-test_node33", "test_node00-dummy_node",
};
struct rte_graph_param gconf = {
.socket_id = SOCKET_ID_ANY,
.nb_node_patterns = 6,
.node_patterns = node_patterns_dummy,
};
uint32_t dummy_node_id;
uint32_t node_id;
node_id = rte_node_from_name("test_node00");
dummy_node_id = rte_node_clone(node_id, "dummy_node");
if (rte_node_is_invalid(dummy_node_id)) {
printf("Got invalid node id\n");
return -1;
}
graph_id = rte_graph_create("worker0", &gconf);
if (graph_id != RTE_GRAPH_ID_INVALID) {
printf("Graph creation success with isolated node, expected graph creation fail\n");
return -1;
}
gconf.nb_node_patterns = 5;
gconf.node_patterns = node_patterns;
graph_id = rte_graph_create("worker0", &gconf);
if (graph_id == RTE_GRAPH_ID_INVALID) {
printf("Graph creation failed with error = %d\n", rte_errno);
return -1;
}
return 0;
}
static int
test_graph_walk(void)
{
struct rte_graph *graph = rte_graph_lookup("worker0");
int i;
if (!graph) {
printf("Graph lookup failed\n");
return -1;
}
for (i = 0; i < 5; i++)
rte_graph_walk(graph);
return 0;
}
static int
test_graph_lookup_functions(void)
{
test_main_t *tm = &test_main;
struct rte_node *node;
int i;
for (i = 0; i < MAX_NODES; i++) {
node = rte_graph_node_get(graph_id, tm->test_node[i].idx);
if (!node) {
printf("rte_graph_node_get, failed for node = %d\n",
tm->test_node[i].idx);
return -1;
}
if (tm->test_node[i].idx != node->id) {
printf("Node id didn't match, expected = %d got = %d\n",
tm->test_node[i].idx, node->id);
return 0;
}
if (strncmp(node->name, node_names[i], RTE_NODE_NAMESIZE)) {
printf("Node name didn't match, expected = %s got %s\n",
node_names[i], node->name);
return -1;
}
}
for (i = 0; i < MAX_NODES; i++) {
node = rte_graph_node_get_by_name("worker0", node_names[i]);
if (!node) {
printf("rte_graph_node_get, failed for node = %d\n",
tm->test_node[i].idx);
return -1;
}
if (tm->test_node[i].idx != node->id) {
printf("Node id didn't match, expected = %d got = %d\n",
tm->test_node[i].idx, node->id);
return 0;
}
if (strncmp(node->name, node_names[i], RTE_NODE_NAMESIZE)) {
printf("Node name didn't match, expected = %s got %s\n",
node_names[i], node->name);
return -1;
}
}
return 0;
}
static int
graph_cluster_stats_cb_t(bool is_first, bool is_last, void *cookie,
const struct rte_graph_cluster_node_stats *st)
{
int i;
RTE_SET_USED(is_first);
RTE_SET_USED(is_last);
RTE_SET_USED(cookie);
for (i = 0; i < MAX_NODES + 1; i++) {
rte_node_t id = rte_node_from_name(node_patterns[i]);
if (id == st->id) {
if (obj_stats[i] != st->objs) {
printf("Obj count miss match for node = %s expected = %"PRId64", got=%"PRId64"\n",
node_patterns[i], obj_stats[i],
st->objs);
return -1;
}
if (fn_calls[i] != st->calls) {
printf("Func call miss match for node = %s expected = %"PRId64", got = %"PRId64"\n",
node_patterns[i], fn_calls[i],
st->calls);
return -1;
}
}
}
return 0;
}
static int
test_print_stats(void)
{
struct rte_graph_cluster_stats_param s_param;
struct rte_graph_cluster_stats *stats;
const char *pattern = "worker0";
if (!rte_graph_has_stats_feature())
return 0;
/* Prepare stats object */
memset(&s_param, 0, sizeof(s_param));
s_param.f = stdout;
s_param.socket_id = SOCKET_ID_ANY;
s_param.graph_patterns = &pattern;
s_param.nb_graph_patterns = 1;
s_param.fn = graph_cluster_stats_cb_t;
stats = rte_graph_cluster_stats_create(&s_param);
if (stats == NULL) {
printf("Unable to get stats\n");
return -1;
}
/* Clear screen and move to top left */
rte_graph_cluster_stats_get(stats, 0);
rte_graph_cluster_stats_destroy(stats);
return 0;
}
static int
graph_setup(void)
{
int i, j;
static const struct rte_mbuf_dynfield graph_dynfield_desc = {
.name = "test_graph_dynfield",
.size = sizeof(graph_dynfield_t),
.align = __alignof__(graph_dynfield_t),
};
graph_dynfield_offset =
rte_mbuf_dynfield_register(&graph_dynfield_desc);
if (graph_dynfield_offset < 0) {
printf("Cannot register mbuf field\n");
return TEST_FAILED;
}
for (i = 0; i <= MAX_NODES; i++) {
for (j = 0; j < MBUFF_SIZE; j++)
mbuf_p[i][j] = &mbuf[i][j];
}
if (test_node_clone()) {
printf("test_node_clone: fail\n");
return -1;
}
printf("test_node_clone: pass\n");
return 0;
}
static void
graph_teardown(void)
{
int id;
id = rte_graph_destroy(rte_graph_from_name("worker0"));
if (id)
printf("Graph Destroy failed\n");
}
static struct unit_test_suite graph_testsuite = {
.suite_name = "Graph library test suite",
.setup = graph_setup,
.teardown = graph_teardown,
.unit_test_cases = {
TEST_CASE(test_update_edges),
TEST_CASE(test_lookup_functions),
TEST_CASE(test_create_graph),
TEST_CASE(test_graph_lookup_functions),
TEST_CASE(test_graph_walk),
TEST_CASE(test_print_stats),
TEST_CASES_END(), /**< NULL terminate unit test array */
},
};
static int
graph_autotest_fn(void)
{
return unit_test_suite_runner(&graph_testsuite);
}
REGISTER_TEST_COMMAND(graph_autotest, graph_autotest_fn);
static int
test_node_list_dump(void)
{
rte_node_list_dump(stdout);
return TEST_SUCCESS;
}
#endif /* !RTE_EXEC_ENV_WINDOWS */
REGISTER_TEST_COMMAND(node_list_dump, test_node_list_dump);