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