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