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