test/threads: add unit test
[dpdk.git] / app / test / test_pie.c
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
10 test_pie(void)
11 {
12         printf("pie not supported on Windows, skipping test\n");
13         return TEST_SKIPPED;
14 }
15
16 static int
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
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
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
118 static uint64_t get_port_ts(void)
119 {
120         return (uint64_t)((double)rte_rdtsc() * inv_cycles_per_byte);
121 }
122
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
132 static inline void rdtsc_prof_start(struct rdtsc_prof *p)
133 {
134         p->clk_start = rte_rdtsc_precise();
135 }
136
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
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
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
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  */
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
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
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  */
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
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
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
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
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
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
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  */
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  */
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  */
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  */
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
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
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
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
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
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
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_TEST_COMMAND(pie_autotest, test_pie);
1091 REGISTER_TEST_COMMAND(pie_perf, test_pie_perf);
1092 REGISTER_TEST_COMMAND(pie_all, test_pie_all);