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