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