test mbuf attach
[dpdk.git] / app / test / test_graph_perf.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2020 Marvell International Ltd.
3  */
4 #include <inttypes.h>
5 #include <signal.h>
6 #include <stdio.h>
7 #include <unistd.h>
8
9 #include <rte_common.h>
10 #include <rte_cycles.h>
11 #include <rte_errno.h>
12 #include <rte_graph.h>
13 #include <rte_graph_worker.h>
14 #include <rte_lcore.h>
15 #include <rte_malloc.h>
16 #include <rte_mbuf.h>
17
18 #include "test.h"
19
20 #define TEST_GRAPH_PERF_MZ           "graph_perf_data"
21 #define TEST_GRAPH_SRC_NAME          "test_graph_perf_source"
22 #define TEST_GRAPH_SRC_BRST_ONE_NAME "test_graph_perf_source_one"
23 #define TEST_GRAPH_WRK_NAME          "test_graph_perf_worker"
24 #define TEST_GRAPH_SNK_NAME          "test_graph_perf_sink"
25
26 #define SOURCES(map)         RTE_DIM(map)
27 #define STAGES(map)          RTE_DIM(map)
28 #define NODES_PER_STAGE(map) RTE_DIM(map[0])
29 #define SINKS(map)           RTE_DIM(map[0])
30
31 #define MAX_EDGES_PER_NODE 7
32
33 struct test_node_data {
34         uint8_t node_id;
35         uint8_t is_sink;
36         uint8_t next_nodes[MAX_EDGES_PER_NODE];
37         uint8_t next_percentage[MAX_EDGES_PER_NODE];
38 };
39
40 struct test_graph_perf {
41         uint16_t nb_nodes;
42         rte_graph_t graph_id;
43         struct test_node_data *node_data;
44 };
45
46 struct graph_lcore_data {
47         uint8_t done;
48         rte_graph_t graph_id;
49 };
50
51 static struct test_node_data *
52 graph_get_node_data(struct test_graph_perf *graph_data, rte_node_t id)
53 {
54         struct test_node_data *node_data = NULL;
55         int i;
56
57         for (i = 0; i < graph_data->nb_nodes; i++)
58                 if (graph_data->node_data[i].node_id == id) {
59                         node_data = &graph_data->node_data[i];
60                         break;
61                 }
62
63         return node_data;
64 }
65
66 static int
67 test_node_ctx_init(const struct rte_graph *graph, struct rte_node *node)
68 {
69         struct test_graph_perf *graph_data;
70         struct test_node_data *node_data;
71         const struct rte_memzone *mz;
72         rte_node_t nid = node->id;
73         rte_edge_t edge = 0;
74         int i;
75
76         RTE_SET_USED(graph);
77
78         mz = rte_memzone_lookup(TEST_GRAPH_PERF_MZ);
79         if (mz == NULL)
80                 return -ENOMEM;
81         graph_data = mz->addr;
82         node_data = graph_get_node_data(graph_data, nid);
83         node->ctx[0] = node->nb_edges;
84         for (i = 0; i < node->nb_edges && !node_data->is_sink; i++, edge++) {
85                 node->ctx[i + 1] = edge;
86                 node->ctx[i + 9] = node_data->next_percentage[i];
87         }
88
89         return 0;
90 }
91
92 /* Source node function */
93 static uint16_t
94 test_perf_node_worker_source(struct rte_graph *graph, struct rte_node *node,
95                              void **objs, uint16_t nb_objs)
96 {
97         uint16_t count;
98         int i;
99
100         RTE_SET_USED(objs);
101         RTE_SET_USED(nb_objs);
102
103         /* Create a proportional stream for every next */
104         for (i = 0; i < node->ctx[0]; i++) {
105                 count = (node->ctx[i + 9] * RTE_GRAPH_BURST_SIZE) / 100;
106                 rte_node_next_stream_get(graph, node, node->ctx[i + 1], count);
107                 rte_node_next_stream_put(graph, node, node->ctx[i + 1], count);
108         }
109
110         return RTE_GRAPH_BURST_SIZE;
111 }
112
113 static struct rte_node_register test_graph_perf_source = {
114         .name = TEST_GRAPH_SRC_NAME,
115         .process = test_perf_node_worker_source,
116         .flags = RTE_NODE_SOURCE_F,
117         .init = test_node_ctx_init,
118 };
119
120 RTE_NODE_REGISTER(test_graph_perf_source);
121
122 static uint16_t
123 test_perf_node_worker_source_burst_one(struct rte_graph *graph,
124                                        struct rte_node *node, void **objs,
125                                        uint16_t nb_objs)
126 {
127         uint16_t count;
128         int i;
129
130         RTE_SET_USED(objs);
131         RTE_SET_USED(nb_objs);
132
133         /* Create a proportional stream for every next */
134         for (i = 0; i < node->ctx[0]; i++) {
135                 count = (node->ctx[i + 9]) / 100;
136                 rte_node_next_stream_get(graph, node, node->ctx[i + 1], count);
137                 rte_node_next_stream_put(graph, node, node->ctx[i + 1], count);
138         }
139
140         return 1;
141 }
142
143 static struct rte_node_register test_graph_perf_source_burst_one = {
144         .name = TEST_GRAPH_SRC_BRST_ONE_NAME,
145         .process = test_perf_node_worker_source_burst_one,
146         .flags = RTE_NODE_SOURCE_F,
147         .init = test_node_ctx_init,
148 };
149
150 RTE_NODE_REGISTER(test_graph_perf_source_burst_one);
151
152 /* Worker node function */
153 static uint16_t
154 test_perf_node_worker(struct rte_graph *graph, struct rte_node *node,
155                       void **objs, uint16_t nb_objs)
156 {
157         uint16_t next = 0;
158         uint16_t enq = 0;
159         uint16_t count;
160         int i;
161
162         /* Move stream for single next node */
163         if (node->ctx[0] == 1) {
164                 rte_node_next_stream_move(graph, node, node->ctx[1]);
165                 return nb_objs;
166         }
167
168         /* Enqueue objects to next nodes proportionally */
169         for (i = 0; i < node->ctx[0]; i++) {
170                 next = node->ctx[i + 1];
171                 count = (node->ctx[i + 9] * nb_objs) / 100;
172                 enq += count;
173                 while (count) {
174                         switch (count & (4 - 1)) {
175                         case 0:
176                                 rte_node_enqueue_x4(graph, node, next, objs[0],
177                                                     objs[1], objs[2], objs[3]);
178                                 objs += 4;
179                                 count -= 4;
180                                 break;
181                         case 1:
182                                 rte_node_enqueue_x1(graph, node, next, objs[0]);
183                                 objs += 1;
184                                 count -= 1;
185                                 break;
186                         case 2:
187                                 rte_node_enqueue_x2(graph, node, next, objs[0],
188                                                     objs[1]);
189                                 objs += 2;
190                                 count -= 2;
191                                 break;
192                         case 3:
193                                 rte_node_enqueue_x2(graph, node, next, objs[0],
194                                                     objs[1]);
195                                 rte_node_enqueue_x1(graph, node, next, objs[0]);
196                                 objs += 3;
197                                 count -= 3;
198                                 break;
199                         }
200                 }
201         }
202
203         if (enq != nb_objs)
204                 rte_node_enqueue(graph, node, next, objs, nb_objs - enq);
205
206         return nb_objs;
207 }
208
209 static struct rte_node_register test_graph_perf_worker = {
210         .name = TEST_GRAPH_WRK_NAME,
211         .process = test_perf_node_worker,
212         .init = test_node_ctx_init,
213 };
214
215 RTE_NODE_REGISTER(test_graph_perf_worker);
216
217 /* Last node in graph a.k.a sink node */
218 static uint16_t
219 test_perf_node_sink(struct rte_graph *graph, struct rte_node *node, void **objs,
220                     uint16_t nb_objs)
221 {
222         RTE_SET_USED(graph);
223         RTE_SET_USED(node);
224         RTE_SET_USED(objs);
225         RTE_SET_USED(nb_objs);
226
227         return nb_objs;
228 }
229
230 static struct rte_node_register test_graph_perf_sink = {
231         .name = TEST_GRAPH_SNK_NAME,
232         .process = test_perf_node_sink,
233         .init = test_node_ctx_init,
234 };
235
236 RTE_NODE_REGISTER(test_graph_perf_sink);
237
238 static int
239 graph_perf_setup(void)
240 {
241         if (rte_lcore_count() < 2) {
242                 printf("Test requires at least 2 lcores\n");
243                 return TEST_SKIPPED;
244         }
245
246         return 0;
247 }
248
249 static void
250 graph_perf_teardown(void)
251 {
252 }
253
254 static inline rte_node_t
255 graph_node_get(const char *pname, char *nname)
256 {
257         rte_node_t pnode_id = rte_node_from_name(pname);
258         char lookup_name[RTE_NODE_NAMESIZE];
259         rte_node_t node_id;
260
261         snprintf(lookup_name, RTE_NODE_NAMESIZE, "%s-%s", pname, nname);
262         node_id = rte_node_from_name(lookup_name);
263
264         if (node_id != RTE_NODE_ID_INVALID) {
265                 if (rte_node_edge_count(node_id))
266                         rte_node_edge_shrink(node_id, 0);
267                 return node_id;
268         }
269
270         return rte_node_clone(pnode_id, nname);
271 }
272
273 static uint16_t
274 graph_node_count_edges(uint32_t stage, uint16_t node, uint16_t nodes_per_stage,
275                        uint8_t edge_map[][nodes_per_stage][nodes_per_stage],
276                        char *ename[], struct test_node_data *node_data,
277                        rte_node_t **node_map)
278 {
279         uint8_t total_percent = 0;
280         uint16_t edges = 0;
281         int i;
282
283         for (i = 0; i < nodes_per_stage && edges < MAX_EDGES_PER_NODE; i++) {
284                 if (edge_map[stage + 1][i][node]) {
285                         ename[edges] = malloc(sizeof(char) * RTE_NODE_NAMESIZE);
286                         snprintf(ename[edges], RTE_NODE_NAMESIZE, "%s",
287                                  rte_node_id_to_name(node_map[stage + 1][i]));
288                         node_data->next_nodes[edges] = node_map[stage + 1][i];
289                         node_data->next_percentage[edges] =
290                                 edge_map[stage + 1][i][node];
291                         edges++;
292                         total_percent += edge_map[stage + 1][i][node];
293                 }
294         }
295
296         if (edges >= MAX_EDGES_PER_NODE || (edges && total_percent != 100)) {
297                 for (i = 0; i < edges; i++)
298                         free(ename[i]);
299                 return RTE_EDGE_ID_INVALID;
300         }
301
302         return edges;
303 }
304
305 static int
306 graph_init(const char *gname, uint8_t nb_srcs, uint8_t nb_sinks,
307            uint32_t stages, uint16_t nodes_per_stage,
308            uint8_t src_map[][nodes_per_stage], uint8_t snk_map[][nb_sinks],
309            uint8_t edge_map[][nodes_per_stage][nodes_per_stage],
310            uint8_t burst_one)
311 {
312         struct test_graph_perf *graph_data;
313         char nname[RTE_NODE_NAMESIZE / 2];
314         struct test_node_data *node_data;
315         char *ename[nodes_per_stage];
316         struct rte_graph_param gconf;
317         const struct rte_memzone *mz;
318         uint8_t total_percent = 0;
319         rte_node_t *src_nodes;
320         rte_node_t *snk_nodes;
321         rte_node_t **node_map;
322         char **node_patterns;
323         rte_graph_t graph_id;
324         rte_edge_t edges;
325         rte_edge_t count;
326         uint32_t i, j, k;
327
328         mz = rte_memzone_reserve(TEST_GRAPH_PERF_MZ,
329                                  sizeof(struct test_graph_perf), 0, 0);
330         if (mz == NULL) {
331                 printf("Failed to allocate graph common memory\n");
332                 return -ENOMEM;
333         }
334
335         graph_data = mz->addr;
336         graph_data->nb_nodes = 0;
337         graph_data->node_data =
338                 malloc(sizeof(struct test_node_data) *
339                        (nb_srcs + nb_sinks + stages * nodes_per_stage));
340         if (graph_data->node_data == NULL) {
341                 printf("Failed to reserve memzone for graph data\n");
342                 goto memzone_free;
343         }
344
345         node_patterns = malloc(sizeof(char *) *
346                                (nb_srcs + nb_sinks + stages * nodes_per_stage));
347         if (node_patterns == NULL) {
348                 printf("Failed to reserve memory for node patterns\n");
349                 goto data_free;
350         }
351
352         src_nodes = malloc(sizeof(rte_node_t) * nb_srcs);
353         if (src_nodes == NULL) {
354                 printf("Failed to reserve memory for src nodes\n");
355                 goto pattern_free;
356         }
357
358         snk_nodes = malloc(sizeof(rte_node_t) * nb_sinks);
359         if (snk_nodes == NULL) {
360                 printf("Failed to reserve memory for snk nodes\n");
361                 goto src_free;
362         }
363
364         node_map = malloc(sizeof(rte_node_t *) * stages +
365                           sizeof(rte_node_t) * nodes_per_stage * stages);
366         if (node_map == NULL) {
367                 printf("Failed to reserve memory for node map\n");
368                 goto snk_free;
369         }
370
371         /* Setup the Graph */
372         for (i = 0; i < stages; i++) {
373                 node_map[i] =
374                         (rte_node_t *)(node_map + stages) + nodes_per_stage * i;
375                 for (j = 0; j < nodes_per_stage; j++) {
376                         total_percent = 0;
377                         for (k = 0; k < nodes_per_stage; k++)
378                                 total_percent += edge_map[i][j][k];
379                         if (!total_percent)
380                                 continue;
381                         node_patterns[graph_data->nb_nodes] =
382                                 malloc(RTE_NODE_NAMESIZE);
383                         if (node_patterns[graph_data->nb_nodes] == NULL) {
384                                 printf("Failed to create memory for pattern\n");
385                                 goto pattern_name_free;
386                         }
387
388                         /* Clone a worker node */
389                         snprintf(nname, sizeof(nname), "%d-%d", i, j);
390                         node_map[i][j] =
391                                 graph_node_get(TEST_GRAPH_WRK_NAME, nname);
392                         if (node_map[i][j] == RTE_NODE_ID_INVALID) {
393                                 printf("Failed to create node[%s]\n", nname);
394                                 graph_data->nb_nodes++;
395                                 goto pattern_name_free;
396                         }
397                         snprintf(node_patterns[graph_data->nb_nodes],
398                                  RTE_NODE_NAMESIZE, "%s",
399                                  rte_node_id_to_name(node_map[i][j]));
400                         node_data =
401                                 &graph_data->node_data[graph_data->nb_nodes];
402                         node_data->node_id = node_map[i][j];
403                         node_data->is_sink = false;
404                         graph_data->nb_nodes++;
405                 }
406         }
407
408         for (i = 0; i < stages - 1; i++) {
409                 for (j = 0; j < nodes_per_stage; j++) {
410                         /* Count edges i.e connections of worker node to next */
411                         node_data =
412                                 graph_get_node_data(graph_data, node_map[i][j]);
413                         edges = graph_node_count_edges(i, j, nodes_per_stage,
414                                                        edge_map, ename,
415                                                        node_data, node_map);
416                         if (edges == RTE_EDGE_ID_INVALID) {
417                                 printf("Invalid edge configuration\n");
418                                 goto pattern_name_free;
419                         }
420                         if (!edges)
421                                 continue;
422
423                         /* Connect a node in stage 'i' to nodes
424                          * in stage 'i + 1' with edges.
425                          */
426                         count = rte_node_edge_update(
427                                 node_map[i][j], 0,
428                                 (const char **)(uintptr_t)ename, edges);
429                         for (k = 0; k < edges; k++)
430                                 free(ename[k]);
431                         if (count != edges) {
432                                 printf("Couldn't add edges %d %d\n", edges,
433                                        count);
434                                 goto pattern_name_free;
435                         }
436                 }
437         }
438
439         /* Setup Source nodes */
440         for (i = 0; i < nb_srcs; i++) {
441                 edges = 0;
442                 total_percent = 0;
443                 node_patterns[graph_data->nb_nodes] = malloc(RTE_NODE_NAMESIZE);
444                 if (node_patterns[graph_data->nb_nodes] == NULL) {
445                         printf("Failed to create memory for pattern\n");
446                         goto pattern_name_free;
447                 }
448                 /* Clone a source node */
449                 snprintf(nname, sizeof(nname), "%d", i);
450                 src_nodes[i] =
451                         graph_node_get(burst_one ? TEST_GRAPH_SRC_BRST_ONE_NAME
452                                                  : TEST_GRAPH_SRC_NAME,
453                                        nname);
454                 if (src_nodes[i] == RTE_NODE_ID_INVALID) {
455                         printf("Failed to create node[%s]\n", nname);
456                         graph_data->nb_nodes++;
457                         goto pattern_name_free;
458                 }
459                 snprintf(node_patterns[graph_data->nb_nodes], RTE_NODE_NAMESIZE,
460                          "%s", rte_node_id_to_name(src_nodes[i]));
461                 node_data = &graph_data->node_data[graph_data->nb_nodes];
462                 node_data->node_id = src_nodes[i];
463                 node_data->is_sink = false;
464                 graph_data->nb_nodes++;
465
466                 /* Prepare next node list  to connect to */
467                 for (j = 0; j < nodes_per_stage; j++) {
468                         if (!src_map[i][j])
469                                 continue;
470                         ename[edges] = malloc(sizeof(char) * RTE_NODE_NAMESIZE);
471                         snprintf(ename[edges], RTE_NODE_NAMESIZE, "%s",
472                                  rte_node_id_to_name(node_map[0][j]));
473                         node_data->next_nodes[edges] = node_map[0][j];
474                         node_data->next_percentage[edges] = src_map[i][j];
475                         edges++;
476                         total_percent += src_map[i][j];
477                 }
478
479                 if (!edges)
480                         continue;
481                 if (edges >= MAX_EDGES_PER_NODE || total_percent != 100) {
482                         printf("Invalid edge configuration\n");
483                         for (j = 0; j < edges; j++)
484                                 free(ename[j]);
485                         goto pattern_name_free;
486                 }
487
488                 /* Connect to list of next nodes using edges */
489                 count = rte_node_edge_update(src_nodes[i], 0,
490                                              (const char **)(uintptr_t)ename,
491                                              edges);
492                 for (k = 0; k < edges; k++)
493                         free(ename[k]);
494                 if (count != edges) {
495                         printf("Couldn't add edges %d %d\n", edges, count);
496                         goto pattern_name_free;
497                 }
498         }
499
500         /* Setup Sink nodes */
501         for (i = 0; i < nb_sinks; i++) {
502                 node_patterns[graph_data->nb_nodes] = malloc(RTE_NODE_NAMESIZE);
503                 if (node_patterns[graph_data->nb_nodes] == NULL) {
504                         printf("Failed to create memory for pattern\n");
505                         goto pattern_name_free;
506                 }
507
508                 /* Clone a sink node */
509                 snprintf(nname, sizeof(nname), "%d", i);
510                 snk_nodes[i] = graph_node_get(TEST_GRAPH_SNK_NAME, nname);
511                 if (snk_nodes[i] == RTE_NODE_ID_INVALID) {
512                         printf("Failed to create node[%s]\n", nname);
513                         graph_data->nb_nodes++;
514                         goto pattern_name_free;
515                 }
516                 snprintf(node_patterns[graph_data->nb_nodes], RTE_NODE_NAMESIZE,
517                          "%s", rte_node_id_to_name(snk_nodes[i]));
518                 node_data = &graph_data->node_data[graph_data->nb_nodes];
519                 node_data->node_id = snk_nodes[i];
520                 node_data->is_sink = true;
521                 graph_data->nb_nodes++;
522         }
523
524         /* Connect last stage worker nodes to sink nodes */
525         for (i = 0; i < nodes_per_stage; i++) {
526                 edges = 0;
527                 total_percent = 0;
528                 node_data = graph_get_node_data(graph_data,
529                                                 node_map[stages - 1][i]);
530                 /* Prepare list of sink nodes to connect to */
531                 for (j = 0; j < nb_sinks; j++) {
532                         if (!snk_map[i][j])
533                                 continue;
534                         ename[edges] = malloc(sizeof(char) * RTE_NODE_NAMESIZE);
535                         snprintf(ename[edges], RTE_NODE_NAMESIZE, "%s",
536                                  rte_node_id_to_name(snk_nodes[j]));
537                         node_data->next_nodes[edges] = snk_nodes[j];
538                         node_data->next_percentage[edges] = snk_map[i][j];
539                         edges++;
540                         total_percent += snk_map[i][j];
541                 }
542                 if (!edges)
543                         continue;
544                 if (edges >= MAX_EDGES_PER_NODE || total_percent != 100) {
545                         printf("Invalid edge configuration\n");
546                         for (j = 0; j < edges; j++)
547                                 free(ename[i]);
548                         goto pattern_name_free;
549                 }
550
551                 /* Connect a worker node to a list of sink nodes */
552                 count = rte_node_edge_update(node_map[stages - 1][i], 0,
553                                              (const char **)(uintptr_t)ename,
554                                              edges);
555                 for (k = 0; k < edges; k++)
556                         free(ename[k]);
557                 if (count != edges) {
558                         printf("Couldn't add edges %d %d\n", edges, count);
559                         goto pattern_name_free;
560                 }
561         }
562
563         /* Create a Graph */
564         gconf.socket_id = SOCKET_ID_ANY;
565         gconf.nb_node_patterns = graph_data->nb_nodes;
566         gconf.node_patterns = (const char **)(uintptr_t)node_patterns;
567
568         graph_id = rte_graph_create(gname, &gconf);
569         if (graph_id == RTE_GRAPH_ID_INVALID) {
570                 printf("Graph creation failed with error = %d\n", rte_errno);
571                 goto pattern_name_free;
572         }
573         graph_data->graph_id = graph_id;
574
575         free(node_map);
576         for (i = 0; i < graph_data->nb_nodes; i++)
577                 free(node_patterns[i]);
578         free(snk_nodes);
579         free(src_nodes);
580         free(node_patterns);
581         return 0;
582
583 pattern_name_free:
584         free(node_map);
585         for (i = 0; i < graph_data->nb_nodes; i++)
586                 free(node_patterns[i]);
587 snk_free:
588         free(snk_nodes);
589 src_free:
590         free(src_nodes);
591 pattern_free:
592         free(node_patterns);
593 data_free:
594         free(graph_data->node_data);
595 memzone_free:
596         rte_memzone_free(mz);
597         return -ENOMEM;
598 }
599
600 /* Worker thread function */
601 static int
602 _graph_perf_wrapper(void *args)
603 {
604         struct graph_lcore_data *data = args;
605         struct rte_graph *graph;
606
607         /* Lookup graph */
608         graph = rte_graph_lookup(rte_graph_id_to_name(data->graph_id));
609
610         /* Graph walk until done */
611         while (!data->done)
612                 rte_graph_walk(graph);
613
614         return 0;
615 }
616
617 static int
618 measure_perf_get(rte_graph_t graph_id)
619 {
620         const char *pattern = rte_graph_id_to_name(graph_id);
621         uint32_t lcore_id = rte_get_next_lcore(-1, 1, 0);
622         struct rte_graph_cluster_stats_param param;
623         struct rte_graph_cluster_stats *stats;
624         struct graph_lcore_data *data;
625
626         data = rte_zmalloc("Graph_perf", sizeof(struct graph_lcore_data),
627                            RTE_CACHE_LINE_SIZE);
628         data->graph_id = graph_id;
629         data->done = 0;
630
631         /* Run graph worker thread function */
632         rte_eal_remote_launch(_graph_perf_wrapper, data, lcore_id);
633
634         /* Collect stats for few msecs */
635         if (rte_graph_has_stats_feature()) {
636                 memset(&param, 0, sizeof(param));
637                 param.f = stdout;
638                 param.socket_id = SOCKET_ID_ANY;
639                 param.graph_patterns = &pattern;
640                 param.nb_graph_patterns = 1;
641
642                 stats = rte_graph_cluster_stats_create(&param);
643                 if (stats == NULL) {
644                         printf("Failed to create stats\n");
645                         return -ENOMEM;
646                 }
647
648                 rte_delay_ms(3E2);
649                 rte_graph_cluster_stats_get(stats, true);
650                 rte_delay_ms(1E3);
651                 rte_graph_cluster_stats_get(stats, false);
652                 rte_graph_cluster_stats_destroy(stats);
653         } else
654                 rte_delay_ms(1E3);
655
656         data->done = 1;
657         rte_eal_wait_lcore(lcore_id);
658
659         return 0;
660 }
661
662 static inline void
663 graph_fini(void)
664 {
665         const struct rte_memzone *mz = rte_memzone_lookup(TEST_GRAPH_PERF_MZ);
666         struct test_graph_perf *graph_data;
667
668         if (mz == NULL)
669                 return;
670         graph_data = mz->addr;
671
672         rte_graph_destroy(graph_data->graph_id);
673         free(graph_data->node_data);
674         rte_memzone_free(rte_memzone_lookup(TEST_GRAPH_PERF_MZ));
675 }
676
677 static int
678 measure_perf(void)
679 {
680         const struct rte_memzone *mz;
681         struct test_graph_perf *graph_data;
682
683         mz = rte_memzone_lookup(TEST_GRAPH_PERF_MZ);
684         if (mz == NULL)
685                 return -ENOMEM;
686         graph_data = mz->addr;
687
688         return measure_perf_get(graph_data->graph_id);
689 }
690
691 static inline int
692 graph_hr_4s_1n_1src_1snk(void)
693 {
694         return measure_perf();
695 }
696
697 static inline int
698 graph_hr_4s_1n_1src_1snk_brst_one(void)
699 {
700         return measure_perf();
701 }
702
703 static inline int
704 graph_hr_4s_1n_2src_1snk(void)
705 {
706         return measure_perf();
707 }
708
709 static inline int
710 graph_hr_4s_1n_1src_2snk(void)
711 {
712         return measure_perf();
713 }
714
715 static inline int
716 graph_tree_4s_4n_1src_4snk(void)
717 {
718         return measure_perf();
719 }
720
721 static inline int
722 graph_reverse_tree_3s_4n_1src_1snk(void)
723 {
724         return measure_perf();
725 }
726
727 static inline int
728 graph_parallel_tree_5s_4n_4src_4snk(void)
729 {
730         return measure_perf();
731 }
732
733 /* Graph Topology
734  * nodes per stage:     1
735  * stages:              4
736  * src:                 1
737  * sink:                1
738  */
739 static inline int
740 graph_init_hr(void)
741 {
742         uint8_t edge_map[][1][1] = {
743                 { {100} },
744                 { {100} },
745                 { {100} },
746                 { {100} },
747         };
748         uint8_t src_map[][1] = { {100} };
749         uint8_t snk_map[][1] = { {100} };
750
751         return graph_init("graph_hr", SOURCES(src_map), SINKS(snk_map),
752                           STAGES(edge_map), NODES_PER_STAGE(edge_map), src_map,
753                           snk_map, edge_map, 0);
754 }
755
756 /* Graph Topology
757  * nodes per stage:     1
758  * stages:              4
759  * src:                 1
760  * sink:                1
761  */
762 static inline int
763 graph_init_hr_brst_one(void)
764 {
765         uint8_t edge_map[][1][1] = {
766                 { {100} },
767                 { {100} },
768                 { {100} },
769                 { {100} },
770         };
771         uint8_t src_map[][1] = { {100} };
772         uint8_t snk_map[][1] = { {100} };
773
774         return graph_init("graph_hr", SOURCES(src_map), SINKS(snk_map),
775                           STAGES(edge_map), NODES_PER_STAGE(edge_map), src_map,
776                           snk_map, edge_map, 1);
777 }
778
779 /* Graph Topology
780  * nodes per stage:     1
781  * stages:              4
782  * src:                 2
783  * sink:                1
784  */
785 static inline int
786 graph_init_hr_multi_src(void)
787 {
788         uint8_t edge_map[][1][1] = {
789                 { {100} },
790                 { {100} },
791                 { {100} },
792                 { {100} },
793         };
794         uint8_t src_map[][1] = {
795                 {100}, {100}
796         };
797         uint8_t snk_map[][1] = { {100} };
798
799         return graph_init("graph_hr", SOURCES(src_map), SINKS(snk_map),
800                           STAGES(edge_map), NODES_PER_STAGE(edge_map), src_map,
801                           snk_map, edge_map, 0);
802 }
803
804 /* Graph Topology
805  * nodes per stage:     1
806  * stages:              4
807  * src:                 1
808  * sink:                2
809  */
810 static inline int
811 graph_init_hr_multi_snk(void)
812 {
813         uint8_t edge_map[][1][1] = {
814                 { {100} },
815                 { {100} },
816                 { {100} },
817                 { {100} },
818         };
819         uint8_t src_map[][1] = { {100} };
820         uint8_t snk_map[][2] = { {50, 50} };
821
822         return graph_init("graph_hr", SOURCES(src_map), SINKS(snk_map),
823                           STAGES(edge_map), NODES_PER_STAGE(edge_map), src_map,
824                           snk_map, edge_map, 0);
825 }
826
827 /* Graph Topology
828  * nodes per stage:     4
829  * stages:              4
830  * src:                 1
831  * sink:                4
832  */
833 static inline int
834 graph_init_tree(void)
835 {
836         uint8_t edge_map[][4][4] = {
837                 {
838                         {100, 0, 0, 0},
839                         {0, 0, 0, 0},
840                         {0, 0, 0, 0},
841                         {0, 0, 0, 0}
842                 },
843                 {
844                         {50, 0, 0, 0},
845                         {50, 0, 0, 0},
846                         {0, 0, 0, 0},
847                         {0, 0, 0, 0}
848                 },
849                 {
850                         {33, 33, 0, 0},
851                         {34, 34, 0, 0},
852                         {33, 33, 0, 0},
853                         {0, 0, 0, 0}
854                 },
855                 {
856                         {25, 25, 25, 0},
857                         {25, 25, 25, 0},
858                         {25, 25, 25, 0},
859                         {25, 25, 25, 0}
860                 }
861         };
862         uint8_t src_map[][4] = { {100, 0, 0, 0} };
863         uint8_t snk_map[][4] = {
864                 {100, 0, 0, 0},
865                 {0, 100, 0, 0},
866                 {0, 0, 100, 0},
867                 {0, 0, 0, 100}
868         };
869
870         return graph_init("graph_full_split", SOURCES(src_map), SINKS(snk_map),
871                           STAGES(edge_map), NODES_PER_STAGE(edge_map), src_map,
872                           snk_map, edge_map, 0);
873 }
874
875 /* Graph Topology
876  * nodes per stage:     4
877  * stages:              3
878  * src:                 1
879  * sink:                1
880  */
881 static inline int
882 graph_init_reverse_tree(void)
883 {
884         uint8_t edge_map[][4][4] = {
885                 {
886                         {25, 25, 25, 25},
887                         {25, 25, 25, 25},
888                         {25, 25, 25, 25},
889                         {25, 25, 25, 25}
890                 },
891                 {
892                         {33, 33, 33, 33},
893                         {33, 33, 33, 33},
894                         {34, 34, 34, 34},
895                         {0, 0, 0, 0}
896                 },
897                 {
898                         {50, 50, 50, 0},
899                         {50, 50, 50, 0},
900                         {0, 0, 0, 0},
901                         {0, 0, 0, 0}
902                 },
903         };
904         uint8_t src_map[][4] = { {25, 25, 25, 25} };
905         uint8_t snk_map[][1] = { {100}, {100}, {0}, {0} };
906
907         return graph_init("graph_full_split", SOURCES(src_map), SINKS(snk_map),
908                           STAGES(edge_map), NODES_PER_STAGE(edge_map), src_map,
909                           snk_map, edge_map, 0);
910 }
911
912 /* Graph Topology
913  * nodes per stage:     4
914  * stages:              5
915  * src:                 4
916  * sink:                4
917  */
918 static inline int
919 graph_init_parallel_tree(void)
920 {
921         uint8_t edge_map[][4][4] = {
922                 {
923                         {100, 0, 0, 0},
924                         {0, 100, 0, 0},
925                         {0, 0, 100, 0},
926                         {0, 0, 0, 100}
927                 },
928                 {
929                         {100, 0, 0, 0},
930                         {0, 100, 0, 0},
931                         {0, 0, 100, 0},
932                         {0, 0, 0, 100}
933                 },
934                 {
935                         {100, 0, 0, 0},
936                         {0, 100, 0, 0},
937                         {0, 0, 100, 0},
938                         {0, 0, 0, 100}
939                 },
940                 {
941                         {100, 0, 0, 0},
942                         {0, 100, 0, 0},
943                         {0, 0, 100, 0},
944                         {0, 0, 0, 100}
945                 },
946                 {
947                         {100, 0, 0, 0},
948                         {0, 100, 0, 0},
949                         {0, 0, 100, 0},
950                         {0, 0, 0, 100}
951                 },
952         };
953         uint8_t src_map[][4] = {
954                 {100, 0, 0, 0},
955                 {0, 100, 0, 0},
956                 {0, 0, 100, 0},
957                 {0, 0, 0, 100}
958         };
959         uint8_t snk_map[][4] = {
960                 {100, 0, 0, 0},
961                 {0, 100, 0, 0},
962                 {0, 0, 100, 0},
963                 {0, 0, 0, 100}
964         };
965
966         return graph_init("graph_parallel", SOURCES(src_map), SINKS(snk_map),
967                           STAGES(edge_map), NODES_PER_STAGE(edge_map), src_map,
968                           snk_map, edge_map, 0);
969 }
970
971 /** Graph Creation cheat sheet
972  *  edge_map -> dictates graph flow from worker stage 0 to worker stage n-1.
973  *  src_map  -> dictates source nodes enqueue percentage to worker stage 0.
974  *  snk_map  -> dictates stage n-1 enqueue percentage to sink.
975  *
976  *  Layout:
977  *  edge_map[<nb_stages>][<nodes_per_stg>][<nodes_in_nxt_stg = nodes_per_stg>]
978  *  src_map[<nb_sources>][<nodes_in_stage0 = nodes_per_stage>]
979  *  snk_map[<nodes_in_stage(n-1) = nodes_per_stage>][<nb_sinks>]
980  *
981  *  The last array dictates the percentage of received objs to enqueue to next
982  *  stage.
983  *
984  *  Note: edge_map[][0][] will always be unused as it will receive from source
985  *
986  *  Example:
987  *      Graph:
988  *      http://bit.ly/2PqbqOy
989  *      Each stage(n) connects to all nodes in the next stage in decreasing
990  *      order.
991  *      Since we can't resize the edge_map dynamically we get away by creating
992  *      dummy nodes and assigning 0 percentages.
993  *      Max nodes across all stages = 4
994  *      stages = 3
995  *      nb_src = 1
996  *      nb_snk = 1
997  *                         // Stages
998  *      edge_map[][4][4] = {
999  *              // Nodes per stage
1000  *              {
1001  *                  {25, 25, 25, 25},
1002  *                  {25, 25, 25, 25},
1003  *                  {25, 25, 25, 25},
1004  *                  {25, 25, 25, 25}
1005  *              },      // This will be unused.
1006  *              {
1007  *                  // Nodes enabled in current stage + prev stage enq %
1008  *                  {33, 33, 33, 33},
1009  *                  {33, 33, 33, 33},
1010  *                  {34, 34, 34, 34},
1011  *                  {0, 0, 0, 0}
1012  *              },
1013  *              {
1014  *                  {50, 50, 50, 0},
1015  *                  {50, 50, 50, 0},
1016  *                  {0, 0, 0, 0},
1017  *                  {0, 0, 0, 0}
1018  *              },
1019  *      };
1020  *      Above, each stage tells how much it should receive from previous except
1021  *      from stage_0.
1022  *
1023  *      src_map[][4] = { {25, 25, 25, 25} };
1024  *      Here, we tell each source the % it has to send to stage_0 nodes. In
1025  *      case we want 2 source node we can declare as
1026  *      src_map[][4] = { {25, 25, 25, 25}, {25, 25, 25, 25} };
1027  *
1028  *      snk_map[][1] = { {100}, {100}, {0}, {0} }
1029  *      Here, we tell stage - 1 nodes how much to enqueue to sink_0.
1030  *      If we have 2 sinks we can do as follows
1031  *      snk_map[][2] = { {50, 50}, {50, 50}, {0, 0}, {0, 0} }
1032  */
1033
1034 static struct unit_test_suite graph_perf_testsuite = {
1035         .suite_name = "Graph library performance test suite",
1036         .setup = graph_perf_setup,
1037         .teardown = graph_perf_teardown,
1038         .unit_test_cases = {
1039                 TEST_CASE_ST(graph_init_hr, graph_fini,
1040                              graph_hr_4s_1n_1src_1snk),
1041                 TEST_CASE_ST(graph_init_hr_brst_one, graph_fini,
1042                              graph_hr_4s_1n_1src_1snk_brst_one),
1043                 TEST_CASE_ST(graph_init_hr_multi_src, graph_fini,
1044                              graph_hr_4s_1n_2src_1snk),
1045                 TEST_CASE_ST(graph_init_hr_multi_snk, graph_fini,
1046                              graph_hr_4s_1n_1src_2snk),
1047                 TEST_CASE_ST(graph_init_tree, graph_fini,
1048                              graph_tree_4s_4n_1src_4snk),
1049                 TEST_CASE_ST(graph_init_reverse_tree, graph_fini,
1050                              graph_reverse_tree_3s_4n_1src_1snk),
1051                 TEST_CASE_ST(graph_init_parallel_tree, graph_fini,
1052                              graph_parallel_tree_5s_4n_4src_4snk),
1053                 TEST_CASES_END(), /**< NULL terminate unit test array */
1054         },
1055 };
1056
1057 static int
1058 test_graph_perf_func(void)
1059 {
1060         return unit_test_suite_runner(&graph_perf_testsuite);
1061 }
1062
1063 REGISTER_TEST_COMMAND(graph_perf_autotest, test_graph_perf_func);