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