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