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