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 = {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 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(¶m, 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(¶m); 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); 1077