xref: /dpdk/app/test/test_red.c (revision cf435a07)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <stdint.h>
38 #include <unistd.h>
39 #include <inttypes.h>
40 #include <sys/time.h>
41 #include <time.h>
42 #include <math.h>
43 
44 #include "test.h"
45 
46 #include <rte_red.h>
47 
48 #ifdef __INTEL_COMPILER
49 #pragma warning(disable:2259)       /* conversion may lose significant bits */
50 #pragma warning(disable:181)        /* Arg incompatible with format string */
51 #endif
52 
53 #define TEST_HZ_PER_KHZ 1000
54 #define TEST_NSEC_MARGIN 500        /**< nanosecond margin when calculating clk freq */
55 
56 #define MAX_QEMPTY_TIME_MSEC   50000
57 #define MSEC_PER_SEC           1000      /**< Milli-seconds per second */
58 #define USEC_PER_MSEC          1000      /**< Micro-seconds per milli-second */
59 #define USEC_PER_SEC           1000000   /**< Micro-seconds per second */
60 #define NSEC_PER_SEC           (USEC_PER_SEC * 1000) /**< Nano-seconds per second */
61 
62 /**< structures for testing rte_red performance and function */
63 struct test_rte_red_config {        /**< Test structure for RTE_RED config */
64 	struct rte_red_config *rconfig; /**< RTE_RED configuration parameters */
65 	uint8_t num_cfg;                /**< Number of RTE_RED configs to test */
66 	uint8_t *wq_log2;               /**< Test wq_log2 value to use */
67 	uint32_t min_th;                /**< Queue minimum threshold */
68 	uint32_t max_th;                /**< Queue maximum threshold */
69 	uint8_t *maxp_inv;              /**< Inverse mark probability */
70 };
71 
72 struct test_queue {                 /**< Test structure for RTE_RED Queues */
73 	struct rte_red *rdata;          /**< RTE_RED runtime data */
74 	uint32_t num_queues;            /**< Number of RTE_RED queues to test */
75 	uint32_t *qconfig;              /**< Configuration of RTE_RED queues for test */
76 	uint32_t *q;                    /**< Queue size */
77 	uint32_t q_ramp_up;             /**< Num of enqueues to ramp up the queue */
78 	uint32_t avg_ramp_up;           /**< Average num of enqueues to ramp up the queue */
79 	uint32_t avg_tolerance;         /**< Tolerance in queue average */
80 	double drop_tolerance;          /**< Drop tolerance of packets not enqueued */
81 };
82 
83 struct test_var {                   /**< Test variables used for testing RTE_RED */
84 	uint32_t wait_usec;             /**< Micro second wait interval */
85 	uint32_t num_iterations;        /**< Number of test iterations */
86 	uint32_t num_ops;               /**< Number of test operations */
87 	uint64_t clk_freq;              /**< CPU clock frequency */
88 	uint32_t sleep_sec;             /**< Seconds to sleep */
89 	uint32_t *dropped;              /**< Test operations dropped */
90 	uint32_t *enqueued;             /**< Test operations enqueued */
91 };
92 
93 struct test_config {                /**< Master test structure for RTE_RED */
94 	const char *ifname;             /**< Interface name */
95 	const char *msg;                /**< Test message for display */
96 	const char *htxt;               /**< Header txt display for result output */
97 	struct test_rte_red_config *tconfig; /**< Test structure for RTE_RED config */
98 	struct test_queue *tqueue;      /**< Test structure for RTE_RED Queues */
99 	struct test_var *tvar;          /**< Test variables used for testing RTE_RED */
100 	uint32_t *tlevel;               /**< Queue levels */
101 };
102 
103 enum test_result {
104 	FAIL = 0,
105 	PASS
106 };
107 
108 /**< Test structure to define tests to run */
109 struct tests {
110 	struct test_config *testcfg;
111 	enum test_result (*testfn)(struct test_config *);
112 };
113 
114 struct rdtsc_prof {
115 	uint64_t clk_start;
116 	uint64_t clk_min;               /**< min clocks */
117 	uint64_t clk_max;               /**< max clocks */
118 	uint64_t clk_avgc;              /**< count to calc average */
119 	double clk_avg;                 /**< cumulative sum to calc average */
120 	const char *name;
121 };
122 
123 static const uint64_t port_speed_bytes = (10ULL*1000ULL*1000ULL*1000ULL)/8ULL;
124 static double inv_cycles_per_byte = 0;
125 static double pkt_time_usec = 0;
126 
127 static void init_port_ts(uint64_t cpu_clock)
128 {
129 	double cycles_per_byte = (double)(cpu_clock) / (double)(port_speed_bytes);
130 	inv_cycles_per_byte = 1.0 / cycles_per_byte;
131 	pkt_time_usec = 1000000.0 / ((double)port_speed_bytes / (double)RTE_RED_S);
132 }
133 
134 static uint64_t get_port_ts(void)
135 {
136 	return (uint64_t)((double)rte_rdtsc() * inv_cycles_per_byte);
137 }
138 
139 static void rdtsc_prof_init(struct rdtsc_prof *p, const char *name)
140 {
141 	p->clk_min = (uint64_t)(-1LL);
142 	p->clk_max = 0;
143 	p->clk_avg = 0;
144 	p->clk_avgc = 0;
145 	p->name = name;
146 }
147 
148 static inline void rdtsc_prof_start(struct rdtsc_prof *p)
149 {
150 	p->clk_start = rte_rdtsc_precise();
151 }
152 
153 static inline void rdtsc_prof_end(struct rdtsc_prof *p)
154 {
155 	uint64_t clk_start = rte_rdtsc() - p->clk_start;
156 
157 	p->clk_avgc++;
158 	p->clk_avg += (double) clk_start;
159 
160 	if (clk_start > p->clk_max)
161 		p->clk_max = clk_start;
162 	if (clk_start < p->clk_min)
163 		p->clk_min = clk_start;
164 }
165 
166 static void rdtsc_prof_print(struct rdtsc_prof *p)
167 {
168 	if (p->clk_avgc>0) {
169 		printf("RDTSC stats for %s: n=%" PRIu64 ", min=%" PRIu64 ", max=%" PRIu64 ", avg=%.1f\n",
170 			p->name,
171 			p->clk_avgc,
172 			p->clk_min,
173 			p->clk_max,
174 			(p->clk_avg / ((double) p->clk_avgc)));
175 	}
176 }
177 
178 static uint32_t rte_red_get_avg_int(const struct rte_red_config *red_cfg,
179 				    struct rte_red *red)
180 {
181 	/**
182 	 * scale by 1/n and convert from fixed-point to integer
183 	 */
184 	return red->avg >> (RTE_RED_SCALING + red_cfg->wq_log2);
185 }
186 
187 static double rte_red_get_avg_float(const struct rte_red_config *red_cfg,
188 				    struct rte_red *red)
189 {
190 	/**
191 	 * scale by 1/n and convert from fixed-point to floating-point
192 	 */
193 	return ldexp((double)red->avg,  -(RTE_RED_SCALING + red_cfg->wq_log2));
194 }
195 
196 static void rte_red_set_avg_int(const struct rte_red_config *red_cfg,
197 				struct rte_red *red,
198 				uint32_t avg)
199 {
200 	/**
201 	 * scale by n and convert from integer to fixed-point
202 	 */
203 	red->avg = avg << (RTE_RED_SCALING + red_cfg->wq_log2);
204 }
205 
206 static double calc_exp_avg_on_empty(double avg, uint32_t n, uint32_t time_diff)
207 {
208 	return avg * pow((1.0 - 1.0 / (double)n), (double)time_diff / pkt_time_usec);
209 }
210 
211 static double calc_drop_rate(uint32_t enqueued, uint32_t dropped)
212 {
213 	return (double)dropped / ((double)enqueued + (double)dropped);
214 }
215 
216 /**
217  * calculate the drop probability
218  */
219 static double calc_drop_prob(uint32_t min_th, uint32_t max_th,
220 			     uint32_t maxp_inv, uint32_t avg)
221 {
222 	double drop_prob = 0.0;
223 
224 	if (avg < min_th) {
225 		drop_prob = 0.0;
226 	} else if (avg < max_th) {
227 		drop_prob = (1.0 / (double)maxp_inv)
228 			* ((double)(avg - min_th)
229 			   / (double)(max_th - min_th));
230 	} else {
231 		drop_prob = 1.0;
232 	}
233 	return drop_prob;
234 }
235 
236 /**
237  *  check if drop rate matches drop probability within tolerance
238  */
239 static int check_drop_rate(double *diff, double drop_rate, double drop_prob, double tolerance)
240 {
241 	double abs_diff = 0.0;
242 	int ret = 1;
243 
244 	abs_diff = fabs(drop_rate - drop_prob);
245 	if ((int)abs_diff == 0) {
246 	        *diff = 0.0;
247 	} else {
248 	        *diff = (abs_diff / drop_prob) * 100.0;
249 	        if (*diff > tolerance) {
250 	                ret = 0;
251 	        }
252         }
253 	return ret;
254 }
255 
256 /**
257  *  check if average queue size is within tolerance
258  */
259 static int check_avg(double *diff, double avg, double exp_avg, double tolerance)
260 {
261 	double abs_diff = 0.0;
262 	int ret = 1;
263 
264 	abs_diff = fabs(avg - exp_avg);
265 	if ((int)abs_diff == 0) {
266 	        *diff = 0.0;
267 	} else {
268 	        *diff = (abs_diff / exp_avg) * 100.0;
269 	        if (*diff > tolerance) {
270 	                ret = 0;
271                 }
272 	}
273 	return ret;
274 }
275 
276 /**
277  * initialize the test rte_red config
278  */
279 static enum test_result
280 test_rte_red_init(struct test_config *tcfg)
281 {
282 	unsigned i = 0;
283 
284 	tcfg->tvar->clk_freq = rte_get_timer_hz();
285 	init_port_ts( tcfg->tvar->clk_freq );
286 
287 	for (i = 0; i < tcfg->tconfig->num_cfg; i++) {
288 		if (rte_red_config_init(&tcfg->tconfig->rconfig[i],
289 					(uint16_t)tcfg->tconfig->wq_log2[i],
290 					(uint16_t)tcfg->tconfig->min_th,
291 					(uint16_t)tcfg->tconfig->max_th,
292 					(uint16_t)tcfg->tconfig->maxp_inv[i]) != 0) {
293 			return FAIL;
294 		}
295 	}
296 
297 	*tcfg->tqueue->q = 0;
298 	*tcfg->tvar->dropped = 0;
299 	*tcfg->tvar->enqueued = 0;
300 	return PASS;
301 }
302 
303 /**
304  * enqueue until actual queue size reaches target level
305  */
306 static int
307 increase_actual_qsize(struct rte_red_config *red_cfg,
308                       struct rte_red *red,
309                       uint32_t *q,
310                       uint32_t level,
311                       uint32_t attempts)
312 {
313         uint32_t i = 0;
314 
315         for (i = 0; i < attempts; i++) {
316                 int ret = 0;
317 
318                 /**
319                  * enqueue
320                  */
321                 ret = rte_red_enqueue(red_cfg, red, *q, get_port_ts() );
322                 if (ret == 0) {
323                         if (++(*q) >= level)
324                                 break;
325                 }
326         }
327         /**
328         * check if target actual queue size has been reached
329         */
330         if (*q != level)
331                 return -1;
332         /**
333          * success
334          */
335         return 0;
336 }
337 
338 /**
339  * enqueue until average queue size reaches target level
340  */
341 static int
342 increase_average_qsize(struct rte_red_config *red_cfg,
343                        struct rte_red *red,
344                        uint32_t *q,
345                        uint32_t level,
346                        uint32_t num_ops)
347 {
348         uint32_t avg = 0;
349         uint32_t i = 0;
350 
351         for (i = 0; i < num_ops; i++) {
352                 /**
353                  * enqueue
354                  */
355                 rte_red_enqueue(red_cfg, red, *q, get_port_ts());
356         }
357         /**
358          * check if target average queue size has been reached
359          */
360         avg = rte_red_get_avg_int(red_cfg, red);
361         if (avg != level)
362                 return -1;
363         /**
364          * success
365          */
366         return 0;
367 }
368 
369 /**
370  * setup default values for the functional test structures
371  */
372 static struct rte_red_config ft_wrconfig[1];
373 static struct rte_red ft_rtdata[1];
374 static uint8_t ft_wq_log2[] = {9};
375 static uint8_t ft_maxp_inv[] = {10};
376 static uint32_t  ft_qconfig[] = {0, 0, 1, 1};
377 static uint32_t  ft_q[] ={0};
378 static uint32_t  ft_dropped[] ={0};
379 static uint32_t  ft_enqueued[] ={0};
380 
381 static struct test_rte_red_config ft_tconfig =  {
382 	.rconfig = ft_wrconfig,
383 	.num_cfg = RTE_DIM(ft_wrconfig),
384 	.wq_log2 = ft_wq_log2,
385 	.min_th = 32,
386 	.max_th = 128,
387 	.maxp_inv = ft_maxp_inv,
388 };
389 
390 static struct test_queue ft_tqueue = {
391 	.rdata = ft_rtdata,
392 	.num_queues = RTE_DIM(ft_rtdata),
393 	.qconfig = ft_qconfig,
394 	.q = ft_q,
395 	.q_ramp_up = 1000000,
396 	.avg_ramp_up = 1000000,
397 	.avg_tolerance = 5,  /* 5 percent */
398 	.drop_tolerance = 50,  /* 50 percent */
399 };
400 
401 static struct test_var ft_tvar = {
402 	.wait_usec = 10000,
403 	.num_iterations = 5,
404 	.num_ops = 10000,
405 	.clk_freq = 0,
406 	.dropped = ft_dropped,
407 	.enqueued = ft_enqueued,
408 	.sleep_sec = (MAX_QEMPTY_TIME_MSEC / MSEC_PER_SEC) + 2,
409 };
410 
411 /**
412  * functional test enqueue/dequeue packets
413  */
414 static void enqueue_dequeue_func(struct rte_red_config *red_cfg,
415                                  struct rte_red *red,
416                                  uint32_t *q,
417                                  uint32_t num_ops,
418                                  uint32_t *enqueued,
419                                  uint32_t *dropped)
420 {
421         uint32_t i = 0;
422 
423         for (i = 0; i < num_ops; i++) {
424                 int ret = 0;
425 
426                 /**
427                  * enqueue
428                  */
429                 ret = rte_red_enqueue(red_cfg, red, *q, get_port_ts());
430                 if (ret == 0)
431                         (*enqueued)++;
432                 else
433                         (*dropped)++;
434         }
435 }
436 
437 /**
438  * Test F1: functional test 1
439  */
440 static uint32_t ft1_tlevels[] =  {6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, 78, 84, 90, 96, 102, 108, 114, 120, 126, 132, 138, 144};
441 
442 static struct test_config func_test1_config = {
443 	.ifname = "functional test 1 interface",
444 	.msg = "functional test 1 : use one rte_red configuration,\n"
445 	"		    increase average queue size to various levels,\n"
446 	"		    compare drop rate to drop probability\n\n",
447 	.htxt = "                "
448 	"avg queue size "
449 	"enqueued       "
450 	"dropped        "
451 	"drop prob %    "
452 	"drop rate %    "
453 	"diff %         "
454 	"tolerance %    "
455 	"\n",
456 	.tconfig = &ft_tconfig,
457 	.tqueue = &ft_tqueue,
458 	.tvar = &ft_tvar,
459 	.tlevel = ft1_tlevels,
460 };
461 
462 static enum test_result func_test1(struct test_config *tcfg)
463 {
464 	enum test_result result = PASS;
465 	uint32_t i = 0;
466 
467 	printf("%s", tcfg->msg);
468 
469 	if (test_rte_red_init(tcfg) != PASS) {
470 		result = FAIL;
471 		goto out;
472 	}
473 
474 	printf("%s", tcfg->htxt);
475 
476 	for (i = 0; i < RTE_DIM(ft1_tlevels); i++) {
477 		const char *label = NULL;
478 		uint32_t avg = 0;
479 		double drop_rate = 0.0;
480 		double drop_prob = 0.0;
481 		double diff = 0.0;
482 
483 		/**
484 		 * reset rte_red run-time data
485 		 */
486 		rte_red_rt_data_init(tcfg->tqueue->rdata);
487 		*tcfg->tvar->enqueued = 0;
488 		*tcfg->tvar->dropped = 0;
489 
490 		if (increase_actual_qsize(tcfg->tconfig->rconfig,
491 					  tcfg->tqueue->rdata,
492 					  tcfg->tqueue->q,
493 					  tcfg->tlevel[i],
494 					  tcfg->tqueue->q_ramp_up) != 0) {
495 			result = FAIL;
496 			goto out;
497 		}
498 
499 		if (increase_average_qsize(tcfg->tconfig->rconfig,
500 					   tcfg->tqueue->rdata,
501 					   tcfg->tqueue->q,
502 					   tcfg->tlevel[i],
503 					   tcfg->tqueue->avg_ramp_up) != 0)  {
504 			result = FAIL;
505 			goto out;
506 		}
507 
508 		enqueue_dequeue_func(tcfg->tconfig->rconfig,
509 				     tcfg->tqueue->rdata,
510 				     tcfg->tqueue->q,
511 				     tcfg->tvar->num_ops,
512 				     tcfg->tvar->enqueued,
513 				     tcfg->tvar->dropped);
514 
515 		avg = rte_red_get_avg_int(tcfg->tconfig->rconfig, tcfg->tqueue->rdata);
516 		if (avg != tcfg->tlevel[i]) {
517                         fprintf(stderr, "Fail: avg != level\n");
518 			result = FAIL;
519                 }
520 
521 		drop_rate = calc_drop_rate(*tcfg->tvar->enqueued, *tcfg->tvar->dropped);
522 		drop_prob = calc_drop_prob(tcfg->tconfig->min_th, tcfg->tconfig->max_th,
523 					   *tcfg->tconfig->maxp_inv, tcfg->tlevel[i]);
524 		if (!check_drop_rate(&diff, drop_rate, drop_prob, (double)tcfg->tqueue->drop_tolerance))
525 		        result = FAIL;
526 
527 		if (tcfg->tlevel[i] == tcfg->tconfig->min_th)
528 			label = "min thresh:     ";
529 		else if (tcfg->tlevel[i] == tcfg->tconfig->max_th)
530 			label = "max thresh:     ";
531 		else
532 			label = "                ";
533 		printf("%s%-15u%-15u%-15u%-15.4lf%-15.4lf%-15.4lf%-15.4lf\n",
534 		       label, avg, *tcfg->tvar->enqueued, *tcfg->tvar->dropped,
535 		       drop_prob * 100.0, drop_rate * 100.0, diff,
536 	               (double)tcfg->tqueue->drop_tolerance);
537 	}
538 out:
539 	return result;
540 }
541 
542 /**
543  * Test F2: functional test 2
544  */
545 static uint32_t ft2_tlevel[] = {127};
546 static uint8_t ft2_wq_log2[] = {9, 9, 9, 9, 9, 9, 9, 9, 9, 9};
547 static uint8_t ft2_maxp_inv[] = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
548 static struct rte_red_config ft2_rconfig[10];
549 
550 static struct test_rte_red_config ft2_tconfig =  {
551 	.rconfig = ft2_rconfig,
552 	.num_cfg = RTE_DIM(ft2_rconfig),
553 	.wq_log2 = ft2_wq_log2,
554 	.min_th = 32,
555 	.max_th = 128,
556 	.maxp_inv = ft2_maxp_inv,
557 };
558 
559 static struct test_config func_test2_config = {
560 	.ifname = "functional test 2 interface",
561 	.msg = "functional test 2 : use several RED configurations,\n"
562 	"		    increase average queue size to just below maximum threshold,\n"
563 	"		    compare drop rate to drop probability\n\n",
564 	.htxt = "RED config     "
565 	"avg queue size "
566 	"min threshold  "
567 	"max threshold  "
568 	"drop prob %    "
569 	"drop rate %    "
570 	"diff %         "
571 	"tolerance %    "
572 	"\n",
573 	.tconfig = &ft2_tconfig,
574 	.tqueue = &ft_tqueue,
575 	.tvar = &ft_tvar,
576 	.tlevel = ft2_tlevel,
577 };
578 
579 static enum test_result func_test2(struct test_config *tcfg)
580 {
581 	enum test_result result = PASS;
582         double prev_drop_rate = 1.0;
583 	uint32_t i = 0;
584 
585 	printf("%s", tcfg->msg);
586 
587 	if (test_rte_red_init(tcfg) != PASS) {
588 		result = FAIL;
589 		goto out;
590 	}
591 	rte_red_rt_data_init(tcfg->tqueue->rdata);
592 
593 	if (increase_actual_qsize(tcfg->tconfig->rconfig,
594 				  tcfg->tqueue->rdata,
595 				  tcfg->tqueue->q,
596 				  *tcfg->tlevel,
597 				  tcfg->tqueue->q_ramp_up) != 0) {
598 		result = FAIL;
599 		goto out;
600 	}
601 
602 	if (increase_average_qsize(tcfg->tconfig->rconfig,
603 				   tcfg->tqueue->rdata,
604 				   tcfg->tqueue->q,
605 				   *tcfg->tlevel,
606 				   tcfg->tqueue->avg_ramp_up) != 0) {
607 		result = FAIL;
608 		goto out;
609 	}
610 	printf("%s", tcfg->htxt);
611 
612 	for (i = 0; i < tcfg->tconfig->num_cfg; i++) {
613 		uint32_t avg = 0;
614 		double drop_rate = 0.0;
615 		double drop_prob = 0.0;
616 		double diff = 0.0;
617 
618 		*tcfg->tvar->dropped = 0;
619 		*tcfg->tvar->enqueued = 0;
620 
621 		enqueue_dequeue_func(&tcfg->tconfig->rconfig[i],
622 				     tcfg->tqueue->rdata,
623 				     tcfg->tqueue->q,
624 				     tcfg->tvar->num_ops,
625 				     tcfg->tvar->enqueued,
626 				     tcfg->tvar->dropped);
627 
628 		avg = rte_red_get_avg_int(&tcfg->tconfig->rconfig[i], tcfg->tqueue->rdata);
629 		if (avg != *tcfg->tlevel)
630 			result = FAIL;
631 
632 		drop_rate = calc_drop_rate(*tcfg->tvar->enqueued, *tcfg->tvar->dropped);
633 		drop_prob = calc_drop_prob(tcfg->tconfig->min_th, tcfg->tconfig->max_th,
634 					   tcfg->tconfig->maxp_inv[i], *tcfg->tlevel);
635 		if (!check_drop_rate(&diff, drop_rate, drop_prob, (double)tcfg->tqueue->drop_tolerance))
636 		        result = FAIL;
637 	        /**
638 	         * drop rate should decrease as maxp_inv increases
639 	         */
640 	        if (drop_rate > prev_drop_rate)
641 	                result = FAIL;
642 	        prev_drop_rate = drop_rate;
643 
644 		printf("%-15u%-15u%-15u%-15u%-15.4lf%-15.4lf%-15.4lf%-15.4lf\n",
645 		       i, avg, tcfg->tconfig->min_th, tcfg->tconfig->max_th,
646 		       drop_prob * 100.0, drop_rate * 100.0, diff,
647 	               (double)tcfg->tqueue->drop_tolerance);
648 	}
649 out:
650 	return result;
651 }
652 
653 /**
654  * Test F3: functional test 3
655  */
656 static uint32_t ft3_tlevel[] = {1022};
657 
658 static struct test_rte_red_config ft3_tconfig =  {
659 	.rconfig = ft_wrconfig,
660 	.num_cfg = RTE_DIM(ft_wrconfig),
661 	.wq_log2 = ft_wq_log2,
662 	.min_th = 32,
663 	.max_th = 1023,
664 	.maxp_inv = ft_maxp_inv,
665 };
666 
667 static struct test_config func_test3_config = {
668 	.ifname = "functional test 3 interface",
669 	.msg = "functional test 3 : use one RED configuration,\n"
670 	"		    increase average queue size to target level,\n"
671 	"		    dequeue all packets until queue is empty,\n"
672 	"		    confirm that average queue size is computed correctly while queue is empty\n\n",
673 	.htxt = "q avg before   "
674 	"q avg after    "
675 	"expected       "
676 	"difference %   "
677 	"tolerance %    "
678 	"result	 "
679 	"\n",
680 	.tconfig = &ft3_tconfig,
681 	.tqueue = &ft_tqueue,
682 	.tvar = &ft_tvar,
683 	.tlevel = ft3_tlevel,
684 };
685 
686 static enum test_result func_test3(struct test_config *tcfg)
687 {
688 	enum test_result result = PASS;
689 	uint32_t i = 0;
690 
691 	printf("%s", tcfg->msg);
692 
693 	if (test_rte_red_init(tcfg) != PASS) {
694 		result = FAIL;
695 		goto out;
696 	}
697 
698 	rte_red_rt_data_init(tcfg->tqueue->rdata);
699 
700 	if (increase_actual_qsize(tcfg->tconfig->rconfig,
701 				  tcfg->tqueue->rdata,
702 				  tcfg->tqueue->q,
703 				  *tcfg->tlevel,
704 				  tcfg->tqueue->q_ramp_up) != 0) {
705 		result = FAIL;
706 		goto out;
707 	}
708 
709 	if (increase_average_qsize(tcfg->tconfig->rconfig,
710 				   tcfg->tqueue->rdata,
711 				   tcfg->tqueue->q,
712 				   *tcfg->tlevel,
713 				   tcfg->tqueue->avg_ramp_up) != 0) {
714 		result = FAIL;
715 		goto out;
716 	}
717 
718 	printf("%s", tcfg->htxt);
719 
720 	for (i = 0; i < tcfg->tvar->num_iterations; i++) {
721 		double avg_before = 0;
722 		double avg_after = 0;
723                 double exp_avg = 0;
724 		double diff = 0.0;
725 
726 		avg_before = rte_red_get_avg_float(tcfg->tconfig->rconfig, tcfg->tqueue->rdata);
727 
728 		/**
729 		* empty the queue
730 		*/
731 		*tcfg->tqueue->q = 0;
732 		rte_red_mark_queue_empty(tcfg->tqueue->rdata, get_port_ts());
733 
734 		rte_delay_us(tcfg->tvar->wait_usec);
735 
736 		/**
737 		 * enqueue one packet to recalculate average queue size
738 		 */
739 		if (rte_red_enqueue(tcfg->tconfig->rconfig,
740 				    tcfg->tqueue->rdata,
741 				    *tcfg->tqueue->q,
742 				    get_port_ts()) == 0) {
743 			(*tcfg->tqueue->q)++;
744 		} else {
745 			printf("%s:%d: packet enqueued on empty queue was dropped\n", __func__, __LINE__);
746 			result = FAIL;
747 		}
748 
749 		exp_avg = calc_exp_avg_on_empty(avg_before,
750 					      (1 << *tcfg->tconfig->wq_log2),
751 					      tcfg->tvar->wait_usec);
752 		avg_after = rte_red_get_avg_float(tcfg->tconfig->rconfig,
753 						  tcfg->tqueue->rdata);
754 		if (!check_avg(&diff, avg_after, exp_avg, (double)tcfg->tqueue->avg_tolerance))
755 		        result = FAIL;
756 
757 		printf("%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15s\n",
758 		       avg_before, avg_after, exp_avg, diff,
759 		       (double)tcfg->tqueue->avg_tolerance,
760 		       diff <= (double)tcfg->tqueue->avg_tolerance ? "pass" : "fail");
761 	}
762 out:
763 	return result;
764 }
765 
766 /**
767  * Test F4: functional test 4
768  */
769 static uint32_t ft4_tlevel[] = {1022};
770 static uint8_t ft4_wq_log2[] = {11};
771 
772 static struct test_rte_red_config ft4_tconfig =  {
773 	.rconfig = ft_wrconfig,
774 	.num_cfg = RTE_DIM(ft_wrconfig),
775 	.min_th = 32,
776 	.max_th = 1023,
777 	.wq_log2 = ft4_wq_log2,
778 	.maxp_inv = ft_maxp_inv,
779 };
780 
781 static struct test_queue ft4_tqueue = {
782 	.rdata = ft_rtdata,
783 	.num_queues = RTE_DIM(ft_rtdata),
784 	.qconfig = ft_qconfig,
785 	.q = ft_q,
786 	.q_ramp_up = 1000000,
787 	.avg_ramp_up = 1000000,
788 	.avg_tolerance = 0,  /* 0 percent */
789 	.drop_tolerance = 50,  /* 50 percent */
790 };
791 
792 static struct test_config func_test4_config = {
793 	.ifname = "functional test 4 interface",
794 	.msg = "functional test 4 : use one RED configuration,\n"
795 	"		    increase average queue size to target level,\n"
796 	"		    dequeue all packets until queue is empty,\n"
797 	"		    confirm that average queue size is computed correctly while\n"
798 	"		    queue is empty for more than 50 sec,\n"
799 	"		    (this test takes 52 sec to run)\n\n",
800 	.htxt = "q avg before   "
801 	"q avg after    "
802 	"expected       "
803 	"difference %   "
804 	"tolerance %    "
805 	"result	 "
806 	"\n",
807 	.tconfig = &ft4_tconfig,
808 	.tqueue = &ft4_tqueue,
809 	.tvar = &ft_tvar,
810 	.tlevel = ft4_tlevel,
811 };
812 
813 static enum test_result func_test4(struct test_config *tcfg)
814 {
815 	enum test_result result = PASS;
816 	uint64_t time_diff = 0;
817 	uint64_t start = 0;
818 	double avg_before = 0.0;
819 	double avg_after = 0.0;
820         double exp_avg = 0.0;
821         double diff = 0.0;
822 
823 	printf("%s", tcfg->msg);
824 
825 	if (test_rte_red_init(tcfg) != PASS) {
826 		result = FAIL;
827 		goto out;
828 	}
829 
830 	rte_red_rt_data_init(tcfg->tqueue->rdata);
831 
832 	if (increase_actual_qsize(tcfg->tconfig->rconfig,
833 				  tcfg->tqueue->rdata,
834 				  tcfg->tqueue->q,
835 				  *tcfg->tlevel,
836 				  tcfg->tqueue->q_ramp_up) != 0) {
837 		result = FAIL;
838 		goto out;
839 	}
840 
841 	if (increase_average_qsize(tcfg->tconfig->rconfig,
842 				   tcfg->tqueue->rdata,
843 				   tcfg->tqueue->q,
844 				   *tcfg->tlevel,
845 				   tcfg->tqueue->avg_ramp_up) != 0) {
846 		result = FAIL;
847 		goto out;
848 	}
849 
850 	printf("%s", tcfg->htxt);
851 
852 	avg_before = rte_red_get_avg_float(tcfg->tconfig->rconfig, tcfg->tqueue->rdata);
853 
854 	/**
855 	 * empty the queue
856 	 */
857 	*tcfg->tqueue->q = 0;
858 	rte_red_mark_queue_empty(tcfg->tqueue->rdata, get_port_ts());
859 
860 	/**
861 	 * record empty time locally
862 	 */
863 	start = rte_rdtsc();
864 
865 	sleep(tcfg->tvar->sleep_sec);
866 
867 	/**
868 	 * enqueue one packet to recalculate average queue size
869 	 */
870 	if (rte_red_enqueue(tcfg->tconfig->rconfig,
871 			    tcfg->tqueue->rdata,
872 			    *tcfg->tqueue->q,
873 			    get_port_ts()) != 0) {
874 		result = FAIL;
875 		goto out;
876 	}
877 	(*tcfg->tqueue->q)++;
878 
879 	/**
880 	 * calculate how long queue has been empty
881 	 */
882 	time_diff = ((rte_rdtsc() - start) / tcfg->tvar->clk_freq)
883 		  * MSEC_PER_SEC;
884 	if (time_diff < MAX_QEMPTY_TIME_MSEC) {
885 		/**
886 		 * this could happen if sleep was interrupted for some reason
887 		 */
888 		result = FAIL;
889 		goto out;
890 	}
891 
892 	/**
893 	 * confirm that average queue size is now at expected level
894 	 */
895         exp_avg = 0.0;
896 	avg_after = rte_red_get_avg_float(tcfg->tconfig->rconfig, tcfg->tqueue->rdata);
897 	if (!check_avg(&diff, avg_after, exp_avg, (double)tcfg->tqueue->avg_tolerance))
898 	        result = FAIL;
899 
900 	printf("%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15s\n",
901 	       avg_before, avg_after, exp_avg,
902 	       diff, (double)tcfg->tqueue->avg_tolerance,
903 	       diff <= (double)tcfg->tqueue->avg_tolerance ? "pass" : "fail");
904 out:
905 	return result;
906 }
907 
908 /**
909  * Test F5: functional test 5
910  */
911 static uint32_t ft5_tlevel[] = {127};
912 static uint8_t ft5_wq_log2[] = {9, 8};
913 static uint8_t ft5_maxp_inv[] = {10, 20};
914 static struct rte_red_config ft5_config[2];
915 static struct rte_red ft5_data[4];
916 static uint32_t ft5_q[4];
917 static uint32_t ft5_dropped[] = {0, 0, 0, 0};
918 static uint32_t ft5_enqueued[] = {0, 0, 0, 0};
919 
920 static struct test_rte_red_config ft5_tconfig =  {
921 	.rconfig = ft5_config,
922 	.num_cfg = RTE_DIM(ft5_config),
923 	.min_th = 32,
924 	.max_th = 128,
925 	.wq_log2 = ft5_wq_log2,
926 	.maxp_inv = ft5_maxp_inv,
927 };
928 
929 static struct test_queue ft5_tqueue = {
930 	.rdata = ft5_data,
931 	.num_queues = RTE_DIM(ft5_data),
932 	.qconfig = ft_qconfig,
933 	.q = ft5_q,
934 	.q_ramp_up = 1000000,
935 	.avg_ramp_up = 1000000,
936 	.avg_tolerance = 5,  /* 10 percent */
937 	.drop_tolerance = 50,  /* 50 percent */
938 };
939 
940 struct test_var ft5_tvar = {
941 	.wait_usec = 0,
942 	.num_iterations = 15,
943 	.num_ops = 10000,
944 	.clk_freq = 0,
945 	.dropped = ft5_dropped,
946 	.enqueued = ft5_enqueued,
947 	.sleep_sec = 0,
948 };
949 
950 static struct test_config func_test5_config = {
951 	.ifname = "functional test 5 interface",
952 	.msg = "functional test 5 : use several queues (each with its own run-time data),\n"
953 	"		    use several RED configurations (such that each configuration is shared by multiple queues),\n"
954 	"		    increase average queue size to just below maximum threshold,\n"
955 	"		    compare drop rate to drop probability,\n"
956 	"		    (this is a larger scale version of functional test 2)\n\n",
957 	.htxt = "queue          "
958 	"config         "
959 	"avg queue size "
960 	"min threshold  "
961 	"max threshold  "
962 	"drop prob %    "
963 	"drop rate %    "
964 	"diff %         "
965 	"tolerance %    "
966 	"\n",
967 	.tconfig = &ft5_tconfig,
968 	.tqueue = &ft5_tqueue,
969 	.tvar = &ft5_tvar,
970 	.tlevel = ft5_tlevel,
971 };
972 
973 static enum test_result func_test5(struct test_config *tcfg)
974 {
975 	enum test_result result = PASS;
976 	uint32_t j = 0;
977 
978 	printf("%s", tcfg->msg);
979 
980 	if (test_rte_red_init(tcfg) != PASS) {
981 		result = FAIL;
982 		goto out;
983 	}
984 
985 	printf("%s", tcfg->htxt);
986 
987 	for (j = 0; j < tcfg->tqueue->num_queues; j++) {
988 		rte_red_rt_data_init(&tcfg->tqueue->rdata[j]);
989 		tcfg->tqueue->q[j] = 0;
990 
991 		if (increase_actual_qsize(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]],
992 					  &tcfg->tqueue->rdata[j],
993 					  &tcfg->tqueue->q[j],
994 					  *tcfg->tlevel,
995 					  tcfg->tqueue->q_ramp_up) != 0) {
996 			result = FAIL;
997 			goto out;
998 		}
999 
1000 		if (increase_average_qsize(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]],
1001 					   &tcfg->tqueue->rdata[j],
1002 					   &tcfg->tqueue->q[j],
1003 					   *tcfg->tlevel,
1004 					   tcfg->tqueue->avg_ramp_up) != 0) {
1005 			result = FAIL;
1006 			goto out;
1007 		}
1008 	}
1009 
1010 	for (j = 0; j < tcfg->tqueue->num_queues; j++) {
1011 		uint32_t avg = 0;
1012 		double drop_rate = 0.0;
1013 		double drop_prob = 0.0;
1014 		double diff = 0.0;
1015 
1016 		tcfg->tvar->dropped[j] = 0;
1017 		tcfg->tvar->enqueued[j] = 0;
1018 
1019 		enqueue_dequeue_func(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]],
1020 				     &tcfg->tqueue->rdata[j],
1021 				     &tcfg->tqueue->q[j],
1022 				     tcfg->tvar->num_ops,
1023 				     &tcfg->tvar->enqueued[j],
1024 				     &tcfg->tvar->dropped[j]);
1025 
1026 		avg = rte_red_get_avg_int(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]],
1027 					  &tcfg->tqueue->rdata[j]);
1028 		if (avg != *tcfg->tlevel)
1029 			result = FAIL;
1030 
1031 		drop_rate = calc_drop_rate(tcfg->tvar->enqueued[j],tcfg->tvar->dropped[j]);
1032 		drop_prob = calc_drop_prob(tcfg->tconfig->min_th, tcfg->tconfig->max_th,
1033 					   tcfg->tconfig->maxp_inv[tcfg->tqueue->qconfig[j]],
1034 					   *tcfg->tlevel);
1035 		if (!check_drop_rate(&diff, drop_rate, drop_prob, (double)tcfg->tqueue->drop_tolerance))
1036 		        result = FAIL;
1037 
1038 		printf("%-15u%-15u%-15u%-15u%-15u%-15.4lf%-15.4lf%-15.4lf%-15.4lf\n",
1039 		       j, tcfg->tqueue->qconfig[j], avg,
1040 		       tcfg->tconfig->min_th, tcfg->tconfig->max_th,
1041 		       drop_prob * 100.0, drop_rate * 100.0,
1042 		       diff, (double)tcfg->tqueue->drop_tolerance);
1043 	}
1044 out:
1045 	return result;
1046 }
1047 
1048 /**
1049  * Test F6: functional test 6
1050  */
1051 static uint32_t ft6_tlevel[] = {1022};
1052 static uint8_t ft6_wq_log2[] = {9, 8};
1053 static uint8_t ft6_maxp_inv[] = {10, 20};
1054 static struct rte_red_config ft6_config[2];
1055 static struct rte_red ft6_data[4];
1056 static uint32_t ft6_q[4];
1057 
1058 static struct test_rte_red_config ft6_tconfig =  {
1059 	.rconfig = ft6_config,
1060 	.num_cfg = RTE_DIM(ft6_config),
1061 	.min_th = 32,
1062 	.max_th = 1023,
1063 	.wq_log2 = ft6_wq_log2,
1064 	.maxp_inv = ft6_maxp_inv,
1065 };
1066 
1067 static struct test_queue ft6_tqueue = {
1068 	.rdata = ft6_data,
1069 	.num_queues = RTE_DIM(ft6_data),
1070 	.qconfig = ft_qconfig,
1071 	.q = ft6_q,
1072 	.q_ramp_up = 1000000,
1073 	.avg_ramp_up = 1000000,
1074 	.avg_tolerance = 5,  /* 10 percent */
1075 	.drop_tolerance = 50,  /* 50 percent */
1076 };
1077 
1078 static struct test_config func_test6_config = {
1079 	.ifname = "functional test 6 interface",
1080 	.msg = "functional test 6 : use several queues (each with its own run-time data),\n"
1081 	"		    use several RED configurations (such that each configuration is sharte_red by multiple queues),\n"
1082 	"		    increase average queue size to target level,\n"
1083 	"		    dequeue all packets until queue is empty,\n"
1084 	"		    confirm that average queue size is computed correctly while queue is empty\n"
1085 	"		    (this is a larger scale version of functional test 3)\n\n",
1086 	.htxt = "queue          "
1087 	"config         "
1088 	"q avg before   "
1089 	"q avg after    "
1090 	"expected       "
1091 	"difference %   "
1092 	"tolerance %    "
1093 	"result	 ""\n",
1094 	.tconfig = &ft6_tconfig,
1095 	.tqueue = &ft6_tqueue,
1096 	.tvar = &ft_tvar,
1097 	.tlevel = ft6_tlevel,
1098 };
1099 
1100 static enum test_result func_test6(struct test_config *tcfg)
1101 {
1102 	enum test_result result = PASS;
1103 	uint32_t j = 0;
1104 
1105 	printf("%s", tcfg->msg);
1106 	if (test_rte_red_init(tcfg) != PASS) {
1107 		result = FAIL;
1108 		goto out;
1109 	}
1110 	printf("%s", tcfg->htxt);
1111 
1112 	for (j = 0; j < tcfg->tqueue->num_queues; j++) {
1113 		rte_red_rt_data_init(&tcfg->tqueue->rdata[j]);
1114 		tcfg->tqueue->q[j] = 0;
1115 
1116 		if (increase_actual_qsize(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]],
1117 					  &tcfg->tqueue->rdata[j],
1118 					  &tcfg->tqueue->q[j],
1119 					  *tcfg->tlevel,
1120 					  tcfg->tqueue->q_ramp_up) != 0) {
1121 			result = FAIL;
1122 			goto out;
1123 		}
1124 		if (increase_average_qsize(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]],
1125 					   &tcfg->tqueue->rdata[j],
1126 					   &tcfg->tqueue->q[j],
1127 					   *tcfg->tlevel,
1128 					   tcfg->tqueue->avg_ramp_up) != 0) {
1129 			result = FAIL;
1130 			goto out;
1131 		}
1132 	}
1133 	for (j = 0; j < tcfg->tqueue->num_queues; j++) {
1134 		double avg_before = 0;
1135 		double avg_after = 0;
1136 		double exp_avg = 0;
1137 		double diff = 0.0;
1138 
1139 		avg_before = rte_red_get_avg_float(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]],
1140 						   &tcfg->tqueue->rdata[j]);
1141 
1142 		/**
1143 		 * empty the queue
1144 		 */
1145 		tcfg->tqueue->q[j] = 0;
1146 		rte_red_mark_queue_empty(&tcfg->tqueue->rdata[j], get_port_ts());
1147 		rte_delay_us(tcfg->tvar->wait_usec);
1148 
1149 		/**
1150 		 * enqueue one packet to recalculate average queue size
1151 		 */
1152 		if (rte_red_enqueue(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]],
1153 				    &tcfg->tqueue->rdata[j],
1154 				    tcfg->tqueue->q[j],
1155 				    get_port_ts()) == 0) {
1156 			tcfg->tqueue->q[j]++;
1157 		} else {
1158 			printf("%s:%d: packet enqueued on empty queue was dropped\n", __func__, __LINE__);
1159 			result = FAIL;
1160 		}
1161 
1162 		exp_avg = calc_exp_avg_on_empty(avg_before,
1163 				(1 << tcfg->tconfig->wq_log2[tcfg->tqueue->qconfig[j]]),
1164 				tcfg->tvar->wait_usec);
1165 		avg_after = rte_red_get_avg_float(&tcfg->tconfig->rconfig[tcfg->tqueue->qconfig[j]],
1166 						&tcfg->tqueue->rdata[j]);
1167 		if (!check_avg(&diff, avg_after, exp_avg, (double)tcfg->tqueue->avg_tolerance))
1168 		        result = FAIL;
1169 
1170 		printf("%-15u%-15u%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15s\n",
1171 		       j, tcfg->tqueue->qconfig[j], avg_before, avg_after,
1172 		       exp_avg, diff, (double)tcfg->tqueue->avg_tolerance,
1173 		       diff <= tcfg->tqueue->avg_tolerance ? "pass" : "fail");
1174 	}
1175 out:
1176 	return result;
1177 }
1178 
1179 /**
1180  * setup default values for the performance test structures
1181  */
1182 static struct rte_red_config pt_wrconfig[1];
1183 static struct rte_red pt_rtdata[1];
1184 static uint8_t pt_wq_log2[] = {9};
1185 static uint8_t pt_maxp_inv[] = {10};
1186 static uint32_t pt_qconfig[] = {0};
1187 static uint32_t pt_q[] = {0};
1188 static uint32_t pt_dropped[] = {0};
1189 static uint32_t pt_enqueued[] = {0};
1190 
1191 static struct test_rte_red_config pt_tconfig =  {
1192 	.rconfig = pt_wrconfig,
1193 	.num_cfg = RTE_DIM(pt_wrconfig),
1194 	.wq_log2 = pt_wq_log2,
1195 	.min_th = 32,
1196 	.max_th = 128,
1197 	.maxp_inv = pt_maxp_inv,
1198 };
1199 
1200 static struct test_queue pt_tqueue = {
1201 	.rdata = pt_rtdata,
1202 	.num_queues = RTE_DIM(pt_rtdata),
1203 	.qconfig = pt_qconfig,
1204 	.q = pt_q,
1205 	.q_ramp_up = 1000000,
1206 	.avg_ramp_up = 1000000,
1207 	.avg_tolerance = 5,  /* 10 percent */
1208 	.drop_tolerance = 50,  /* 50 percent */
1209 };
1210 
1211 /**
1212  * enqueue/dequeue packets
1213  */
1214 static void enqueue_dequeue_perf(struct rte_red_config *red_cfg,
1215 				 struct rte_red *red,
1216 				 uint32_t *q,
1217 				 uint32_t num_ops,
1218 				 uint32_t *enqueued,
1219 				 uint32_t *dropped,
1220 				 struct rdtsc_prof *prof)
1221 {
1222 	uint32_t i = 0;
1223 
1224 	for (i = 0; i < num_ops; i++) {
1225 		uint64_t ts = 0;
1226 		int ret = 0;
1227 		/**
1228 		 * enqueue
1229 		 */
1230 		ts = get_port_ts();
1231 		rdtsc_prof_start(prof);
1232 		ret = rte_red_enqueue(red_cfg, red, *q, ts );
1233 		rdtsc_prof_end(prof);
1234 		if (ret == 0)
1235 			(*enqueued)++;
1236 		else
1237 			(*dropped)++;
1238 	}
1239 }
1240 
1241 /**
1242  * Setup test structures for tests P1, P2, P3
1243  * performance tests 1, 2 and 3
1244  */
1245 static uint32_t pt1_tlevel[] = {16};
1246 static uint32_t pt2_tlevel[] = {80};
1247 static uint32_t pt3_tlevel[] = {144};
1248 
1249 static struct test_var perf1_tvar = {
1250 	.wait_usec = 0,
1251 	.num_iterations = 15,
1252 	.num_ops = 50000000,
1253 	.clk_freq = 0,
1254 	.dropped = pt_dropped,
1255 	.enqueued = pt_enqueued,
1256 	.sleep_sec = 0
1257 };
1258 
1259 static struct test_config perf1_test1_config = {
1260 	.ifname = "performance test 1 interface",
1261 	.msg = "performance test 1 : use one RED configuration,\n"
1262 	"		     set actual and average queue sizes to level below min threshold,\n"
1263 	"		     measure enqueue performance\n\n",
1264 	.tconfig = &pt_tconfig,
1265 	.tqueue = &pt_tqueue,
1266 	.tvar = &perf1_tvar,
1267 	.tlevel = pt1_tlevel,
1268 };
1269 
1270 static struct test_config perf1_test2_config = {
1271 	.ifname = "performance test 2 interface",
1272 	.msg = "performance test 2 : use one RED configuration,\n"
1273 	"		     set actual and average queue sizes to level in between min and max thresholds,\n"
1274 	"		     measure enqueue performance\n\n",
1275 	.tconfig = &pt_tconfig,
1276 	.tqueue = &pt_tqueue,
1277 	.tvar = &perf1_tvar,
1278 	.tlevel = pt2_tlevel,
1279 };
1280 
1281 static struct test_config perf1_test3_config = {
1282 	.ifname = "performance test 3 interface",
1283 	.msg = "performance test 3 : use one RED configuration,\n"
1284 	"		     set actual and average queue sizes to level above max threshold,\n"
1285 	"		     measure enqueue performance\n\n",
1286 	.tconfig = &pt_tconfig,
1287 	.tqueue = &pt_tqueue,
1288 	.tvar = &perf1_tvar,
1289 	.tlevel = pt3_tlevel,
1290 };
1291 
1292 /**
1293  * Performance test function to measure enqueue performance.
1294  * This runs performance tests 1, 2 and 3
1295  */
1296 static enum test_result perf1_test(struct test_config *tcfg)
1297 {
1298 	enum test_result result = PASS;
1299 	struct rdtsc_prof prof = {0, 0, 0, 0, 0.0, NULL};
1300 	uint32_t total = 0;
1301 
1302 	printf("%s", tcfg->msg);
1303 
1304 	rdtsc_prof_init(&prof, "enqueue");
1305 
1306 	if (test_rte_red_init(tcfg) != PASS) {
1307 		result = FAIL;
1308 		goto out;
1309 	}
1310 
1311 	/**
1312 	 * set average queue size to target level
1313 	 */
1314 	*tcfg->tqueue->q = *tcfg->tlevel;
1315 
1316 	/**
1317 	 * initialize the rte_red run time data structure
1318 	 */
1319 	rte_red_rt_data_init(tcfg->tqueue->rdata);
1320 
1321 	/**
1322 	 *  set the queue average
1323 	 */
1324 	rte_red_set_avg_int(tcfg->tconfig->rconfig, tcfg->tqueue->rdata, *tcfg->tlevel);
1325 	if (rte_red_get_avg_int(tcfg->tconfig->rconfig, tcfg->tqueue->rdata)
1326 	    != *tcfg->tlevel) {
1327 		result = FAIL;
1328 		goto out;
1329 	}
1330 
1331 	enqueue_dequeue_perf(tcfg->tconfig->rconfig,
1332 			     tcfg->tqueue->rdata,
1333 			     tcfg->tqueue->q,
1334 			     tcfg->tvar->num_ops,
1335 			     tcfg->tvar->enqueued,
1336 			     tcfg->tvar->dropped,
1337 			     &prof);
1338 
1339 	total = *tcfg->tvar->enqueued + *tcfg->tvar->dropped;
1340 
1341 	printf("\ntotal: %u, enqueued: %u (%.2lf%%), dropped: %u (%.2lf%%)\n", total,
1342 	       *tcfg->tvar->enqueued, ((double)(*tcfg->tvar->enqueued) / (double)total) * 100.0,
1343 	       *tcfg->tvar->dropped, ((double)(*tcfg->tvar->dropped) / (double)total) * 100.0);
1344 
1345 	rdtsc_prof_print(&prof);
1346 out:
1347 	return result;
1348 }
1349 
1350 /**
1351  * Setup test structures for tests P4, P5, P6
1352  * performance tests 4, 5 and 6
1353  */
1354 static uint32_t pt4_tlevel[] = {16};
1355 static uint32_t pt5_tlevel[] = {80};
1356 static uint32_t pt6_tlevel[] = {144};
1357 
1358 static struct test_var perf2_tvar = {
1359 	.wait_usec = 500,
1360 	.num_iterations = 10000,
1361 	.num_ops = 10000,
1362 	.dropped = pt_dropped,
1363 	.enqueued = pt_enqueued,
1364 	.sleep_sec = 0
1365 };
1366 
1367 static struct test_config perf2_test4_config = {
1368 	.ifname = "performance test 4 interface",
1369 	.msg = "performance test 4 : use one RED configuration,\n"
1370 	"		     set actual and average queue sizes to level below min threshold,\n"
1371 	"		     dequeue all packets until queue is empty,\n"
1372 	"		     measure enqueue performance when queue is empty\n\n",
1373 	.htxt = "iteration      "
1374 	"q avg before   "
1375 	"q avg after    "
1376 	"expected       "
1377 	"difference %   "
1378 	"tolerance %    "
1379 	"result	 ""\n",
1380 	.tconfig = &pt_tconfig,
1381 	.tqueue = &pt_tqueue,
1382 	.tvar = &perf2_tvar,
1383 	.tlevel = pt4_tlevel,
1384 };
1385 
1386 static struct test_config perf2_test5_config = {
1387 	.ifname = "performance test 5 interface",
1388 	.msg = "performance test 5 : use one RED configuration,\n"
1389 	"		     set actual and average queue sizes to level in between min and max thresholds,\n"
1390 	"		     dequeue all packets until queue is empty,\n"
1391 	"		     measure enqueue performance when queue is empty\n\n",
1392 	.htxt = "iteration      "
1393 	"q avg before   "
1394 	"q avg after    "
1395 	"expected       "
1396 	"difference     "
1397 	"tolerance      "
1398 	"result	 ""\n",
1399 	.tconfig = &pt_tconfig,
1400 	.tqueue = &pt_tqueue,
1401 	.tvar = &perf2_tvar,
1402 	.tlevel = pt5_tlevel,
1403 };
1404 
1405 static struct test_config perf2_test6_config = {
1406 	.ifname = "performance test 6 interface",
1407 	.msg = "performance test 6 : use one RED configuration,\n"
1408 	"		     set actual and average queue sizes to level above max threshold,\n"
1409 	"		     dequeue all packets until queue is empty,\n"
1410 	"		     measure enqueue performance when queue is empty\n\n",
1411 	.htxt = "iteration      "
1412 	"q avg before   "
1413 	"q avg after    "
1414 	"expected       "
1415 	"difference %   "
1416 	"tolerance %    "
1417 	"result	 ""\n",
1418 	.tconfig = &pt_tconfig,
1419 	.tqueue = &pt_tqueue,
1420 	.tvar = &perf2_tvar,
1421 	.tlevel = pt6_tlevel,
1422 };
1423 
1424 /**
1425  * Performance test function to measure enqueue performance when the
1426  * queue is empty. This runs performance tests 4, 5 and 6
1427  */
1428 static enum test_result perf2_test(struct test_config *tcfg)
1429 {
1430 	enum test_result result = PASS;
1431 	struct rdtsc_prof prof = {0, 0, 0, 0, 0.0, NULL};
1432 	uint32_t total = 0;
1433 	uint32_t i = 0;
1434 
1435 	printf("%s", tcfg->msg);
1436 
1437 	rdtsc_prof_init(&prof, "enqueue");
1438 
1439 	if (test_rte_red_init(tcfg) != PASS) {
1440 		result = FAIL;
1441 		goto out;
1442 	}
1443 
1444 	printf("%s", tcfg->htxt);
1445 
1446 	for (i = 0; i < tcfg->tvar->num_iterations; i++) {
1447 		uint32_t count = 0;
1448 		uint64_t ts = 0;
1449 		double avg_before = 0;
1450 		int ret = 0;
1451 
1452 		/**
1453 		 * set average queue size to target level
1454 		 */
1455 		*tcfg->tqueue->q = *tcfg->tlevel;
1456 		count = (*tcfg->tqueue->rdata).count;
1457 
1458 		/**
1459 		 * initialize the rte_red run time data structure
1460 		 */
1461 		rte_red_rt_data_init(tcfg->tqueue->rdata);
1462 		(*tcfg->tqueue->rdata).count = count;
1463 
1464 		/**
1465 		 * set the queue average
1466 		 */
1467 		rte_red_set_avg_int(tcfg->tconfig->rconfig, tcfg->tqueue->rdata, *tcfg->tlevel);
1468 		avg_before = rte_red_get_avg_float(tcfg->tconfig->rconfig, tcfg->tqueue->rdata);
1469 		if ((avg_before < *tcfg->tlevel) || (avg_before > *tcfg->tlevel)) {
1470 			result = FAIL;
1471 			goto out;
1472 		}
1473 
1474 		/**
1475 		 * empty the queue
1476 		 */
1477 		*tcfg->tqueue->q = 0;
1478 		rte_red_mark_queue_empty(tcfg->tqueue->rdata, get_port_ts());
1479 
1480 		/**
1481 		 * wait for specified period of time
1482 		 */
1483 		rte_delay_us(tcfg->tvar->wait_usec);
1484 
1485 		/**
1486 		 * measure performance of enqueue operation while queue is empty
1487 		 */
1488 		ts = get_port_ts();
1489 		rdtsc_prof_start(&prof);
1490 		ret = rte_red_enqueue(tcfg->tconfig->rconfig, tcfg->tqueue->rdata,
1491 				      *tcfg->tqueue->q, ts );
1492 		rdtsc_prof_end(&prof);
1493 
1494 		/**
1495 		 * gather enqueued/dropped statistics
1496 		 */
1497 		if (ret == 0)
1498 			(*tcfg->tvar->enqueued)++;
1499 		else
1500 			(*tcfg->tvar->dropped)++;
1501 
1502 		/**
1503 		 * on first and last iteration, confirm that
1504 		 * average queue size was computed correctly
1505 		 */
1506 		if ((i == 0) || (i == tcfg->tvar->num_iterations - 1)) {
1507 			double avg_after = 0;
1508 			double exp_avg = 0;
1509 			double diff = 0.0;
1510 			int ok = 0;
1511 
1512 			avg_after = rte_red_get_avg_float(tcfg->tconfig->rconfig, tcfg->tqueue->rdata);
1513 			exp_avg = calc_exp_avg_on_empty(avg_before,
1514 						  (1 << *tcfg->tconfig->wq_log2),
1515 						  tcfg->tvar->wait_usec);
1516 			if (check_avg(&diff, avg_after, exp_avg, (double)tcfg->tqueue->avg_tolerance))
1517 		        	ok = 1;
1518 			printf("%-15u%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15.4lf%-15s\n",
1519 				i, avg_before, avg_after, exp_avg, diff,
1520 				(double)tcfg->tqueue->avg_tolerance, ok ? "pass" : "fail");
1521 			if (!ok) {
1522 				result = FAIL;
1523 				goto out;
1524 			}
1525 		}
1526 	}
1527 	total =  *tcfg->tvar->enqueued +  *tcfg->tvar->dropped;
1528 	printf("\ntotal: %u, enqueued: %u (%.2lf%%), dropped: %u (%.2lf%%)\n", total,
1529 	       *tcfg->tvar->enqueued, ((double)(*tcfg->tvar->enqueued) / (double)total) * 100.0,
1530 	       *tcfg->tvar->dropped, ((double)(*tcfg->tvar->dropped) / (double)total) * 100.0);
1531 
1532 	rdtsc_prof_print(&prof);
1533 out:
1534 	return result;
1535 }
1536 
1537 /**
1538  * setup default values for overflow test structures
1539  */
1540 static uint32_t avg_max = 0;
1541 static uint32_t avg_max_bits = 0;
1542 
1543 static struct rte_red_config ovfl_wrconfig[1];
1544 static struct rte_red ovfl_rtdata[1];
1545 static uint8_t ovfl_maxp_inv[] = {10};
1546 static uint32_t ovfl_qconfig[] = {0, 0, 1, 1};
1547 static uint32_t ovfl_q[] ={0};
1548 static uint32_t ovfl_dropped[] ={0};
1549 static uint32_t ovfl_enqueued[] ={0};
1550 static uint32_t ovfl_tlevel[] = {1023};
1551 static uint8_t ovfl_wq_log2[] = {12};
1552 
1553 static struct test_rte_red_config ovfl_tconfig =  {
1554 	.rconfig = ovfl_wrconfig,
1555 	.num_cfg = RTE_DIM(ovfl_wrconfig),
1556 	.wq_log2 = ovfl_wq_log2,
1557 	.min_th = 32,
1558 	.max_th = 1023,
1559 	.maxp_inv = ovfl_maxp_inv,
1560 };
1561 
1562 static struct test_queue ovfl_tqueue = {
1563 	.rdata = ovfl_rtdata,
1564 	.num_queues = RTE_DIM(ovfl_rtdata),
1565 	.qconfig = ovfl_qconfig,
1566 	.q = ovfl_q,
1567 	.q_ramp_up = 1000000,
1568 	.avg_ramp_up = 1000000,
1569 	.avg_tolerance = 5,  /* 10 percent */
1570 	.drop_tolerance = 50,  /* 50 percent */
1571 };
1572 
1573 static struct test_var ovfl_tvar = {
1574 	.wait_usec = 10000,
1575 	.num_iterations = 1,
1576 	.num_ops = 10000,
1577 	.clk_freq = 0,
1578 	.dropped = ovfl_dropped,
1579 	.enqueued = ovfl_enqueued,
1580 	.sleep_sec = 0
1581 };
1582 
1583 static void ovfl_check_avg(uint32_t avg)
1584 {
1585 	if (avg > avg_max) {
1586 		double avg_log = 0;
1587 		uint32_t bits = 0;
1588 		avg_max = avg;
1589 		avg_log = log(((double)avg_max));
1590 		avg_log = avg_log / log(2.0);
1591 		bits = (uint32_t)ceil(avg_log);
1592 		if (bits > avg_max_bits)
1593 			avg_max_bits = bits;
1594 	}
1595 }
1596 
1597 static struct test_config ovfl_test1_config = {
1598 	.ifname = "queue avergage overflow test interface",
1599 	.msg = "overflow test 1 : use one RED configuration,\n"
1600 	"		  increase average queue size to target level,\n"
1601 	"		  check maximum number of bits requirte_red to represent avg_s\n\n",
1602 	.htxt = "avg queue size  "
1603 	"wq_log2  "
1604 	"fraction bits  "
1605 	"max queue avg  "
1606 	"num bits  "
1607 	"enqueued  "
1608 	"dropped   "
1609 	"drop prob %  "
1610 	"drop rate %  "
1611 	"\n",
1612 	.tconfig = &ovfl_tconfig,
1613 	.tqueue = &ovfl_tqueue,
1614 	.tvar = &ovfl_tvar,
1615 	.tlevel = ovfl_tlevel,
1616 };
1617 
1618 static enum test_result ovfl_test1(struct test_config *tcfg)
1619 {
1620 	enum test_result result = PASS;
1621 	uint32_t avg = 0;
1622 	uint32_t i = 0;
1623 	double drop_rate = 0.0;
1624 	double drop_prob = 0.0;
1625 	double diff = 0.0;
1626 	int ret = 0;
1627 
1628 	printf("%s", tcfg->msg);
1629 
1630 	if (test_rte_red_init(tcfg) != PASS) {
1631 
1632 		result = FAIL;
1633 		goto out;
1634 	}
1635 
1636 	/**
1637 	 * reset rte_red run-time data
1638 	 */
1639 	rte_red_rt_data_init(tcfg->tqueue->rdata);
1640 
1641 	/**
1642 	 * increase actual queue size
1643 	 */
1644 	for (i = 0; i < tcfg->tqueue->q_ramp_up; i++) {
1645 		ret = rte_red_enqueue(tcfg->tconfig->rconfig, tcfg->tqueue->rdata,
1646 				      *tcfg->tqueue->q, get_port_ts());
1647 
1648 		if (ret == 0) {
1649 			if (++(*tcfg->tqueue->q) >= *tcfg->tlevel)
1650 				break;
1651 		}
1652 	}
1653 
1654 	/**
1655 	 * enqueue
1656 	 */
1657 	for (i = 0; i < tcfg->tqueue->avg_ramp_up; i++) {
1658 		ret = rte_red_enqueue(tcfg->tconfig->rconfig, tcfg->tqueue->rdata,
1659 				      *tcfg->tqueue->q, get_port_ts());
1660 		ovfl_check_avg((*tcfg->tqueue->rdata).avg);
1661 		avg = rte_red_get_avg_int(tcfg->tconfig->rconfig, tcfg->tqueue->rdata);
1662 		if (avg == *tcfg->tlevel) {
1663 			if (ret == 0)
1664 				(*tcfg->tvar->enqueued)++;
1665 			else
1666 				(*tcfg->tvar->dropped)++;
1667 		}
1668 	}
1669 
1670 	/**
1671 	 * check if target average queue size has been reached
1672 	 */
1673 	avg = rte_red_get_avg_int(tcfg->tconfig->rconfig, tcfg->tqueue->rdata);
1674 	if (avg != *tcfg->tlevel) {
1675 		result = FAIL;
1676 		goto out;
1677 	}
1678 
1679 	/**
1680 	 * check drop rate against drop probability
1681 	 */
1682 	drop_rate = calc_drop_rate(*tcfg->tvar->enqueued, *tcfg->tvar->dropped);
1683 	drop_prob = calc_drop_prob(tcfg->tconfig->min_th,
1684 				   tcfg->tconfig->max_th,
1685 				   *tcfg->tconfig->maxp_inv,
1686 				   *tcfg->tlevel);
1687 	if (!check_drop_rate(&diff, drop_rate, drop_prob, (double)tcfg->tqueue->drop_tolerance))
1688 	        result = FAIL;
1689 
1690 	printf("%s", tcfg->htxt);
1691 
1692 	printf("%-16u%-9u%-15u0x%08x     %-10u%-10u%-10u%-13.2lf%-13.2lf\n",
1693 	       avg, *tcfg->tconfig->wq_log2, RTE_RED_SCALING,
1694 	       avg_max, avg_max_bits,
1695 	       *tcfg->tvar->enqueued, *tcfg->tvar->dropped,
1696 	       drop_prob * 100.0, drop_rate * 100.0);
1697 out:
1698 	return result;
1699 }
1700 
1701 /**
1702  * define the functional and performance tests to be executed
1703  */
1704 struct tests func_tests[] = {
1705 	{ &func_test1_config, func_test1 },
1706 	{ &func_test2_config, func_test2 },
1707 	{ &func_test3_config, func_test3 },
1708 	{ &func_test4_config, func_test4 },
1709 	{ &func_test5_config, func_test5 },
1710 	{ &func_test6_config, func_test6 },
1711 	{ &ovfl_test1_config, ovfl_test1 },
1712 };
1713 
1714 struct tests func_tests_quick[] = {
1715 	{ &func_test1_config, func_test1 },
1716 	{ &func_test2_config, func_test2 },
1717 	{ &func_test3_config, func_test3 },
1718 	/* no test 4 as it takes a lot of time */
1719 	{ &func_test5_config, func_test5 },
1720 	{ &func_test6_config, func_test6 },
1721 	{ &ovfl_test1_config, ovfl_test1 },
1722 };
1723 
1724 struct tests perf_tests[] = {
1725 	{ &perf1_test1_config, perf1_test },
1726 	{ &perf1_test2_config, perf1_test },
1727 	{ &perf1_test3_config, perf1_test },
1728 	{ &perf2_test4_config, perf2_test },
1729 	{ &perf2_test5_config, perf2_test },
1730 	{ &perf2_test6_config, perf2_test },
1731 };
1732 
1733 /**
1734  * function to execute the required_red tests
1735  */
1736 static void run_tests(struct tests *test_type, uint32_t test_count, uint32_t *num_tests, uint32_t *num_pass)
1737 {
1738 	enum test_result result = PASS;
1739 	uint32_t i = 0;
1740 
1741 	for (i = 0; i < test_count; i++) {
1742 		printf("\n--------------------------------------------------------------------------------\n");
1743 		result = test_type[i].testfn(test_type[i].testcfg);
1744 		(*num_tests)++;
1745 		if (result == PASS) {
1746 			(*num_pass)++;
1747 				printf("-------------------------------------<pass>-------------------------------------\n");
1748 		} else {
1749 			printf("-------------------------------------<fail>-------------------------------------\n");
1750 		}
1751 	}
1752 	return;
1753 }
1754 
1755 /**
1756  * check if functions accept invalid parameters
1757  *
1758  * First, all functions will be called without initialized RED
1759  * Then, all of them will be called with NULL/invalid parameters
1760  *
1761  * Some functions are not tested as they are performance-critical and thus
1762  * don't do any parameter checking.
1763  */
1764 static int
1765 test_invalid_parameters(void)
1766 {
1767 	struct rte_red_config config;
1768 
1769 	if (rte_red_rt_data_init(NULL) == 0) {
1770 		printf("rte_red_rt_data_init should have failed!\n");
1771 		return -1;
1772 	}
1773 
1774 	if (rte_red_config_init(NULL, 0, 0, 0, 0) == 0) {
1775 		printf("rte_red_config_init should have failed!\n");
1776 		return -1;
1777 	}
1778 
1779 	if (rte_red_rt_data_init(NULL) == 0) {
1780 		printf("rte_red_rt_data_init should have failed!\n");
1781 		return -1;
1782 	}
1783 
1784 	/* NULL config */
1785 	if (rte_red_config_init(NULL, 0, 0, 0, 0) == 0) {
1786 		printf("%i: rte_red_config_init should have failed!\n", __LINE__);
1787 		return -1;
1788 	}
1789 	/* min_treshold == max_treshold */
1790 	if (rte_red_config_init(&config, 0, 1, 1, 0) == 0) {
1791 		printf("%i: rte_red_config_init should have failed!\n", __LINE__);
1792 		return -1;
1793 	}
1794 	/* min_treshold > max_treshold */
1795 	if (rte_red_config_init(&config, 0, 2, 1, 0) == 0) {
1796 		printf("%i: rte_red_config_init should have failed!\n", __LINE__);
1797 		return -1;
1798 	}
1799 	/* wq_log2 > RTE_RED_WQ_LOG2_MAX */
1800 	if (rte_red_config_init(&config,
1801 			RTE_RED_WQ_LOG2_MAX + 1, 1, 2, 0) == 0) {
1802 		printf("%i: rte_red_config_init should have failed!\n", __LINE__);
1803 		return -1;
1804 	}
1805 	/* wq_log2 < RTE_RED_WQ_LOG2_MIN */
1806 	if (rte_red_config_init(&config,
1807 			RTE_RED_WQ_LOG2_MIN - 1, 1, 2, 0) == 0) {
1808 		printf("%i: rte_red_config_init should have failed!\n", __LINE__);
1809 		return -1;
1810 	}
1811 	/* maxp_inv > RTE_RED_MAXP_INV_MAX */
1812 	if (rte_red_config_init(&config,
1813 			RTE_RED_WQ_LOG2_MIN, 1, 2, RTE_RED_MAXP_INV_MAX + 1) == 0) {
1814 		printf("%i: rte_red_config_init should have failed!\n", __LINE__);
1815 		return -1;
1816 	}
1817 	/* maxp_inv < RTE_RED_MAXP_INV_MIN */
1818 	if (rte_red_config_init(&config,
1819 			RTE_RED_WQ_LOG2_MIN, 1, 2, RTE_RED_MAXP_INV_MIN - 1) == 0) {
1820 		printf("%i: rte_red_config_init should have failed!\n", __LINE__);
1821 		return -1;
1822 	}
1823 
1824 	return 0;
1825 }
1826 
1827 static void
1828 show_stats(const uint32_t num_tests, const uint32_t num_pass)
1829 {
1830 	if (num_pass == num_tests)
1831 		printf("[total: %u, pass: %u]\n", num_tests, num_pass);
1832 	else
1833 		printf("[total: %u, pass: %u, fail: %u]\n", num_tests, num_pass,
1834 		       num_tests - num_pass);
1835 }
1836 
1837 static int
1838 tell_the_result(const uint32_t num_tests, const uint32_t num_pass)
1839 {
1840 	return (num_pass == num_tests) ? 0 : 1;
1841 }
1842 
1843 static int
1844 test_red(void)
1845 {
1846 	uint32_t num_tests = 0;
1847 	uint32_t num_pass = 0;
1848 
1849 	if (test_invalid_parameters() < 0)
1850 		return -1;
1851 	run_tests(func_tests_quick, RTE_DIM(func_tests_quick),
1852 		  &num_tests, &num_pass);
1853 	show_stats(num_tests, num_pass);
1854 	return tell_the_result(num_tests, num_pass);
1855 }
1856 
1857 static int
1858 test_red_perf(void)
1859 {
1860 	uint32_t num_tests = 0;
1861 	uint32_t num_pass = 0;
1862 
1863 	run_tests(perf_tests, RTE_DIM(perf_tests), &num_tests, &num_pass);
1864 	show_stats(num_tests, num_pass);
1865 	return tell_the_result(num_tests, num_pass);
1866 }
1867 
1868 static int
1869 test_red_all(void)
1870 {
1871 	uint32_t num_tests = 0;
1872 	uint32_t num_pass = 0;
1873 
1874 	if (test_invalid_parameters() < 0)
1875 		return -1;
1876 
1877 	run_tests(func_tests, RTE_DIM(func_tests), &num_tests, &num_pass);
1878 	run_tests(perf_tests, RTE_DIM(perf_tests), &num_tests, &num_pass);
1879 	show_stats(num_tests, num_pass);
1880 	return tell_the_result(num_tests, num_pass);
1881 }
1882 
1883 REGISTER_TEST_COMMAND(red_autotest, test_red);
1884 REGISTER_TEST_COMMAND(red_perf, test_red_perf);
1885 REGISTER_TEST_COMMAND(red_all, test_red_all);
1886