From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id BBB63A0524; Fri, 31 Jan 2020 18:04:49 +0100 (CET) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 96E9D1C122; Fri, 31 Jan 2020 18:04:49 +0100 (CET) Received: from mx0b-0016f401.pphosted.com (mx0b-0016f401.pphosted.com [67.231.156.173]) by dpdk.org (Postfix) with ESMTP id 98D541C117; Fri, 31 Jan 2020 18:04:47 +0100 (CET) Received: from pps.filterd (m0045851.ppops.net [127.0.0.1]) by mx0b-0016f401.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 00VGuEWb032452; Fri, 31 Jan 2020 09:04:42 -0800 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=marvell.com; h=from : to : cc : subject : date : message-id : in-reply-to : references : mime-version : content-transfer-encoding : content-type; s=pfpt0818; bh=57o9hPx3mKltrNGOeu3k+pbJ1RInMQFMQZWLwdlJsNc=; b=tc6ZgPHErSMakdr3g6mshnHPiNnln/8oiql4+m9ndG3BNugFH7tSYefsNDLgypr1mlqG dX59WmeZvipUwJP0jTY2r3oNiOqfLVgcXMeAAGMfN/bH4ZZpdcu+xhDRPpjerQViSi4+ +d60V/liY/kpmd7hj8EVTFwQhjwrKD8H7/pu4WyDgqKc0vErUYS9/Nq79J8YZSmMULss MQJL/IZ9gw09C1YCDfN6GkUGUd+30l545pSmCEDL7Fnkf9uYKaxVivVssrwDm6aYRtGI tASJQvgUzSTjuYXN4e1COkHD5Ki5TlWtBG3jFQl0RE7cOlT8ubDsFqYUE/2rbYQiimm4 aw== Received: from sc-exch02.marvell.com ([199.233.58.182]) by mx0b-0016f401.pphosted.com with ESMTP id 2xrp2tmggq-6 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-SHA384 bits=256 verify=NOT); Fri, 31 Jan 2020 09:04:42 -0800 Received: from SC-EXCH03.marvell.com (10.93.176.83) by SC-EXCH02.marvell.com (10.93.176.82) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Fri, 31 Jan 2020 09:03:11 -0800 Received: from maili.marvell.com (10.93.176.43) by SC-EXCH03.marvell.com (10.93.176.83) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Fri, 31 Jan 2020 09:03:10 -0800 Received: from jerin-lab.marvell.com (jerin-lab.marvell.com [10.28.34.14]) by maili.marvell.com (Postfix) with ESMTP id 02FA93F7040; Fri, 31 Jan 2020 09:03:00 -0800 (PST) From: To: CC: , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , Date: Fri, 31 Jan 2020 22:32:00 +0530 Message-ID: <20200131170201.3236153-5-jerinj@marvell.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200131170201.3236153-1-jerinj@marvell.com> References: <20200131170201.3236153-1-jerinj@marvell.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Content-Type: text/plain X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.572 definitions=2020-01-31_04:2020-01-31, 2020-01-31 signatures=0 Subject: [dpdk-dev] [RFC PATCH 4/5] test: add graph performance test cases. X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" From: Pavan Nikhilesh Example command to execute the test: echo "graph_perf_autotest" | sudo ./build/app/test/dpdk-test -c 0x30 Signed-off-by: Pavan Nikhilesh --- app/test/Makefile | 1 + app/test/meson.build | 1 + app/test/test_graph_perf.c | 888 +++++++++++++++++++++++++++++++++++++ 3 files changed, 890 insertions(+) create mode 100644 app/test/test_graph_perf.c diff --git a/app/test/Makefile b/app/test/Makefile index e1dbe297e..429c32209 100644 --- a/app/test/Makefile +++ b/app/test/Makefile @@ -222,6 +222,7 @@ endif ifeq ($(CONFIG_RTE_LIBRTE_GRAPH), y) SRCS-y += test_graph.c +SRCS-y += test_graph_perf.c endif ifeq ($(CONFIG_RTE_LIBRTE_RAWDEV),y) diff --git a/app/test/meson.build b/app/test/meson.build index d5d0c2173..a0f3d3389 100644 --- a/app/test/meson.build +++ b/app/test/meson.build @@ -55,6 +55,7 @@ test_sources = files('commands.c', 'test_func_reentrancy.c', 'test_flow_classify.c', 'test_graph.c', + 'test_graph_perf.c', 'test_hash.c', 'test_hash_functions.c', 'test_hash_multiwriter.c', diff --git a/app/test/test_graph_perf.c b/app/test/test_graph_perf.c new file mode 100644 index 000000000..364cfd15a --- /dev/null +++ b/app/test/test_graph_perf.c @@ -0,0 +1,888 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2020 Marvell International Ltd. + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test.h" + +#define TEST_GRAPH_PERF_MZ "graph_perf_data" +#define TEST_GRAPH_SRC_NAME "test_graph_perf_source" +#define TEST_GRAPH_SRC_BRST_ONE_NAME "test_graph_perf_source_one" +#define TEST_GRAPH_WRK_NAME "test_graph_perf_worker" +#define TEST_GRAPH_SNK_NAME "test_graph_perf_sink" + +#define SOURCES(map) sizeof(map)/sizeof(map[0]) +#define STAGES(map) sizeof(map)/sizeof(map[0]) +#define NODES_PER_STAGE(map) sizeof(map[0])/sizeof(map[0][0]) +#define SINKS(map) sizeof(map[0])/sizeof(map[0][0]) + +#define MAX_EDGES_PER_NODE 7 + +struct test_node_data { + uint8_t node_id; + uint8_t is_sink; + uint8_t next_nodes[MAX_EDGES_PER_NODE]; + uint8_t next_percentage[MAX_EDGES_PER_NODE]; +}; + +struct test_graph_perf { + uint16_t nb_nodes; + rte_graph_t graph_id; + struct test_node_data *node_data; +}; + +struct graph_lcore_data { + uint8_t done; + rte_graph_t graph_id; +}; + +static struct test_node_data * +graph_get_node_data(struct test_graph_perf *graph_data, rte_node_t id) +{ + struct test_node_data *node_data = NULL; + int i; + + for (i = 0; i < graph_data->nb_nodes; i++) + if (graph_data->node_data[i].node_id == id) { + node_data = &graph_data->node_data[i]; + break; + } + + return node_data; +} + +static int +test_node_ctx_init(const struct rte_graph *graph, struct rte_node *node) +{ + struct test_graph_perf *graph_data; + struct test_node_data *node_data; + const struct rte_memzone *mz; + rte_node_t nid = node->id; + rte_edge_t edge = 0; + int i; + + RTE_SET_USED(graph); + + mz = rte_memzone_lookup(TEST_GRAPH_PERF_MZ); + graph_data = mz->addr; + node_data = graph_get_node_data(graph_data, nid); + node->ctx[0] = node->nb_edges; + for (i = 0; i < node->nb_edges && !node_data->is_sink; i++, edge++) { + node->ctx[i + 1] = edge; + node->ctx[i + 9] = node_data->next_percentage[i]; + } + + + return 0; +} + +static uint16_t +test_perf_node_worker_source(struct rte_graph *graph, + struct rte_node *node, void **objs, + uint16_t nb_objs) +{ + uint16_t count; + int i; + + RTE_SET_USED(objs); + RTE_SET_USED(nb_objs); + + for (i = 0; i < node->ctx[0]; i++) { + count = (node->ctx[i + 9] * RTE_GRAPH_BURST_SIZE) / 100; + rte_node_next_stream_get(graph, node, node->ctx[i + 1], count); + rte_node_next_stream_put(graph, node, node->ctx[i + 1], count); + } + + return RTE_GRAPH_BURST_SIZE; +} + +static struct rte_node_register test_graph_perf_source = { + .name = TEST_GRAPH_SRC_NAME, + .process = test_perf_node_worker_source, + .flags = RTE_NODE_SOURCE_F, + .init = test_node_ctx_init, +}; + +RTE_NODE_REGISTER(test_graph_perf_source); + +static uint16_t +test_perf_node_worker_source_burst_one(struct rte_graph *graph, + struct rte_node *node, void **objs, + uint16_t nb_objs) +{ + uint16_t count; + int i; + + RTE_SET_USED(objs); + RTE_SET_USED(nb_objs); + + for (i = 0; i < node->ctx[0]; i++) { + count = (node->ctx[i + 9]) / 100; + rte_node_next_stream_get(graph, node, node->ctx[i + 1], count); + rte_node_next_stream_put(graph, node, node->ctx[i + 1], count); + } + + return 1; +} + +static struct rte_node_register test_graph_perf_source_burst_one = { + .name = TEST_GRAPH_SRC_BRST_ONE_NAME, + .process = test_perf_node_worker_source_burst_one, + .flags = RTE_NODE_SOURCE_F, + .init = test_node_ctx_init, +}; + +RTE_NODE_REGISTER(test_graph_perf_source_burst_one); + +static uint16_t +test_perf_node_worker(struct rte_graph *graph, + struct rte_node *node, void **objs, uint16_t nb_objs) +{ + uint16_t next = 0; + uint16_t enq = 0; + uint16_t count; + int i; + + if (node->ctx[0] == 1) { + rte_node_next_stream_move(graph, node, node->ctx[1]); + return nb_objs; + } + + for (i = 0; i < node->ctx[0]; i++) { + next = node->ctx[i + 1]; + count = (node->ctx[i + 9] * nb_objs) / 100; + enq += count; + while (count) { + switch (count & (4 - 1)) { + case 0: + rte_node_enqueue_x4(graph, node, next, objs[0], + objs[1], objs[2], objs[3]); + objs += 4; + count -= 4; + break; + case 1: + rte_node_enqueue_x1(graph, node, next, objs[0]); + objs += 1; + count -= 1; + break; + case 2: + rte_node_enqueue_x2(graph, node, next, objs[0], + objs[1]); + objs += 2; + count -= 2; + break; + case 3: + rte_node_enqueue_x2(graph, node, next, objs[0], + objs[1]); + rte_node_enqueue_x1(graph, node, next, objs[0]); + objs += 3; + count -= 3; + break; + } + } + + } + + if (enq != nb_objs) + rte_node_enqueue(graph, node, next, objs, nb_objs - enq); + + return nb_objs; +} + +static struct rte_node_register test_graph_perf_worker = { + .name = TEST_GRAPH_WRK_NAME, + .process = test_perf_node_worker, + .init = test_node_ctx_init, +}; + +RTE_NODE_REGISTER(test_graph_perf_worker); + +static uint16_t +test_perf_node_sink(struct rte_graph *graph, + struct rte_node *node, void **objs, + uint16_t nb_objs) +{ + RTE_SET_USED(graph); + RTE_SET_USED(node); + RTE_SET_USED(objs); + RTE_SET_USED(nb_objs); + + return nb_objs; +} + +static struct rte_node_register test_graph_perf_sink = { + .name = TEST_GRAPH_SNK_NAME, + .process = test_perf_node_sink, + .init = test_node_ctx_init, +}; + +RTE_NODE_REGISTER(test_graph_perf_sink); + +static int graph_perf_setup(void) +{ + if (rte_lcore_count() < 2) { + printf("Test requires atleast 2 lcores\n"); + return TEST_SKIPPED; + } + + return 0; +} + +static void graph_perf_teardown(void) +{ +} + +static inline rte_node_t +graph_node_get(const char *pname, char *nname) +{ + rte_node_t pnode_id = rte_node_from_name(pname); + char lookup_name[RTE_NODE_NAMESIZE]; + rte_node_t node_id; + + snprintf(lookup_name, RTE_NODE_NAMESIZE, "%s-%s", pname, nname); + node_id = rte_node_from_name(lookup_name); + + if (node_id != RTE_NODE_ID_INVALID) { + if (rte_node_edge_count(node_id)) + rte_node_edge_shrink(node_id, 0); + return node_id; + } + + return rte_node_clone(pnode_id, nname); +} + +static uint16_t +graph_node_count_edges(uint32_t stage, uint16_t node, uint16_t nodes_per_stage, + uint8_t edge_map[][nodes_per_stage][nodes_per_stage], + char *ename[], struct test_node_data *node_data, + rte_node_t **node_map) +{ + uint8_t total_percent = 0; + uint16_t edges = 0; + int i; + + for (i = 0; i < nodes_per_stage && edges < MAX_EDGES_PER_NODE; i++) { + if (edge_map[stage + 1][i][node]) { + ename[edges] = malloc(sizeof(char) * RTE_NODE_NAMESIZE); + snprintf(ename[edges], RTE_NODE_NAMESIZE, "%s", + rte_node_id_to_name(node_map[stage + 1][i])); + node_data->next_nodes[edges] = node_map[stage + 1][i]; + node_data->next_percentage[edges] = + edge_map[stage + 1][i][node]; + edges++; + total_percent += edge_map[stage + 1][i][node]; + } + } + + if (edges >= MAX_EDGES_PER_NODE || (edges && total_percent != 100)) { + for (i = 0; i < edges; i++) + free(ename[i]); + return RTE_EDGE_ID_INVALID; + } + + return edges; +} + +static int graph_init(const char *gname, uint8_t nb_srcs, uint8_t nb_sinks, + uint32_t stages, uint16_t nodes_per_stage, + uint8_t src_map[][nodes_per_stage], + uint8_t snk_map[][nb_sinks], + uint8_t edge_map[][nodes_per_stage][nodes_per_stage], + uint8_t burst_one) +{ + struct test_graph_perf *graph_data; + char nname[RTE_NODE_NAMESIZE / 2]; + struct test_node_data *node_data; + char *ename[nodes_per_stage]; + struct rte_graph_param gconf; + const struct rte_memzone *mz; + uint8_t total_percent = 0; + rte_node_t *src_nodes; + rte_node_t *snk_nodes; + rte_node_t **node_map; + char **node_patterns; + rte_graph_t graph_id; + rte_edge_t edges; + rte_edge_t count; + uint32_t i, j, k; + + mz = rte_memzone_reserve(TEST_GRAPH_PERF_MZ, + sizeof(struct test_graph_perf), 0, 0); + if (mz == NULL) { + printf("failed to allocate graph common memory\n"); + return -ENOMEM; + } + + graph_data = mz->addr; + graph_data->nb_nodes = 0; + graph_data->node_data = malloc(sizeof(struct test_node_data) * + (nb_srcs + nb_sinks + stages * + nodes_per_stage)); + if (graph_data->node_data == NULL) { + printf("failed to reserve memzone for graph data\n"); + goto memzone_free; + } + + node_patterns = malloc(sizeof(char *) * (nb_srcs + nb_sinks + stages * + nodes_per_stage)); + if (node_patterns == NULL) { + printf("failed to reserve memory for node patterns\n"); + goto data_free; + } + + src_nodes = malloc(sizeof(rte_node_t) * nb_srcs); + if (src_nodes == NULL) { + printf("failed to reserve memory for src nodes\n"); + goto pattern_free; + } + + snk_nodes = malloc(sizeof(rte_node_t) * nb_sinks); + if (snk_nodes == NULL) { + printf("failed to reserve memory for snk nodes\n"); + goto src_free; + } + + node_map = malloc(sizeof(rte_node_t *) * stages + sizeof(rte_node_t) * + nodes_per_stage * stages); + if (node_map == NULL) { + printf("failed to reserve memory for node map\n"); + goto snk_free; + } + + /* Setup the Graph */ + for (i = 0; i < stages; i++) { + node_map[i] = (rte_node_t *) (node_map + stages) + + nodes_per_stage * i; + for (j = 0; j < nodes_per_stage; j++) { + total_percent = 0; + for (k = 0; k < nodes_per_stage; k++) + total_percent += edge_map[i][j][k]; + if (!total_percent) + continue; + node_patterns[graph_data->nb_nodes] = + malloc(RTE_NODE_NAMESIZE); + if (node_patterns[graph_data->nb_nodes] == NULL) { + printf("Failed to create memory for pattern\n"); + goto pattern_name_free; + } + snprintf(nname, sizeof(nname), "%d-%d", i, j); + node_map[i][j] = graph_node_get(TEST_GRAPH_WRK_NAME, + nname); + if (node_map[i][j] == RTE_NODE_ID_INVALID) { + printf("Failed to create node[%s]\n", nname); + graph_data->nb_nodes++; + goto pattern_name_free; + } + snprintf(node_patterns[graph_data->nb_nodes], + RTE_NODE_NAMESIZE, "%s", + rte_node_id_to_name(node_map[i][j])); + node_data = &graph_data->node_data[graph_data->nb_nodes]; + node_data->node_id = node_map[i][j]; + node_data->is_sink = false; + graph_data->nb_nodes++; + } + + } + + for (i = 0; i < stages - 1; i++) { + for (j = 0; j < nodes_per_stage; j++ ) { + node_data = graph_get_node_data(graph_data, + node_map[i][j]); + edges = graph_node_count_edges(i, j, nodes_per_stage, + edge_map, ename, node_data, node_map); + if (edges == RTE_EDGE_ID_INVALID) { + printf("Invalid edge configuration\n"); + goto pattern_name_free; + } + if (!edges) + continue; + count = rte_node_edge_update(node_map[i][j], 0, + (const char **)(uintptr_t) + ename, edges); + for (k = 0; k < edges; k++) + free(ename[k]); + if (count != edges) { + printf("Couldnt add edges %d %d\n", edges, + count); + goto pattern_name_free; + } + } + } + + /* Setup Source nodes */ + for (i = 0; i < nb_srcs; i++) { + edges = 0; + total_percent = 0; + node_patterns[graph_data->nb_nodes] = malloc(RTE_NODE_NAMESIZE); + if (node_patterns[graph_data->nb_nodes] == NULL) { + printf("Failed to create memory for pattern\n"); + goto pattern_name_free; + } + snprintf(nname, sizeof(nname), "%d", i); + src_nodes[i] = graph_node_get(burst_one ? + TEST_GRAPH_SRC_BRST_ONE_NAME : + TEST_GRAPH_SRC_NAME, nname); + if (src_nodes[i] == RTE_NODE_ID_INVALID) { + printf("Failed to create node[%s]\n", nname); + graph_data->nb_nodes++; + goto pattern_name_free; + } + snprintf(node_patterns[graph_data->nb_nodes], RTE_NODE_NAMESIZE, + "%s", rte_node_id_to_name(src_nodes[i])); + node_data = &graph_data->node_data[graph_data->nb_nodes]; + node_data->node_id = src_nodes[i]; + node_data->is_sink = false; + graph_data->nb_nodes++; + for (j = 0; j < nodes_per_stage; j++) { + if (!src_map[i][j]) + continue; + ename[edges] = malloc(sizeof(char) * RTE_NODE_NAMESIZE); + snprintf(ename[edges], RTE_NODE_NAMESIZE, "%s", + rte_node_id_to_name(node_map[0][j])); + node_data->next_nodes[edges] = node_map[0][j]; + node_data->next_percentage[edges] = src_map[i][j]; + edges++; + total_percent += src_map[i][j]; + } + + if (!edges) + continue; + if (edges >= MAX_EDGES_PER_NODE || total_percent != 100) { + printf("Invalid edge configuration\n"); + for (j = 0; j < edges; j++) + free(ename[j]); + goto pattern_name_free; + } + count = rte_node_edge_update(src_nodes[i], 0, + (const char **)(uintptr_t)ename, + edges); + for (k = 0; k < edges; k++) + free(ename[k]); + if (count != edges) { + printf("Couldnt add edges %d %d\n", edges, count); + goto pattern_name_free; + } + } + + /* Setup Sink nodes */ + for (i = 0; i < nb_sinks; i++) { + node_patterns[graph_data->nb_nodes] = malloc(RTE_NODE_NAMESIZE); + if (node_patterns[graph_data->nb_nodes] == NULL) { + printf("Failed to create memory for pattern\n"); + goto pattern_name_free; + } + snprintf(nname, sizeof(nname), "%d", i); + snk_nodes[i] = graph_node_get(TEST_GRAPH_SNK_NAME, nname); + if (snk_nodes[i] == RTE_NODE_ID_INVALID) { + printf("Failed to create node[%s]\n", nname); + graph_data->nb_nodes++; + goto pattern_name_free; + } + snprintf(node_patterns[graph_data->nb_nodes], + RTE_NODE_NAMESIZE, "%s", + rte_node_id_to_name(snk_nodes[i])); + node_data = &graph_data->node_data[graph_data->nb_nodes]; + node_data->node_id = snk_nodes[i]; + node_data->is_sink = true; + graph_data->nb_nodes++; + } + + for (i = 0; i < nodes_per_stage; i++) { + edges = 0; + total_percent = 0; + node_data = graph_get_node_data(graph_data, + node_map[stages - 1][i]); + for (j = 0; j < nb_sinks; j++) { + if(!snk_map[i][j]) + continue; + ename[edges] = malloc(sizeof(char) * RTE_NODE_NAMESIZE); + snprintf(ename[edges], RTE_NODE_NAMESIZE, "%s", + rte_node_id_to_name(snk_nodes[j])); + node_data->next_nodes[edges] = snk_nodes[j]; + node_data->next_percentage[edges] = snk_map[i][j]; + edges++; + total_percent += snk_map[i][j]; + } + if (!edges) + continue; + if (edges >= MAX_EDGES_PER_NODE || total_percent != 100) { + printf("Invalid edge configuration\n"); + for (j = 0; j < edges; j++) + free(ename[i]); + goto pattern_name_free; + } + count = rte_node_edge_update(node_map[stages - 1][i], 0, + (const char **)(uintptr_t) ename, + edges); + for (k = 0; k < edges; k++) + free(ename[k]); + if (count != edges) { + printf("Couldnt add edges %d %d\n", edges, count); + goto pattern_name_free; + } + } + + gconf.socket_id = SOCKET_ID_ANY; + gconf.nb_node_patterns = graph_data->nb_nodes; + gconf.node_patterns = (const char **)(uintptr_t) node_patterns; + + graph_id = rte_graph_create(gname, &gconf); + if (graph_id == RTE_GRAPH_ID_INVALID) { + printf("Graph creation failed with error = %d\n", rte_errno); + goto pattern_name_free; + } + graph_data->graph_id = graph_id; + + for (i = 0; i < graph_data->nb_nodes; i++) + free(node_patterns[i]); + free(snk_nodes); + free(src_nodes); + free(node_patterns); + return 0; + +pattern_name_free: + for (i = 0; i < graph_data->nb_nodes; i++) + free(node_patterns[i]); +snk_free: + free(snk_nodes); +src_free: + free(src_nodes); +pattern_free: + free(node_patterns); +data_free: + free(graph_data->node_data); +memzone_free: + rte_memzone_free(mz); + return -ENOMEM; +} + +static int +_graph_perf_wrapper(void *args) +{ + struct graph_lcore_data *data = args; + struct rte_graph *graph; + + graph = rte_graph_lookup(rte_graph_id_to_name(data->graph_id)); + while (!data->done) + rte_graph_walk(graph); + + return 0; +} + +static int measure_perf_get(rte_graph_t graph_id) +{ + const char *pattern = rte_graph_id_to_name(graph_id); + uint32_t lcore_id = rte_get_next_lcore(-1, 1, 0); + struct rte_graph_cluster_stats_param param; + struct rte_graph_cluster_stats *stats; + struct graph_lcore_data *data; + + data = rte_zmalloc("Graph_perf", sizeof(struct graph_lcore_data), + RTE_CACHE_LINE_SIZE); + data->graph_id = graph_id; + data->done = 0; + + rte_eal_remote_launch(_graph_perf_wrapper, data, lcore_id); + if (rte_graph_has_stats_feature()) { + memset(¶m, 0, sizeof(param)); + param.f = stdout; + param.socket_id = SOCKET_ID_ANY; + param.graph_patterns = &pattern; + param.nb_graph_patterns = 1; + + stats = rte_graph_cluster_stats_create(¶m); + if (stats == NULL) { + printf("Failed to create stats\n"); + return -ENOMEM; + } + + rte_delay_ms(3E2); + rte_graph_cluster_stats_get(stats, true); + rte_delay_ms(1E3); + rte_graph_cluster_stats_get(stats, false); + rte_graph_cluster_stats_destroy(stats); + } else + rte_delay_ms(1E3); + + data->done = 1; + rte_eal_wait_lcore(lcore_id); + + return 0; +} + +static inline void +graph_fini(void) +{ + const struct rte_memzone *mz = rte_memzone_lookup(TEST_GRAPH_PERF_MZ); + struct test_graph_perf *graph_data; + + if (mz == NULL) + return; + graph_data = mz->addr; + + rte_graph_destroy(rte_graph_id_to_name(graph_data->graph_id)); + free(graph_data->node_data); + rte_memzone_free(rte_memzone_lookup(TEST_GRAPH_PERF_MZ)); +} + +static int +measure_perf(void) +{ + const struct rte_memzone *mz; + struct test_graph_perf *graph_data; + + mz = rte_memzone_lookup(TEST_GRAPH_PERF_MZ); + graph_data = mz->addr; + + return measure_perf_get(graph_data->graph_id); +} + +static inline int +graph_hr_4s_1n_1src_1snk(void) { + return measure_perf(); +} + +static inline int +graph_hr_4s_1n_1src_1snk_brst_one(void) { + return measure_perf(); +} + +static inline int +graph_hr_4s_1n_2src_1snk(void) { + return measure_perf(); +} + +static inline int +graph_hr_4s_1n_1src_2snk(void) { + return measure_perf(); +} + +static inline int +graph_tree_4s_4n_1src_4snk(void) { + return measure_perf(); +} + +static inline int +graph_reverse_tree_3s_4n_1src_1snk(void) { + return measure_perf(); +} + +static inline int +graph_parallel_tree_5s_4n_4src_4snk(void) { + return measure_perf(); +} + +static inline int +graph_init_hr(void) +{ + uint8_t edge_map[][1][1] = { + {{100}}, + {{100}}, + {{100}}, + {{100}}, + }; + uint8_t src_map[][1] = {{100}}; + uint8_t snk_map[][1] = {{100}}; + return graph_init("graph_hr", SOURCES(src_map), SINKS(snk_map), + STAGES(edge_map), NODES_PER_STAGE(edge_map), src_map, + snk_map, edge_map, 0); +} + +static inline int +graph_init_hr_brst_one(void) +{ + uint8_t edge_map[][1][1] = { + {{100}}, + {{100}}, + {{100}}, + {{100}}, + }; + uint8_t src_map[][1] = {{100}}; + uint8_t snk_map[][1] = {{100}}; + return graph_init("graph_hr", SOURCES(src_map), SINKS(snk_map), + STAGES(edge_map), NODES_PER_STAGE(edge_map), src_map, + snk_map, edge_map, 1); +} + +static inline int +graph_init_hr_multi_src(void) +{ + uint8_t edge_map[][1][1] = { + {{100}}, + {{100}}, + {{100}}, + {{100}}, + }; + uint8_t src_map[][1] = {{100},{100}}; + uint8_t snk_map[][1] = {{100}}; + return graph_init("graph_hr", SOURCES(src_map), SINKS(snk_map), + STAGES(edge_map), NODES_PER_STAGE(edge_map), src_map, + snk_map, edge_map, 0); +} + +static inline int +graph_init_hr_multi_snk(void) +{ + uint8_t edge_map[][1][1] = { + {{100}}, + {{100}}, + {{100}}, + {{100}}, + }; + uint8_t src_map[][1] = {{100}}; + uint8_t snk_map[][2] = {{50, 50}}; + return graph_init("graph_hr", SOURCES(src_map), SINKS(snk_map), + STAGES(edge_map), NODES_PER_STAGE(edge_map), src_map, + snk_map, edge_map, 0); +} + +static inline int +graph_init_tree(void) +{ + uint8_t edge_map[][4][4] = { + {{100, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, + {{50, 0, 0, 0}, {50, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}, + {{33, 33, 0, 0}, {34, 34, 0, 0}, {33, 33, 0, 0}, {0,0,0,0}}, + {{25, 25, 25, 0}, {25, 25, 25, 0}, {25, 25, 25, 0}, + {25, 25, 25, 0}} + }; + uint8_t src_map[][4] = {{100, 0, 0, 0}}; + uint8_t snk_map[][4] = {{100,0,0,0}, {0,100,0,0}, {0,0,100,0}, {0,0,0,100}}; + + return graph_init("graph_full_split", SOURCES(src_map), SINKS(snk_map), + STAGES(edge_map), NODES_PER_STAGE(edge_map), src_map, + snk_map, edge_map, 0); +} + +static inline int +graph_init_reverse_tree(void) +{ + uint8_t edge_map[][4][4] = { + {{25,25,25,25}, {25,25,25,25}, {25,25,25,25}, {25,25,25,25}}, + {{33,33,33,33}, {33,33,33,33}, {34,34,34,34}, {0,0,0,0}}, + {{50,50,50,0}, {50,50,50,0}, {0,0,0,0}, {0,0,0,0}}, + }; + uint8_t src_map[][4] = {{25, 25, 25, 25}}; + uint8_t snk_map[][1] = {{100}, {100}, {0}, {0}}; + + return graph_init("graph_full_split", SOURCES(src_map), SINKS(snk_map), + STAGES(edge_map), NODES_PER_STAGE(edge_map), src_map, + snk_map, edge_map, 0); +} + +static inline int +graph_init_parallel_tree(void) +{ + uint8_t edge_map[][4][4] = { + {{100,0,0,0}, {0,100,0,0}, {0,0,100,0}, {0,0,0,100}}, + {{100,0,0,0}, {0,100,0,0}, {0,0,100,0}, {0,0,0,100}}, + {{100,0,0,0}, {0,100,0,0}, {0,0,100,0}, {0,0,0,100}}, + {{100,0,0,0}, {0,100,0,0}, {0,0,100,0}, {0,0,0,100}}, + {{100,0,0,0}, {0,100,0,0}, {0,0,100,0}, {0,0,0,100}}, + }; + uint8_t src_map[][4] = {{100,0,0,0}, {0,100,0,0}, {0,0,100,0}, {0,0,0,100}}; + uint8_t snk_map[][4] = {{100,0,0,0}, {0,100,0,0}, {0,0,100,0}, {0,0,0,100}}; + + return graph_init("graph_parallel", SOURCES(src_map), SINKS(snk_map), + STAGES(edge_map), NODES_PER_STAGE(edge_map), src_map, + snk_map, edge_map, 0); +} + +/** Graph Creation cheatsheet + * edge_map -> dictates graph flow from worker stage 0 to worker stage n-1. + * src_map -> dictates source nodes enqueue percentage to worker stage 0. + * snk_map -> dictates stage n-1 enqueue percentage to sink. + * + * Layout: + * edge_map[][][] + * src_map[][] + * snk_map[][] + * + * The last array dictates the percentage of received objs to enqueue to next + * stage. + * + * Note: edge_map[][0][] will always be unused as it will receive from source + * + * Example: + * Graph: + * http://bit.ly/2PqbqOy + * Each stage(n) connects to all nodes in the next stage in decreasing + * order. + * Since we cant resize the edge_map dynamically we get away by creating + * dummy nodes and assigning 0 percentages. + * Max nodes across all stages = 4 + * stages = 3 + * nb_src = 1 + * nb_snk = 1 + * // Stages + * edge_map[][4][4] = { + * // Nodes per stage + * { + * {25,25,25,25},{25,25,25,25},{25,25,25,25},{25,25,25,25} + * }, // This will be unused. + * { + * // Nodes enabled in current stage + prev stage enq % + * {33,33,33,33}, {33,33,33,33}, {34,34,34,34}, {0,0,0,0} + * }, + * { + * {50,50,50,0}, {50,50,50,0}, {0,0,0,0}, {0,0,0,0} + * }, + * }; + * Above, each stage tells how much it should receive from previous except + * from stage_0. + * + * src_map[][4] = {{25, 25, 25, 25}}; + * Here, we tell each source the % it has to send to stage_0 nodes. In + * case we want 2 source node we can declae as + * src_map[][4] = {{25, 25, 25, 25}, {25, 25, 25, 25}}; + * + * snk_map[][1] = {{100}, {100}, {0}, {0}} + * Here, we tell stage - 1 nodes how much to enqueue to sink_0. + * If we have 2 sinks we can do as follows + * snk_map[][2] = {{50, 50}, {50, 50}, {0, 0}, {0, 0}} + * + * TODO: add validation logic for above declaration style. + * */ + +static struct unit_test_suite graph_perf_testsuite = { + .suite_name = "Graph library performance test suite", + .setup = graph_perf_setup, + .teardown = graph_perf_teardown, + .unit_test_cases = { + TEST_CASE_ST(graph_init_hr, graph_fini, + graph_hr_4s_1n_1src_1snk), + TEST_CASE_ST(graph_init_hr_brst_one, graph_fini, + graph_hr_4s_1n_1src_1snk_brst_one), + TEST_CASE_ST(graph_init_hr_multi_src, graph_fini, + graph_hr_4s_1n_2src_1snk), + TEST_CASE_ST(graph_init_hr_multi_snk, graph_fini, + graph_hr_4s_1n_1src_2snk), + TEST_CASE_ST(graph_init_tree, graph_fini, + graph_tree_4s_4n_1src_4snk), + TEST_CASE_ST(graph_init_reverse_tree, graph_fini, + graph_reverse_tree_3s_4n_1src_1snk), + TEST_CASE_ST(graph_init_parallel_tree, graph_fini, + graph_parallel_tree_5s_4n_4src_4snk), + TEST_CASES_END(), /**< NULL terminate unit test array */ + } +}; + +static int +test_graph_perf_func(void) +{ + return unit_test_suite_runner(&graph_perf_testsuite); +} + +REGISTER_TEST_COMMAND(graph_perf_autotest, test_graph_perf_func); -- 2.24.1