1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 5 #include <stdlib.h> 6 #include <stdio.h> 7 #include <string.h> 8 #include <stdint.h> 9 #include <unistd.h> 10 #include <inttypes.h> 11 #include <sys/time.h> 12 #include <time.h> 13 #include <math.h> 14 15 #include "test.h" 16 17 #include <rte_pie.h> 18 19 #ifdef __INTEL_COMPILER 20 #pragma warning(disable:2259) /* conversion may lose significant bits */ 21 #pragma warning(disable:181) /* Arg incompatible with format string */ 22 #endif 23 24 /**< structures for testing rte_pie performance and function */ 25 struct test_rte_pie_config { /**< Test structure for RTE_PIE config */ 26 struct rte_pie_config *pconfig; /**< RTE_PIE configuration parameters */ 27 uint8_t num_cfg; /**< Number of RTE_PIE configs to test */ 28 uint16_t qdelay_ref; /**< Latency Target (milliseconds) */ 29 uint16_t *dp_update_interval; /**< Update interval for drop probability 30 * (milliseconds) 31 */ 32 uint16_t *max_burst; /**< Max Burst Allowance (milliseconds) */ 33 uint16_t tailq_th; /**< Tailq drop threshold (packet counts) */ 34 }; 35 36 struct test_queue { /**< Test structure for RTE_PIE Queues */ 37 struct rte_pie *pdata_in; /**< RTE_PIE runtime data input */ 38 struct rte_pie *pdata_out; /**< RTE_PIE runtime data output*/ 39 uint32_t num_queues; /**< Number of RTE_PIE queues to test */ 40 uint32_t *qlen; /**< Queue size */ 41 uint32_t q_ramp_up; /**< Num of enqueues to ramp up the queue */ 42 double drop_tolerance; /**< Drop tolerance of packets not enqueued */ 43 }; 44 45 struct test_var { /**< Test variables used for testing RTE_PIE */ 46 uint32_t num_iterations; /**< Number of test iterations */ 47 uint32_t num_ops; /**< Number of test operations */ 48 uint64_t clk_freq; /**< CPU clock frequency */ 49 uint32_t *dropped; /**< Test operations dropped */ 50 uint32_t *enqueued; /**< Test operations enqueued */ 51 uint32_t *dequeued; /**< Test operations dequeued */ 52 }; 53 54 struct test_config { /**< Primary test structure for RTE_PIE */ 55 const char *ifname; /**< Interface name */ 56 const char *msg; /**< Test message for display */ 57 const char *htxt; /**< Header txt display for result output */ 58 struct test_rte_pie_config *tconfig; /**< Test structure for RTE_PIE config */ 59 struct test_queue *tqueue; /**< Test structure for RTE_PIE Queues */ 60 struct test_var *tvar; /**< Test variables used for testing RTE_PIE */ 61 uint32_t *tlevel; /**< Queue levels */ 62 }; 63 64 enum test_result { 65 FAIL = 0, 66 PASS 67 }; 68 69 /**< Test structure to define tests to run */ 70 struct tests { 71 struct test_config *testcfg; 72 enum test_result (*testfn)(struct test_config *cfg); 73 }; 74 75 struct rdtsc_prof { 76 uint64_t clk_start; 77 uint64_t clk_min; /**< min clocks */ 78 uint64_t clk_max; /**< max clocks */ 79 uint64_t clk_avgc; /**< count to calc average */ 80 double clk_avg; /**< cumulative sum to calc average */ 81 const char *name; 82 }; 83 84 static const uint64_t port_speed_bytes = (10ULL*1000ULL*1000ULL*1000ULL)/8ULL; 85 static double inv_cycles_per_byte; 86 87 static void init_port_ts(uint64_t cpu_clock) 88 { 89 double cycles_per_byte = (double)(cpu_clock) / (double)(port_speed_bytes); 90 inv_cycles_per_byte = 1.0 / cycles_per_byte; 91 } 92 93 static uint64_t get_port_ts(void) 94 { 95 return (uint64_t)((double)rte_rdtsc() * inv_cycles_per_byte); 96 } 97 98 static void rdtsc_prof_init(struct rdtsc_prof *p, const char *name) 99 { 100 p->clk_min = (uint64_t)(-1LL); 101 p->clk_max = 0; 102 p->clk_avg = 0; 103 p->clk_avgc = 0; 104 p->name = name; 105 } 106 107 static inline void rdtsc_prof_start(struct rdtsc_prof *p) 108 { 109 p->clk_start = rte_rdtsc_precise(); 110 } 111 112 static inline void rdtsc_prof_end(struct rdtsc_prof *p) 113 { 114 uint64_t clk_start = rte_rdtsc() - p->clk_start; 115 116 p->clk_avgc++; 117 p->clk_avg += (double) clk_start; 118 119 if (clk_start > p->clk_max) 120 p->clk_max = clk_start; 121 if (clk_start < p->clk_min) 122 p->clk_min = clk_start; 123 } 124 125 static void rdtsc_prof_print(struct rdtsc_prof *p) 126 { 127 if (p->clk_avgc > 0) { 128 printf("RDTSC stats for %s: n=%" PRIu64 ", min=%" PRIu64 129 ",max=%" PRIu64 ", avg=%.1f\n", 130 p->name, 131 p->clk_avgc, 132 p->clk_min, 133 p->clk_max, 134 (p->clk_avg / ((double) p->clk_avgc))); 135 } 136 } 137 138 static uint16_t rte_pie_get_active(const struct rte_pie_config *pie_cfg, 139 struct rte_pie *pie) 140 { 141 /**< Flag for activating/deactivating pie */ 142 RTE_SET_USED(pie_cfg); 143 return pie->active; 144 } 145 146 static void rte_pie_set_active(const struct rte_pie_config *pie_cfg, 147 struct rte_pie *pie, 148 uint16_t active) 149 { 150 /**< Flag for activating/deactivating pie */ 151 RTE_SET_USED(pie_cfg); 152 pie->active = active; 153 } 154 155 /** 156 * Read the drop probability 157 */ 158 static double rte_pie_get_drop_prob(const struct rte_pie_config *pie_cfg, 159 struct rte_pie *pie) 160 { 161 /**< Current packet drop probability */ 162 RTE_SET_USED(pie_cfg); 163 return pie->drop_prob; 164 } 165 166 static double rte_pie_get_avg_dq_time(const struct rte_pie_config *pie_cfg, 167 struct rte_pie *pie) 168 { 169 /**< Current packet drop probability */ 170 RTE_SET_USED(pie_cfg); 171 return pie->avg_dq_time; 172 } 173 174 static double calc_drop_rate(uint32_t enqueued, uint32_t dropped) 175 { 176 return (double)dropped / ((double)enqueued + (double)dropped); 177 } 178 179 /** 180 * check if drop rate matches drop probability within tolerance 181 */ 182 static int check_drop_rate(double *diff, double drop_rate, double drop_prob, 183 double tolerance) 184 { 185 double abs_diff = 0.0; 186 int ret = 1; 187 188 abs_diff = fabs(drop_rate - drop_prob); 189 if ((int)abs_diff == 0) { 190 *diff = 0.0; 191 } else { 192 *diff = (abs_diff / drop_prob) * 100.0; 193 if (*diff > tolerance) 194 ret = 0; 195 } 196 return ret; 197 } 198 199 /** 200 * initialize the test rte_pie config 201 */ 202 static enum test_result 203 test_rte_pie_init(struct test_config *tcfg) 204 { 205 unsigned int i = 0; 206 207 tcfg->tvar->clk_freq = rte_get_timer_hz(); 208 init_port_ts(tcfg->tvar->clk_freq); 209 210 for (i = 0; i < tcfg->tconfig->num_cfg; i++) { 211 if (rte_pie_config_init(&tcfg->tconfig->pconfig[i], 212 (uint16_t)tcfg->tconfig->qdelay_ref, 213 (uint16_t)tcfg->tconfig->dp_update_interval[i], 214 (uint16_t)tcfg->tconfig->max_burst[i], 215 (uint16_t)tcfg->tconfig->tailq_th) != 0) { 216 return FAIL; 217 } 218 } 219 220 *tcfg->tqueue->qlen = 0; 221 *tcfg->tvar->dropped = 0; 222 *tcfg->tvar->enqueued = 0; 223 224 return PASS; 225 } 226 227 /** 228 * enqueue until actual queue size reaches target level 229 */ 230 static int 231 increase_qsize(struct rte_pie_config *pie_cfg, 232 struct rte_pie *pie, 233 uint32_t *qlen, 234 uint32_t pkt_len, 235 uint32_t attempts) 236 { 237 uint32_t i = 0; 238 239 for (i = 0; i < attempts; i++) { 240 int ret = 0; 241 242 /** 243 * enqueue 244 */ 245 ret = rte_pie_enqueue(pie_cfg, pie, *qlen, pkt_len, get_port_ts()); 246 /** 247 * check if target actual queue size has been reached 248 */ 249 if (ret == 0) 250 return 0; 251 } 252 /** 253 * no success 254 */ 255 return -1; 256 } 257 258 /** 259 * functional test enqueue/dequeue packets 260 */ 261 static void 262 enqueue_dequeue_func(struct rte_pie_config *pie_cfg, 263 struct rte_pie *pie, 264 uint32_t *qlen, 265 uint32_t num_ops, 266 uint32_t *enqueued, 267 uint32_t *dropped) 268 { 269 uint32_t i = 0; 270 271 for (i = 0; i < num_ops; i++) { 272 int ret = 0; 273 274 /** 275 * enqueue 276 */ 277 ret = rte_pie_enqueue(pie_cfg, pie, *qlen, sizeof(uint32_t), 278 get_port_ts()); 279 if (ret == 0) 280 (*enqueued)++; 281 else 282 (*dropped)++; 283 } 284 } 285 286 /** 287 * setup default values for the Functional test structures 288 */ 289 static struct rte_pie_config ft_wpconfig[1]; 290 static struct rte_pie ft_rtdata[1]; 291 static uint32_t ft_q[] = {0}; 292 static uint32_t ft_dropped[] = {0}; 293 static uint32_t ft_enqueued[] = {0}; 294 static uint16_t ft_max_burst[] = {64}; 295 static uint16_t ft_dp_update_interval[] = {150}; 296 297 static struct test_rte_pie_config ft_tconfig = { 298 .pconfig = ft_wpconfig, 299 .num_cfg = RTE_DIM(ft_wpconfig), 300 .qdelay_ref = 15, 301 .dp_update_interval = ft_dp_update_interval, 302 .max_burst = ft_max_burst, 303 .tailq_th = 15, 304 }; 305 306 static struct test_queue ft_tqueue = { 307 .pdata_in = ft_rtdata, 308 .num_queues = RTE_DIM(ft_rtdata), 309 .qlen = ft_q, 310 .q_ramp_up = 10, 311 .drop_tolerance = 0, 312 }; 313 314 static struct test_var ft_tvar = { 315 .num_iterations = 0, 316 .num_ops = 10000, 317 .clk_freq = 0, 318 .dropped = ft_dropped, 319 .enqueued = ft_enqueued, 320 }; 321 322 /** 323 * Test F1: functional test 1 324 */ 325 static uint32_t ft_tlevels[] = {6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 326 72, 78, 84, 90, 96, 102, 108, 114, 120, 126, 132, 138, 144}; 327 328 static struct test_config func_test_config1 = { 329 .ifname = "functional test interface", 330 .msg = "functional test : use one pie configuration\n\n", 331 .htxt = " " 332 "drop probability " 333 "enqueued " 334 "dropped " 335 "drop prob % " 336 "drop rate % " 337 "diff % " 338 "tolerance % " 339 "active " 340 "\n", 341 .tconfig = &ft_tconfig, 342 .tqueue = &ft_tqueue, 343 .tvar = &ft_tvar, 344 .tlevel = ft_tlevels, 345 }; 346 347 static enum test_result func_test1(struct test_config *tcfg) 348 { 349 enum test_result result = PASS; 350 uint32_t i = 0; 351 352 printf("%s", tcfg->msg); 353 354 if (test_rte_pie_init(tcfg) != PASS) { 355 result = FAIL; 356 goto out; 357 } 358 359 printf("%s", tcfg->htxt); 360 361 /** 362 * reset rte_pie run-time data 363 */ 364 rte_pie_rt_data_init(tcfg->tqueue->pdata_in); 365 rte_pie_set_active(NULL, tcfg->tqueue->pdata_in, 1); 366 *tcfg->tvar->enqueued = 0; 367 *tcfg->tvar->dropped = 0; 368 369 if (increase_qsize(&tcfg->tconfig->pconfig[i], 370 tcfg->tqueue->pdata_in, 371 tcfg->tqueue->qlen, 372 tcfg->tlevel[i], 373 tcfg->tqueue->q_ramp_up) != 0) { 374 fprintf(stderr, "Fail: increase qsize\n"); 375 result = FAIL; 376 goto out; 377 } 378 379 for (i = 0; i < RTE_DIM(ft_tlevels); i++) { 380 const char *label = NULL; 381 uint16_t prob = 0; 382 uint16_t active = 0; 383 double drop_rate = 1.0; 384 double drop_prob = 0.0; 385 double diff = 0.0; 386 387 enqueue_dequeue_func(&tcfg->tconfig->pconfig[i], 388 tcfg->tqueue->pdata_in, 389 tcfg->tqueue->qlen, 390 tcfg->tvar->num_ops, 391 tcfg->tvar->enqueued, 392 tcfg->tvar->dropped); 393 394 drop_rate = calc_drop_rate(*tcfg->tvar->enqueued, 395 *tcfg->tvar->dropped); 396 drop_prob = rte_pie_get_drop_prob(NULL, tcfg->tqueue->pdata_in); 397 398 if (drop_prob != 0) { 399 fprintf(stderr, "Fail: check drop prob\n"); 400 result = FAIL; 401 } 402 403 if (drop_rate != 0) { 404 fprintf(stderr, "Fail: check drop rate\n"); 405 result = FAIL; 406 } 407 408 label = "Summary "; 409 active = rte_pie_get_active(NULL, tcfg->tqueue->pdata_in); 410 printf("%s%-16u%-12u%-12u%-12.4lf%-12.4lf%-12.4lf%-12.4lf%-8i\n", 411 label, prob, *tcfg->tvar->enqueued, *tcfg->tvar->dropped, 412 drop_prob * 100.0, drop_rate * 100.0, diff, 413 (double)tcfg->tqueue->drop_tolerance, active); 414 } 415 out: 416 return result; 417 } 418 419 /** 420 * Test F2: functional test 2 421 */ 422 static uint32_t ft2_tlevel[] = {127}; 423 static uint16_t ft2_max_burst[] = {1, 2, 8, 16, 32, 64, 128, 256, 512, 1024}; 424 static uint16_t ft2_dp_update_interval[] = { 425 10, 20, 50, 150, 300, 600, 900, 1200, 1500, 3000}; 426 static struct rte_pie_config ft2_pconfig[10]; 427 428 static struct test_rte_pie_config ft2_tconfig = { 429 .pconfig = ft2_pconfig, 430 .num_cfg = RTE_DIM(ft2_pconfig), 431 .qdelay_ref = 15, 432 .dp_update_interval = ft2_dp_update_interval, 433 .max_burst = ft2_max_burst, 434 .tailq_th = 15, 435 }; 436 437 static struct test_config func_test_config2 = { 438 .ifname = "functional test 2 interface", 439 .msg = "functional test 2 : use several PIE configurations,\n" 440 " compare drop rate to drop probability\n\n", 441 .htxt = "PIE config " 442 "avg queue size " 443 "enqueued " 444 "dropped " 445 "drop prob % " 446 "drop rate % " 447 "diff % " 448 "tolerance % " 449 "\n", 450 .tconfig = &ft2_tconfig, 451 .tqueue = &ft_tqueue, 452 .tvar = &ft_tvar, 453 .tlevel = ft2_tlevel, 454 }; 455 456 static enum test_result func_test2(struct test_config *tcfg) 457 { 458 enum test_result result = PASS; 459 uint32_t i = 0; 460 461 printf("%s", tcfg->msg); 462 463 printf("%s", tcfg->htxt); 464 465 for (i = 0; i < tcfg->tconfig->num_cfg; i++) { 466 uint32_t avg = 0; 467 double drop_rate = 0.0; 468 double drop_prob = 0.0; 469 double diff = 0.0; 470 471 if (test_rte_pie_init(tcfg) != PASS) { 472 result = FAIL; 473 goto out; 474 } 475 476 rte_pie_rt_data_init(tcfg->tqueue->pdata_in); 477 rte_pie_set_active(NULL, tcfg->tqueue->pdata_in, 1); 478 *tcfg->tvar->enqueued = 0; 479 *tcfg->tvar->dropped = 0; 480 481 if (increase_qsize(&tcfg->tconfig->pconfig[i], 482 tcfg->tqueue->pdata_in, 483 tcfg->tqueue->qlen, 484 *tcfg->tlevel, 485 tcfg->tqueue->q_ramp_up) != 0) { 486 result = FAIL; 487 goto out; 488 } 489 490 enqueue_dequeue_func(&tcfg->tconfig->pconfig[i], 491 tcfg->tqueue->pdata_in, 492 tcfg->tqueue->qlen, 493 tcfg->tvar->num_ops, 494 tcfg->tvar->enqueued, 495 tcfg->tvar->dropped); 496 497 avg = rte_pie_get_avg_dq_time(NULL, tcfg->tqueue->pdata_in); 498 499 drop_rate = calc_drop_rate(*tcfg->tvar->enqueued, 500 *tcfg->tvar->dropped); 501 drop_prob = rte_pie_get_drop_prob(NULL, tcfg->tqueue->pdata_in); 502 503 if (!check_drop_rate(&diff, drop_rate, drop_prob, 504 (double)tcfg->tqueue->drop_tolerance)) { 505 fprintf(stderr, "Fail: drop rate outside tolerance\n"); 506 result = FAIL; 507 } 508 509 printf("%-15u%-15u%-15u%-15u%-15.4lf%-15.4lf%-15.4lf%-15.4lf\n", 510 i, avg, *tcfg->tvar->enqueued, *tcfg->tvar->dropped, 511 drop_prob * 100.0, drop_rate * 100.0, diff, 512 (double)tcfg->tqueue->drop_tolerance); 513 } 514 out: 515 return result; 516 } 517 518 static uint32_t ft3_qlen[] = {100}; 519 520 static struct test_rte_pie_config ft3_tconfig = { 521 .pconfig = ft_wpconfig, 522 .num_cfg = RTE_DIM(ft_wpconfig), 523 .qdelay_ref = 15, 524 .dp_update_interval = ft_dp_update_interval, 525 .max_burst = ft_max_burst, 526 .tailq_th = 15, 527 }; 528 529 static struct test_queue ft3_tqueue = { 530 .pdata_in = ft_rtdata, 531 .num_queues = RTE_DIM(ft_rtdata), 532 .qlen = ft3_qlen, 533 .q_ramp_up = 10, 534 .drop_tolerance = 0, 535 }; 536 537 static struct test_var ft3_tvar = { 538 .num_iterations = 0, 539 .num_ops = 10000, 540 .clk_freq = 0, 541 .dropped = ft_dropped, 542 .enqueued = ft_enqueued, 543 }; 544 545 /** 546 * Test F3: functional test 3 547 */ 548 static uint32_t ft3_tlevels[] = {64, 127, 222}; 549 550 static struct test_config func_test_config3 = { 551 .ifname = "functional test interface", 552 .msg = "functional test 2 : use one pie configuration\n" 553 "using non zero qlen\n\n", 554 .htxt = " " 555 "drop probability " 556 "enqueued " 557 "dropped " 558 "drop prob % " 559 "drop rate % " 560 "diff % " 561 "tolerance % " 562 "active " 563 "\n", 564 .tconfig = &ft3_tconfig, 565 .tqueue = &ft3_tqueue, 566 .tvar = &ft3_tvar, 567 .tlevel = ft3_tlevels, 568 }; 569 570 static enum test_result func_test3(struct test_config *tcfg) 571 { 572 enum test_result result = PASS; 573 uint32_t i = 0; 574 575 printf("%s", tcfg->msg); 576 577 if (test_rte_pie_init(tcfg) != PASS) { 578 result = FAIL; 579 goto out; 580 } 581 582 printf("%s", tcfg->htxt); 583 584 /** 585 * reset rte_pie run-time data 586 */ 587 rte_pie_rt_data_init(tcfg->tqueue->pdata_in); 588 rte_pie_set_active(NULL, tcfg->tqueue->pdata_in, 1); 589 *tcfg->tvar->enqueued = 0; 590 *tcfg->tvar->dropped = 0; 591 592 if (increase_qsize(&tcfg->tconfig->pconfig[i], 593 tcfg->tqueue->pdata_in, 594 tcfg->tqueue->qlen, 595 tcfg->tlevel[i], 596 tcfg->tqueue->q_ramp_up) != 0) { 597 fprintf(stderr, "Fail: increase qsize\n"); 598 result = FAIL; 599 goto out; 600 } 601 602 for (i = 0; i < RTE_DIM(ft_tlevels); i++) { 603 const char *label = NULL; 604 uint16_t prob = 0; 605 uint16_t active = 0; 606 double drop_rate = 1.0; 607 double drop_prob = 0.0; 608 double diff = 0.0; 609 610 enqueue_dequeue_func(&tcfg->tconfig->pconfig[i], 611 tcfg->tqueue->pdata_in, 612 tcfg->tqueue->qlen, 613 tcfg->tvar->num_ops, 614 tcfg->tvar->enqueued, 615 tcfg->tvar->dropped); 616 617 drop_rate = calc_drop_rate(*tcfg->tvar->enqueued, 618 *tcfg->tvar->dropped); 619 drop_prob = rte_pie_get_drop_prob(NULL, tcfg->tqueue->pdata_in); 620 621 if (drop_prob != 0) { 622 fprintf(stderr, "Fail: check drop prob\n"); 623 result = FAIL; 624 } 625 626 if (drop_rate != 0) { 627 fprintf(stderr, "Fail: check drop rate\n"); 628 result = FAIL; 629 } 630 631 label = "Summary "; 632 active = rte_pie_get_active(NULL, tcfg->tqueue->pdata_in); 633 printf("%s%-16u%-12u%-12u%-12.4lf%-12.4lf%-12.4lf%-12.4lf%-8i\n", 634 label, prob, *tcfg->tvar->enqueued, *tcfg->tvar->dropped, 635 drop_prob * 100.0, drop_rate * 100.0, diff, 636 (double)tcfg->tqueue->drop_tolerance, active); 637 } 638 out: 639 return result; 640 } 641 642 /** 643 * setup default values for the Performance test structures 644 */ 645 static struct rte_pie_config pt_wrconfig[1]; 646 static struct rte_pie pt_rtdata[1]; 647 static struct rte_pie pt_wtdata[1]; 648 static uint32_t pt_q[] = {0}; 649 static uint32_t pt_dropped[] = {0}; 650 static uint32_t pt_enqueued[] = {0}; 651 static uint32_t pt_dequeued[] = {0}; 652 static uint16_t pt_max_burst[] = {64}; 653 static uint16_t pt_dp_update_interval[] = {150}; 654 655 static struct test_rte_pie_config pt_tconfig = { 656 .pconfig = pt_wrconfig, 657 .num_cfg = RTE_DIM(pt_wrconfig), 658 .qdelay_ref = 15, 659 .dp_update_interval = pt_dp_update_interval, 660 .max_burst = pt_max_burst, 661 .tailq_th = 150, 662 }; 663 664 static struct test_queue pt_tqueue = { 665 .pdata_in = pt_rtdata, 666 .num_queues = RTE_DIM(pt_rtdata), 667 .qlen = pt_q, 668 .q_ramp_up = 1000000, 669 .drop_tolerance = 0, /* 0 percent */ 670 }; 671 672 static struct test_rte_pie_config pt_tconfig2 = { 673 .pconfig = pt_wrconfig, 674 .num_cfg = RTE_DIM(pt_wrconfig), 675 .qdelay_ref = 15, 676 .dp_update_interval = pt_dp_update_interval, 677 .max_burst = pt_max_burst, 678 .tailq_th = 150, 679 }; 680 681 static struct test_queue pt_tqueue2 = { 682 .pdata_in = pt_rtdata, 683 .pdata_out = pt_wtdata, 684 .num_queues = RTE_DIM(pt_rtdata), 685 .qlen = pt_q, 686 .q_ramp_up = 1000000, 687 .drop_tolerance = 0, /* 0 percent */ 688 }; 689 690 /** 691 * enqueue/dequeue packets 692 * aka 693 * rte_sched_port_enqueue(port, in_mbufs, 10); 694 * rte_sched_port_dequeue(port, out_mbufs, 10); 695 */ 696 static void enqueue_dequeue_perf(struct rte_pie_config *pie_cfg, 697 struct rte_pie *pie_in, 698 struct rte_pie *pie_out, 699 uint32_t *qlen, 700 uint32_t num_ops, 701 uint32_t *enqueued, 702 uint32_t *dropped, 703 uint32_t *dequeued, 704 struct rdtsc_prof *prof) 705 { 706 uint32_t i = 0; 707 708 if (pie_cfg == NULL) { 709 printf("%s: Error: PIE configuration cannot be empty.\n", __func__); 710 return; 711 } 712 713 if (pie_in == NULL) { 714 printf("%s: Error: PIE enqueue data cannot be empty.\n", __func__); 715 return; 716 } 717 718 for (i = 0; i < num_ops; i++) { 719 uint64_t ts = 0; 720 int ret = 0; 721 722 /** 723 * enqueue 724 */ 725 ts = get_port_ts(); 726 rdtsc_prof_start(prof); 727 ret = rte_pie_enqueue(pie_cfg, pie_in, *qlen, 728 1000*sizeof(uint32_t), ts); 729 rdtsc_prof_end(prof); 730 731 if (ret == 0) 732 (*enqueued)++; 733 else 734 (*dropped)++; 735 736 if (pie_out != NULL) { 737 ts = get_port_ts(); 738 rdtsc_prof_start(prof); 739 rte_pie_dequeue(pie_out, 1000*sizeof(uint32_t), ts); 740 rdtsc_prof_end(prof); 741 742 (*dequeued)++; 743 } 744 } 745 } 746 747 /** 748 * Setup test structures for tests P1 749 * performance tests 1 750 */ 751 static uint32_t pt1_tlevel[] = {80}; 752 753 static struct test_var perf1_tvar = { 754 .num_iterations = 0, 755 .num_ops = 30000, 756 .clk_freq = 0, 757 .dropped = pt_dropped, 758 .enqueued = pt_enqueued 759 }; 760 761 static struct test_config perf_test_config = { 762 .ifname = "performance test 1 interface", 763 .msg = "performance test 1 : use one PIE configuration,\n" 764 " measure enqueue performance\n\n", 765 .tconfig = &pt_tconfig, 766 .tqueue = &pt_tqueue, 767 .tvar = &perf1_tvar, 768 .tlevel = pt1_tlevel, 769 }; 770 771 /** 772 * Performance test function to measure enqueue performance. 773 * 774 */ 775 static enum test_result perf_test(struct test_config *tcfg) 776 { 777 enum test_result result = PASS; 778 struct rdtsc_prof prof = {0, 0, 0, 0, 0.0, NULL}; 779 uint32_t total = 0; 780 781 printf("%s", tcfg->msg); 782 783 rdtsc_prof_init(&prof, "enqueue"); 784 785 if (test_rte_pie_init(tcfg) != PASS) { 786 result = FAIL; 787 goto out; 788 } 789 790 /** 791 * initialize the rte_pie run time data structure 792 */ 793 rte_pie_rt_data_init(tcfg->tqueue->pdata_in); 794 rte_pie_set_active(NULL, tcfg->tqueue->pdata_in, 1); 795 *tcfg->tvar->enqueued = 0; 796 *tcfg->tvar->dropped = 0; 797 798 enqueue_dequeue_perf(tcfg->tconfig->pconfig, 799 tcfg->tqueue->pdata_in, 800 NULL, 801 tcfg->tqueue->qlen, 802 tcfg->tvar->num_ops, 803 tcfg->tvar->enqueued, 804 tcfg->tvar->dropped, 805 tcfg->tvar->dequeued, 806 &prof); 807 808 total = *tcfg->tvar->enqueued + *tcfg->tvar->dropped; 809 810 printf("\ntotal: %u, enqueued: %u (%.2lf%%), dropped: %u (%.2lf%%)\n", 811 total, *tcfg->tvar->enqueued, 812 ((double)(*tcfg->tvar->enqueued) / (double)total) * 100.0, 813 *tcfg->tvar->dropped, 814 ((double)(*tcfg->tvar->dropped) / (double)total) * 100.0); 815 816 rdtsc_prof_print(&prof); 817 out: 818 return result; 819 } 820 821 822 823 /** 824 * Setup test structures for tests P2 825 * performance tests 2 826 */ 827 static uint32_t pt2_tlevel[] = {80}; 828 829 static struct test_var perf2_tvar = { 830 .num_iterations = 0, 831 .num_ops = 30000, 832 .clk_freq = 0, 833 .dropped = pt_dropped, 834 .enqueued = pt_enqueued, 835 .dequeued = pt_dequeued 836 }; 837 838 static struct test_config perf_test_config2 = { 839 .ifname = "performance test 2 interface", 840 .msg = "performance test 2 : use one PIE configuration,\n" 841 " measure enqueue & dequeue performance\n\n", 842 .tconfig = &pt_tconfig2, 843 .tqueue = &pt_tqueue2, 844 .tvar = &perf2_tvar, 845 .tlevel = pt2_tlevel, 846 }; 847 848 /** 849 * Performance test function to measure enqueue & dequeue performance. 850 * 851 */ 852 static enum test_result perf_test2(struct test_config *tcfg) 853 { 854 enum test_result result = PASS; 855 struct rdtsc_prof prof = {0, 0, 0, 0, 0.0, NULL}; 856 uint32_t total = 0; 857 858 printf("%s", tcfg->msg); 859 860 rdtsc_prof_init(&prof, "enqueue"); 861 862 if (test_rte_pie_init(tcfg) != PASS) { 863 result = FAIL; 864 goto out; 865 } 866 867 /** 868 * initialize the rte_pie run time data structure 869 */ 870 rte_pie_rt_data_init(tcfg->tqueue->pdata_in); 871 rte_pie_set_active(NULL, tcfg->tqueue->pdata_in, 1); 872 *tcfg->tvar->enqueued = 0; 873 *tcfg->tvar->dequeued = 0; 874 *tcfg->tvar->dropped = 0; 875 876 enqueue_dequeue_perf(tcfg->tconfig->pconfig, 877 tcfg->tqueue->pdata_in, 878 tcfg->tqueue->pdata_out, 879 tcfg->tqueue->qlen, 880 tcfg->tvar->num_ops, 881 tcfg->tvar->enqueued, 882 tcfg->tvar->dropped, 883 tcfg->tvar->dequeued, 884 &prof); 885 886 total = *tcfg->tvar->enqueued + *tcfg->tvar->dropped; 887 888 printf("\ntotal: %u, dequeued: %u (%.2lf%%), dropped: %u (%.2lf%%)\n", 889 total, *tcfg->tvar->dequeued, 890 ((double)(*tcfg->tvar->dequeued) / (double)total) * 100.0, 891 *tcfg->tvar->dropped, 892 ((double)(*tcfg->tvar->dropped) / (double)total) * 100.0); 893 894 rdtsc_prof_print(&prof); 895 out: 896 return result; 897 } 898 899 /** 900 * define the functional tests to be executed fast 901 */ 902 struct tests func_pie_tests_quick[] = { 903 { &func_test_config1, func_test1 }, 904 { &func_test_config2, func_test2 }, 905 }; 906 907 /** 908 * define the functional and performance tests to be executed 909 */ 910 struct tests func_pie_tests[] = { 911 { &func_test_config1, func_test1 }, 912 { &func_test_config2, func_test2 }, 913 { &func_test_config3, func_test3 }, 914 }; 915 916 struct tests perf_pie_tests[] = { 917 { &perf_test_config, perf_test }, 918 { &perf_test_config2, perf_test2 }, 919 }; 920 921 /** 922 * function to execute the required pie tests 923 */ 924 static void run_tests(struct tests *test_type, uint32_t test_count, 925 uint32_t *num_tests, uint32_t *num_pass) 926 { 927 enum test_result result = PASS; 928 uint32_t i = 0; 929 static const char *bar_str = "-------------------------------------" 930 "-------------------------------------------"; 931 static const char *bar_pass_str = "-------------------------------------" 932 "<pass>-------------------------------------"; 933 static const char *bar_fail_str = "-------------------------------------" 934 "<fail>-------------------------------------"; 935 936 for (i = 0; i < test_count; i++) { 937 printf("\n%s\n", bar_str); 938 result = test_type[i].testfn(test_type[i].testcfg); 939 (*num_tests)++; 940 if (result == PASS) { 941 (*num_pass)++; 942 printf("%s\n", bar_pass_str); 943 } else { 944 printf("%s\n", bar_fail_str); 945 } 946 } 947 } 948 949 /** 950 * check if functions accept invalid parameters 951 * 952 * First, all functions will be called without initialized PIE 953 * Then, all of them will be called with NULL/invalid parameters 954 * 955 * Some functions are not tested as they are performance-critical and thus 956 * don't do any parameter checking. 957 */ 958 static int 959 test_invalid_parameters(void) 960 { 961 struct rte_pie_config config; 962 static const char *shf_str = "rte_pie_config_init should have failed!"; 963 static const char *shf_rt_str = "rte_pie_rt_data_init should have failed!"; 964 965 /* NULL config */ 966 if (rte_pie_rt_data_init(NULL) == 0) { 967 printf("%i: %s\n", __LINE__, shf_rt_str); 968 return -1; 969 } 970 971 /* NULL config */ 972 if (rte_pie_config_init(NULL, 0, 0, 0, 0) == 0) { 973 printf("%i%s\n", __LINE__, shf_str); 974 return -1; 975 } 976 977 /* qdelay_ref <= 0 */ 978 if (rte_pie_config_init(&config, 0, 1, 1, 1) == 0) { 979 printf("%i%s\n", __LINE__, shf_str); 980 return -1; 981 } 982 983 /* dp_update_interval <= 0 */ 984 if (rte_pie_config_init(&config, 1, 0, 1, 1) == 0) { 985 printf("%i%s\n", __LINE__, shf_str); 986 return -1; 987 } 988 989 /* max_burst <= 0 */ 990 if (rte_pie_config_init(&config, 1, 1, 0, 1) == 0) { 991 printf("%i%s\n", __LINE__, shf_str); 992 return -1; 993 } 994 995 /* tailq_th <= 0 */ 996 if (rte_pie_config_init(&config, 1, 1, 1, 0) == 0) { 997 printf("%i%s\n", __LINE__, shf_str); 998 return -1; 999 } 1000 1001 RTE_SET_USED(config); 1002 1003 return 0; 1004 } 1005 1006 static void 1007 show_stats(const uint32_t num_tests, const uint32_t num_pass) 1008 { 1009 if (num_pass == num_tests) 1010 printf("[total: %u, pass: %u]\n", num_tests, num_pass); 1011 else 1012 printf("[total: %u, pass: %u, fail: %u]\n", num_tests, num_pass, 1013 num_tests - num_pass); 1014 } 1015 1016 static int 1017 tell_the_result(const uint32_t num_tests, const uint32_t num_pass) 1018 { 1019 return (num_pass == num_tests) ? 0 : 1; 1020 } 1021 1022 static int 1023 test_pie(void) 1024 { 1025 uint32_t num_tests = 0; 1026 uint32_t num_pass = 0; 1027 1028 if (test_invalid_parameters() < 0) 1029 return -1; 1030 1031 run_tests(func_pie_tests_quick, RTE_DIM(func_pie_tests_quick), 1032 &num_tests, &num_pass); 1033 show_stats(num_tests, num_pass); 1034 return tell_the_result(num_tests, num_pass); 1035 } 1036 1037 static int 1038 test_pie_perf(void) 1039 { 1040 uint32_t num_tests = 0; 1041 uint32_t num_pass = 0; 1042 1043 run_tests(perf_pie_tests, RTE_DIM(perf_pie_tests), &num_tests, &num_pass); 1044 show_stats(num_tests, num_pass); 1045 return tell_the_result(num_tests, num_pass); 1046 } 1047 1048 static int 1049 test_pie_all(void) 1050 { 1051 uint32_t num_tests = 0; 1052 uint32_t num_pass = 0; 1053 1054 if (test_invalid_parameters() < 0) 1055 return -1; 1056 1057 run_tests(func_pie_tests, RTE_DIM(func_pie_tests), &num_tests, &num_pass); 1058 run_tests(perf_pie_tests, RTE_DIM(perf_pie_tests), &num_tests, &num_pass); 1059 show_stats(num_tests, num_pass); 1060 return tell_the_result(num_tests, num_pass); 1061 } 1062 1063 REGISTER_TEST_COMMAND(pie_autotest, test_pie); 1064 REGISTER_TEST_COMMAND(pie_perf, test_pie_perf); 1065 REGISTER_TEST_COMMAND(pie_all, test_pie_all); 1066