Branch data Line data Source code
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 [ # # # # : 0 : for (i = 0; i < graph_data->nb_nodes; i++)
# # ]
69 [ # # # # : 0 : 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 : 0 : 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 : 0 : rte_node_t nid = node->id;
84 : : rte_edge_t edge = 0;
85 : : int i;
86 : :
87 : : RTE_SET_USED(graph);
88 : :
89 : 0 : mz = rte_memzone_lookup(TEST_GRAPH_PERF_MZ);
90 [ # # ]: 0 : if (mz == NULL)
91 : : return -ENOMEM;
92 : 0 : graph_data = mz->addr;
93 : : node_data = graph_get_node_data(graph_data, nid);
94 : 0 : node->ctx[0] = node->nb_edges;
95 [ # # # # ]: 0 : for (i = 0; i < node->nb_edges && !node_data->is_sink; i++, edge++) {
96 : 0 : node->ctx[i + 1] = edge;
97 : 0 : 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 : 0 : 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 [ # # ]: 0 : for (i = 0; i < node->ctx[0]; i++) {
116 : 0 : count = (node->ctx[i + 9] * RTE_GRAPH_BURST_SIZE) / 100;
117 : 0 : rte_node_next_stream_get(graph, node, node->ctx[i + 1], count);
118 [ # # ]: 0 : rte_node_next_stream_put(graph, node, node->ctx[i + 1], count);
119 : : }
120 : :
121 : 0 : 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 : 251 : RTE_NODE_REGISTER(test_graph_perf_source);
132 : :
133 : : static uint16_t
134 : 0 : 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 [ # # ]: 0 : for (i = 0; i < node->ctx[0]; i++) {
146 : 0 : count = (node->ctx[i + 9]) / 100;
147 : 0 : rte_node_next_stream_get(graph, node, node->ctx[i + 1], count);
148 [ # # ]: 0 : rte_node_next_stream_put(graph, node, node->ctx[i + 1], count);
149 : : }
150 : :
151 : 0 : 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 : 251 : RTE_NODE_REGISTER(test_graph_perf_source_burst_one);
162 : :
163 : : /* Worker node function */
164 : : static uint16_t
165 : 0 : 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 [ # # ]: 0 : if (node->ctx[0] == 1) {
175 : 0 : rte_node_next_stream_move(graph, node, node->ctx[1]);
176 : 0 : return nb_objs;
177 : : }
178 : :
179 : : /* Enqueue objects to next nodes proportionally */
180 [ # # ]: 0 : for (i = 0; i < node->ctx[0]; i++) {
181 : 0 : next = node->ctx[i + 1];
182 : 0 : count = (node->ctx[i + 9] * nb_objs) / 100;
183 : 0 : enq += count;
184 [ # # ]: 0 : while (count) {
185 [ # # # # ]: 0 : switch (count & (4 - 1)) {
186 : 0 : case 0:
187 : 0 : rte_node_enqueue_x4(graph, node, next, objs[0],
188 : : objs[1], objs[2], objs[3]);
189 : 0 : objs += 4;
190 : 0 : count -= 4;
191 : 0 : break;
192 : 0 : case 1:
193 : 0 : rte_node_enqueue_x1(graph, node, next, objs[0]);
194 : 0 : objs += 1;
195 : 0 : count -= 1;
196 : 0 : break;
197 : 0 : case 2:
198 : 0 : rte_node_enqueue_x2(graph, node, next, objs[0],
199 : : objs[1]);
200 : 0 : objs += 2;
201 : 0 : count -= 2;
202 : 0 : break;
203 : 0 : case 3:
204 : 0 : rte_node_enqueue_x2(graph, node, next, objs[0],
205 : : objs[1]);
206 : 0 : rte_node_enqueue_x1(graph, node, next, objs[0]);
207 : 0 : objs += 3;
208 : 0 : count -= 3;
209 : 0 : break;
210 : : }
211 : : }
212 : : }
213 : :
214 [ # # ]: 0 : if (enq != nb_objs)
215 : 0 : 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 : 251 : RTE_NODE_REGISTER(test_graph_perf_worker);
227 : :
228 : : /* Last node in graph a.k.a sink node */
229 : : static uint16_t
230 : 0 : 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 : 0 : 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 : 251 : RTE_NODE_REGISTER(test_graph_perf_sink);
248 : :
249 : : static int
250 : 0 : graph_perf_setup(void)
251 : : {
252 [ # # ]: 0 : if (rte_lcore_count() < 2) {
253 : : printf("Test requires at least 2 lcores\n");
254 : 0 : return TEST_SKIPPED;
255 : : }
256 : :
257 : : return 0;
258 : : }
259 : :
260 : : static void
261 : 0 : graph_perf_teardown(void)
262 : : {
263 : 0 : }
264 : :
265 : : static inline rte_node_t
266 : 0 : graph_node_get(const char *pname, char *nname)
267 : : {
268 : 0 : 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 : 0 : node_id = rte_node_from_name(lookup_name);
274 : :
275 [ # # ]: 0 : if (node_id != RTE_NODE_ID_INVALID) {
276 [ # # ]: 0 : if (rte_node_edge_count(node_id))
277 : 0 : rte_node_edge_shrink(node_id, 0);
278 : 0 : return node_id;
279 : : }
280 : :
281 : 0 : return rte_node_clone(pnode_id, nname);
282 : : }
283 : :
284 : : static uint16_t
285 : 0 : 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 [ # # # # ]: 0 : for (i = 0; i < nodes_per_stage && edges < MAX_EDGES_PER_NODE; i++) {
295 [ # # ]: 0 : if (edge_map[stage + 1][i][node]) {
296 : 0 : ename[edges] = malloc(sizeof(char) * RTE_NODE_NAMESIZE);
297 : 0 : snprintf(ename[edges], RTE_NODE_NAMESIZE, "%s",
298 : 0 : rte_node_id_to_name(node_map[stage + 1][i]));
299 : 0 : node_data->next_nodes[edges] = node_map[stage + 1][i];
300 : 0 : node_data->next_percentage[edges] =
301 : 0 : edge_map[stage + 1][i][node];
302 : 0 : edges++;
303 : 0 : total_percent += edge_map[stage + 1][i][node];
304 : : }
305 : : }
306 : :
307 [ # # # # ]: 0 : if (edges >= MAX_EDGES_PER_NODE || (edges && total_percent != 100)) {
308 [ # # ]: 0 : for (i = 0; i < edges; i++)
309 : 0 : free(ename[i]);
310 : : return RTE_EDGE_ID_INVALID;
311 : : }
312 : :
313 : : return edges;
314 : : }
315 : :
316 : : static int
317 : 0 : 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 : 0 : {
323 : : struct test_graph_perf *graph_data;
324 : : char nname[RTE_NODE_NAMESIZE / 2];
325 : : struct test_node_data *node_data;
326 : 0 : char *ename[nodes_per_stage];
327 : 0 : struct rte_graph_param gconf = {0};
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 : 0 : mz = rte_memzone_reserve(TEST_GRAPH_PERF_MZ,
340 : : sizeof(struct test_graph_perf), 0, 0);
341 [ # # ]: 0 : if (mz == NULL) {
342 : : printf("Failed to allocate graph common memory\n");
343 : 0 : return -ENOMEM;
344 : : }
345 : :
346 : 0 : graph_data = mz->addr;
347 : 0 : graph_data->nb_nodes = 0;
348 : 0 : graph_data->node_data =
349 : 0 : malloc(sizeof(struct test_node_data) *
350 : 0 : (nb_srcs + nb_sinks + stages * nodes_per_stage));
351 [ # # ]: 0 : if (graph_data->node_data == NULL) {
352 : : printf("Failed to reserve memzone for graph data\n");
353 : 0 : goto memzone_free;
354 : : }
355 : :
356 : 0 : node_patterns = malloc(sizeof(char *) *
357 : : (nb_srcs + nb_sinks + stages * nodes_per_stage));
358 [ # # ]: 0 : if (node_patterns == NULL) {
359 : : printf("Failed to reserve memory for node patterns\n");
360 : 0 : goto data_free;
361 : : }
362 : :
363 : 0 : src_nodes = malloc(sizeof(rte_node_t) * nb_srcs);
364 [ # # ]: 0 : if (src_nodes == NULL) {
365 : : printf("Failed to reserve memory for src nodes\n");
366 : 0 : goto pattern_free;
367 : : }
368 : :
369 : 0 : snk_nodes = malloc(sizeof(rte_node_t) * nb_sinks);
370 [ # # ]: 0 : if (snk_nodes == NULL) {
371 : : printf("Failed to reserve memory for snk nodes\n");
372 : 0 : goto src_free;
373 : : }
374 : :
375 : 0 : node_map = malloc(sizeof(rte_node_t *) * stages +
376 : : sizeof(rte_node_t) * nodes_per_stage * stages);
377 [ # # ]: 0 : if (node_map == NULL) {
378 : : printf("Failed to reserve memory for node map\n");
379 : 0 : goto snk_free;
380 : : }
381 : :
382 : : /* Setup the Graph */
383 [ # # ]: 0 : for (i = 0; i < stages; i++) {
384 : 0 : node_map[i] =
385 : 0 : (rte_node_t *)(node_map + stages) + nodes_per_stage * i;
386 [ # # ]: 0 : for (j = 0; j < nodes_per_stage; j++) {
387 : : total_percent = 0;
388 [ # # ]: 0 : for (k = 0; k < nodes_per_stage; k++)
389 : 0 : total_percent += edge_map[i][j][k];
390 [ # # ]: 0 : if (!total_percent)
391 : 0 : continue;
392 : 0 : node_patterns[graph_data->nb_nodes] =
393 : 0 : malloc(RTE_NODE_NAMESIZE);
394 [ # # ]: 0 : if (node_patterns[graph_data->nb_nodes] == NULL) {
395 : : printf("Failed to create memory for pattern\n");
396 : 0 : goto pattern_name_free;
397 : : }
398 : :
399 : : /* Clone a worker node */
400 : : snprintf(nname, sizeof(nname), "%d-%d", i, j);
401 : 0 : node_map[i][j] =
402 : 0 : graph_node_get(TEST_GRAPH_WRK_NAME, nname);
403 [ # # ]: 0 : if (node_map[i][j] == RTE_NODE_ID_INVALID) {
404 : : printf("Failed to create node[%s]\n", nname);
405 : 0 : graph_data->nb_nodes++;
406 : 0 : goto pattern_name_free;
407 : : }
408 : 0 : snprintf(node_patterns[graph_data->nb_nodes],
409 : : RTE_NODE_NAMESIZE, "%s",
410 : : rte_node_id_to_name(node_map[i][j]));
411 : 0 : node_data =
412 : 0 : &graph_data->node_data[graph_data->nb_nodes];
413 : 0 : node_data->node_id = node_map[i][j];
414 : 0 : node_data->is_sink = false;
415 : 0 : graph_data->nb_nodes++;
416 : : }
417 : : }
418 : :
419 [ # # ]: 0 : for (i = 0; i < stages - 1; i++) {
420 [ # # ]: 0 : for (j = 0; j < nodes_per_stage; j++) {
421 : : /* Count edges i.e connections of worker node to next */
422 : : node_data =
423 : 0 : graph_get_node_data(graph_data, node_map[i][j]);
424 : 0 : edges = graph_node_count_edges(i, j, nodes_per_stage,
425 : : edge_map, ename,
426 : : node_data, node_map);
427 [ # # ]: 0 : if (edges == RTE_EDGE_ID_INVALID) {
428 : : printf("Invalid edge configuration\n");
429 : 0 : goto pattern_name_free;
430 : : }
431 [ # # ]: 0 : if (!edges)
432 : 0 : continue;
433 : :
434 : : /* Connect a node in stage 'i' to nodes
435 : : * in stage 'i + 1' with edges.
436 : : */
437 : 0 : count = rte_node_edge_update(
438 : 0 : node_map[i][j], 0,
439 : : (const char **)(uintptr_t)ename, edges);
440 [ # # ]: 0 : for (k = 0; k < edges; k++)
441 : 0 : free(ename[k]);
442 [ # # ]: 0 : if (count != edges) {
443 : 0 : printf("Couldn't add edges %d %d\n", edges,
444 : : count);
445 : 0 : goto pattern_name_free;
446 : : }
447 : : }
448 : : }
449 : :
450 : : /* Setup Source nodes */
451 [ # # ]: 0 : for (i = 0; i < nb_srcs; i++) {
452 : : edges = 0;
453 : : total_percent = 0;
454 : 0 : node_patterns[graph_data->nb_nodes] = malloc(RTE_NODE_NAMESIZE);
455 [ # # ]: 0 : if (node_patterns[graph_data->nb_nodes] == NULL) {
456 : : printf("Failed to create memory for pattern\n");
457 : 0 : goto pattern_name_free;
458 : : }
459 : : /* Clone a source node */
460 : : snprintf(nname, sizeof(nname), "%d", i);
461 : 0 : src_nodes[i] =
462 [ # # ]: 0 : graph_node_get(burst_one ? TEST_GRAPH_SRC_BRST_ONE_NAME
463 : : : TEST_GRAPH_SRC_NAME,
464 : : nname);
465 [ # # ]: 0 : if (src_nodes[i] == RTE_NODE_ID_INVALID) {
466 : : printf("Failed to create node[%s]\n", nname);
467 : 0 : graph_data->nb_nodes++;
468 : 0 : goto pattern_name_free;
469 : : }
470 : 0 : snprintf(node_patterns[graph_data->nb_nodes], RTE_NODE_NAMESIZE,
471 : : "%s", rte_node_id_to_name(src_nodes[i]));
472 : 0 : node_data = &graph_data->node_data[graph_data->nb_nodes];
473 : 0 : node_data->node_id = src_nodes[i];
474 : 0 : node_data->is_sink = false;
475 : 0 : graph_data->nb_nodes++;
476 : :
477 : : /* Prepare next node list to connect to */
478 [ # # ]: 0 : for (j = 0; j < nodes_per_stage; j++) {
479 [ # # ]: 0 : if (!src_map[i][j])
480 : 0 : continue;
481 : 0 : ename[edges] = malloc(sizeof(char) * RTE_NODE_NAMESIZE);
482 : 0 : snprintf(ename[edges], RTE_NODE_NAMESIZE, "%s",
483 : 0 : rte_node_id_to_name(node_map[0][j]));
484 : 0 : node_data->next_nodes[edges] = node_map[0][j];
485 : 0 : node_data->next_percentage[edges] = src_map[i][j];
486 : 0 : edges++;
487 : 0 : total_percent += src_map[i][j];
488 : : }
489 : :
490 [ # # ]: 0 : if (!edges)
491 : 0 : continue;
492 [ # # ]: 0 : if (edges >= MAX_EDGES_PER_NODE || total_percent != 100) {
493 : : printf("Invalid edge configuration\n");
494 [ # # ]: 0 : for (j = 0; j < edges; j++)
495 : 0 : free(ename[j]);
496 : 0 : goto pattern_name_free;
497 : : }
498 : :
499 : : /* Connect to list of next nodes using edges */
500 : 0 : count = rte_node_edge_update(src_nodes[i], 0,
501 : : (const char **)(uintptr_t)ename,
502 : : edges);
503 [ # # ]: 0 : for (k = 0; k < edges; k++)
504 : 0 : free(ename[k]);
505 [ # # ]: 0 : if (count != edges) {
506 : 0 : printf("Couldn't add edges %d %d\n", edges, count);
507 : 0 : goto pattern_name_free;
508 : : }
509 : : }
510 : :
511 : : /* Setup Sink nodes */
512 [ # # ]: 0 : for (i = 0; i < nb_sinks; i++) {
513 : 0 : node_patterns[graph_data->nb_nodes] = malloc(RTE_NODE_NAMESIZE);
514 [ # # ]: 0 : if (node_patterns[graph_data->nb_nodes] == NULL) {
515 : : printf("Failed to create memory for pattern\n");
516 : 0 : goto pattern_name_free;
517 : : }
518 : :
519 : : /* Clone a sink node */
520 : : snprintf(nname, sizeof(nname), "%d", i);
521 : 0 : snk_nodes[i] = graph_node_get(TEST_GRAPH_SNK_NAME, nname);
522 [ # # ]: 0 : if (snk_nodes[i] == RTE_NODE_ID_INVALID) {
523 : : printf("Failed to create node[%s]\n", nname);
524 : 0 : graph_data->nb_nodes++;
525 : 0 : goto pattern_name_free;
526 : : }
527 : 0 : snprintf(node_patterns[graph_data->nb_nodes], RTE_NODE_NAMESIZE,
528 : : "%s", rte_node_id_to_name(snk_nodes[i]));
529 : 0 : node_data = &graph_data->node_data[graph_data->nb_nodes];
530 : 0 : node_data->node_id = snk_nodes[i];
531 : 0 : node_data->is_sink = true;
532 : 0 : graph_data->nb_nodes++;
533 : : }
534 : :
535 : : /* Connect last stage worker nodes to sink nodes */
536 [ # # ]: 0 : for (i = 0; i < nodes_per_stage; i++) {
537 : : edges = 0;
538 : : total_percent = 0;
539 : 0 : node_data = graph_get_node_data(graph_data,
540 : 0 : node_map[stages - 1][i]);
541 : : /* Prepare list of sink nodes to connect to */
542 [ # # ]: 0 : for (j = 0; j < nb_sinks; j++) {
543 [ # # ]: 0 : if (!snk_map[i][j])
544 : 0 : continue;
545 : 0 : ename[edges] = malloc(sizeof(char) * RTE_NODE_NAMESIZE);
546 : 0 : snprintf(ename[edges], RTE_NODE_NAMESIZE, "%s",
547 : 0 : rte_node_id_to_name(snk_nodes[j]));
548 : 0 : node_data->next_nodes[edges] = snk_nodes[j];
549 : 0 : node_data->next_percentage[edges] = snk_map[i][j];
550 : 0 : edges++;
551 : 0 : total_percent += snk_map[i][j];
552 : : }
553 [ # # ]: 0 : if (!edges)
554 : 0 : continue;
555 [ # # ]: 0 : if (edges >= MAX_EDGES_PER_NODE || total_percent != 100) {
556 : : printf("Invalid edge configuration\n");
557 [ # # ]: 0 : for (j = 0; j < edges; j++)
558 : 0 : free(ename[i]);
559 : 0 : goto pattern_name_free;
560 : : }
561 : :
562 : : /* Connect a worker node to a list of sink nodes */
563 : 0 : count = rte_node_edge_update(node_map[stages - 1][i], 0,
564 : : (const char **)(uintptr_t)ename,
565 : : edges);
566 [ # # ]: 0 : for (k = 0; k < edges; k++)
567 : 0 : free(ename[k]);
568 [ # # ]: 0 : if (count != edges) {
569 : 0 : printf("Couldn't add edges %d %d\n", edges, count);
570 : 0 : goto pattern_name_free;
571 : : }
572 : : }
573 : :
574 : : /* Create a Graph */
575 : 0 : gconf.socket_id = SOCKET_ID_ANY;
576 : 0 : gconf.nb_node_patterns = graph_data->nb_nodes;
577 : 0 : gconf.node_patterns = (const char **)(uintptr_t)node_patterns;
578 : :
579 : 0 : graph_id = rte_graph_create(gname, &gconf);
580 [ # # ]: 0 : if (graph_id == RTE_GRAPH_ID_INVALID) {
581 : 0 : printf("Graph creation failed with error = %d\n", rte_errno);
582 : 0 : goto pattern_name_free;
583 : : }
584 : 0 : graph_data->graph_id = graph_id;
585 : :
586 : 0 : free(node_map);
587 [ # # ]: 0 : for (i = 0; i < graph_data->nb_nodes; i++)
588 : 0 : free(node_patterns[i]);
589 : 0 : free(snk_nodes);
590 : 0 : free(src_nodes);
591 : 0 : free(node_patterns);
592 : 0 : return 0;
593 : :
594 : 0 : pattern_name_free:
595 : 0 : free(node_map);
596 [ # # ]: 0 : for (i = 0; i < graph_data->nb_nodes; i++)
597 : 0 : free(node_patterns[i]);
598 : 0 : snk_free:
599 : 0 : free(snk_nodes);
600 : 0 : src_free:
601 : 0 : free(src_nodes);
602 : 0 : pattern_free:
603 : 0 : free(node_patterns);
604 : 0 : data_free:
605 : 0 : free(graph_data->node_data);
606 : 0 : memzone_free:
607 : 0 : rte_memzone_free(mz);
608 : 0 : return -ENOMEM;
609 : : }
610 : :
611 : : /* Worker thread function */
612 : : static int
613 : 0 : _graph_perf_wrapper(void *args)
614 : : {
615 : : struct graph_lcore_data *data = args;
616 : : struct rte_graph *graph;
617 : :
618 : : /* Lookup graph */
619 : 0 : graph = rte_graph_lookup(rte_graph_id_to_name(data->graph_id));
620 : :
621 : : /* Graph walk until done */
622 [ # # ]: 0 : while (!data->done)
623 : 0 : rte_graph_walk(graph);
624 : :
625 : 0 : return 0;
626 : : }
627 : :
628 : : static int
629 : 0 : measure_perf_get(rte_graph_t graph_id)
630 : : {
631 : 0 : const char *pattern = rte_graph_id_to_name(graph_id);
632 : 0 : 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 : 0 : data = rte_zmalloc("Graph_perf", sizeof(struct graph_lcore_data),
638 : : RTE_CACHE_LINE_SIZE);
639 : 0 : data->graph_id = graph_id;
640 : 0 : data->done = 0;
641 : :
642 : : /* Run graph worker thread function */
643 : 0 : 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(¶m, 0, sizeof(param));
648 : 0 : param.f = stdout;
649 : 0 : param.socket_id = SOCKET_ID_ANY;
650 : 0 : param.graph_patterns = &pattern;
651 : 0 : param.nb_graph_patterns = 1;
652 : :
653 : 0 : stats = rte_graph_cluster_stats_create(¶m);
654 [ # # ]: 0 : if (stats == NULL) {
655 : : printf("Failed to create stats\n");
656 : 0 : return -ENOMEM;
657 : : }
658 : :
659 : : rte_delay_ms(3E2);
660 : 0 : rte_graph_cluster_stats_get(stats, true);
661 : : rte_delay_ms(1E3);
662 : 0 : rte_graph_cluster_stats_get(stats, false);
663 : 0 : rte_graph_cluster_stats_destroy(stats);
664 : : } else
665 : : rte_delay_ms(1E3);
666 : :
667 : 0 : data->done = 1;
668 : 0 : rte_eal_wait_lcore(lcore_id);
669 : :
670 : 0 : return 0;
671 : : }
672 : :
673 : : static inline void
674 : 0 : graph_fini(void)
675 : : {
676 : 0 : const struct rte_memzone *mz = rte_memzone_lookup(TEST_GRAPH_PERF_MZ);
677 : : struct test_graph_perf *graph_data;
678 : :
679 [ # # ]: 0 : if (mz == NULL)
680 : : return;
681 : 0 : graph_data = mz->addr;
682 : :
683 : 0 : rte_graph_destroy(graph_data->graph_id);
684 : 0 : free(graph_data->node_data);
685 : 0 : rte_memzone_free(rte_memzone_lookup(TEST_GRAPH_PERF_MZ));
686 : : }
687 : :
688 : : static int
689 : 0 : measure_perf(void)
690 : : {
691 : : const struct rte_memzone *mz;
692 : : struct test_graph_perf *graph_data;
693 : :
694 : 0 : mz = rte_memzone_lookup(TEST_GRAPH_PERF_MZ);
695 [ # # ]: 0 : if (mz == NULL)
696 : : return -ENOMEM;
697 : 0 : graph_data = mz->addr;
698 : :
699 : 0 : return measure_perf_get(graph_data->graph_id);
700 : : }
701 : :
702 : : static inline int
703 : 0 : graph_hr_4s_1n_1src_1snk(void)
704 : : {
705 : 0 : return measure_perf();
706 : : }
707 : :
708 : : static inline int
709 : 0 : graph_hr_4s_1n_1src_1snk_brst_one(void)
710 : : {
711 : 0 : return measure_perf();
712 : : }
713 : :
714 : : static inline int
715 : 0 : graph_hr_4s_1n_2src_1snk(void)
716 : : {
717 : 0 : return measure_perf();
718 : : }
719 : :
720 : : static inline int
721 : 0 : graph_hr_4s_1n_1src_2snk(void)
722 : : {
723 : 0 : return measure_perf();
724 : : }
725 : :
726 : : static inline int
727 : 0 : graph_tree_4s_4n_1src_4snk(void)
728 : : {
729 : 0 : return measure_perf();
730 : : }
731 : :
732 : : static inline int
733 : 0 : graph_reverse_tree_3s_4n_1src_1snk(void)
734 : : {
735 : 0 : return measure_perf();
736 : : }
737 : :
738 : : static inline int
739 : 0 : graph_parallel_tree_5s_4n_4src_4snk(void)
740 : : {
741 : 0 : 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 : 0 : graph_init_hr(void)
752 : : {
753 : 0 : uint8_t edge_map[][1][1] = {
754 : : { {100} },
755 : : { {100} },
756 : : { {100} },
757 : : { {100} },
758 : : };
759 : 0 : uint8_t src_map[][1] = { {100} };
760 : 0 : uint8_t snk_map[][1] = { {100} };
761 : :
762 : 0 : 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 : 0 : graph_init_hr_brst_one(void)
775 : : {
776 : 0 : uint8_t edge_map[][1][1] = {
777 : : { {100} },
778 : : { {100} },
779 : : { {100} },
780 : : { {100} },
781 : : };
782 : 0 : uint8_t src_map[][1] = { {100} };
783 : 0 : uint8_t snk_map[][1] = { {100} };
784 : :
785 : 0 : 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 : 0 : graph_init_hr_multi_src(void)
798 : : {
799 : 0 : uint8_t edge_map[][1][1] = {
800 : : { {100} },
801 : : { {100} },
802 : : { {100} },
803 : : { {100} },
804 : : };
805 : 0 : uint8_t src_map[][1] = {
806 : : {100}, {100}
807 : : };
808 : 0 : uint8_t snk_map[][1] = { {100} };
809 : :
810 : 0 : 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 : 0 : graph_init_hr_multi_snk(void)
823 : : {
824 : 0 : uint8_t edge_map[][1][1] = {
825 : : { {100} },
826 : : { {100} },
827 : : { {100} },
828 : : { {100} },
829 : : };
830 : 0 : uint8_t src_map[][1] = { {100} };
831 : 0 : uint8_t snk_map[][2] = { {50, 50} };
832 : :
833 : 0 : 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 : 0 : graph_init_tree(void)
846 : : {
847 : 0 : 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 : 0 : uint8_t src_map[][4] = { {100, 0, 0, 0} };
874 : 0 : 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 : 0 : 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 : 0 : graph_init_reverse_tree(void)
894 : : {
895 : 0 : 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 : 0 : uint8_t src_map[][4] = { {25, 25, 25, 25} };
916 : 0 : uint8_t snk_map[][1] = { {100}, {100}, {0}, {0} };
917 : :
918 : 0 : 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 : 0 : graph_init_parallel_tree(void)
931 : : {
932 : 0 : 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 : 0 : 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 : 0 : 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 : 0 : 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 : 0 : test_graph_perf_func(void)
1070 : : {
1071 : 0 : return unit_test_suite_runner(&graph_perf_testsuite);
1072 : : }
1073 : :
1074 : : #endif /* !RTE_EXEC_ENV_WINDOWS */
1075 : :
1076 : 251 : REGISTER_PERF_TEST(graph_perf_autotest, test_graph_perf_func);
|