xref: /dpdk/app/test/test_pie.c (revision 2490bb897182f57de80fd924dd3ae48dda819b8c)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4 
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <stdint.h>
9 #include <unistd.h>
10 #include <inttypes.h>
11 #include <sys/time.h>
12 #include <time.h>
13 #include <math.h>
14 
15 #include "test.h"
16 
17 #include <rte_pie.h>
18 
19 #ifdef __INTEL_COMPILER
20 #pragma warning(disable:2259)       /* conversion may lose significant bits */
21 #pragma warning(disable:181)        /* Arg incompatible with format string */
22 #endif
23 
24 /**< structures for testing rte_pie performance and function */
25 struct test_rte_pie_config {        /**< Test structure for RTE_PIE config */
26 	struct rte_pie_config *pconfig; /**< RTE_PIE configuration parameters */
27 	uint8_t num_cfg;                /**< Number of RTE_PIE configs to test */
28 	uint16_t qdelay_ref;            /**< Latency Target (milliseconds) */
29 	uint16_t *dp_update_interval;   /**< Update interval for drop probability
30 					  * (milliseconds)
31 					  */
32 	uint16_t *max_burst;            /**< Max Burst Allowance (milliseconds) */
33 	uint16_t tailq_th;              /**< Tailq drop threshold (packet counts) */
34 };
35 
36 struct test_queue {                 /**< Test structure for RTE_PIE Queues */
37 	struct rte_pie *pdata_in;       /**< RTE_PIE runtime data input */
38 	struct rte_pie *pdata_out;		/**< RTE_PIE runtime data output*/
39 	uint32_t num_queues;            /**< Number of RTE_PIE queues to test */
40 	uint32_t *qlen;                 /**< Queue size */
41 	uint32_t q_ramp_up;             /**< Num of enqueues to ramp up the queue */
42 	double drop_tolerance;          /**< Drop tolerance of packets not enqueued */
43 };
44 
45 struct test_var {                   /**< Test variables used for testing RTE_PIE */
46 	uint32_t num_iterations;        /**< Number of test iterations */
47 	uint32_t num_ops;               /**< Number of test operations */
48 	uint64_t clk_freq;              /**< CPU clock frequency */
49 	uint32_t *dropped;              /**< Test operations dropped */
50 	uint32_t *enqueued;             /**< Test operations enqueued */
51 	uint32_t *dequeued;             /**< Test operations dequeued */
52 };
53 
54 struct test_config {                /**< Primary test structure for RTE_PIE */
55 	const char *ifname;             /**< Interface name */
56 	const char *msg;                /**< Test message for display */
57 	const char *htxt;               /**< Header txt display for result output */
58 	struct test_rte_pie_config *tconfig; /**< Test structure for RTE_PIE config */
59 	struct test_queue *tqueue;      /**< Test structure for RTE_PIE Queues */
60 	struct test_var *tvar;          /**< Test variables used for testing RTE_PIE */
61 	uint32_t *tlevel;               /**< Queue levels */
62 };
63 
64 enum test_result {
65 	FAIL = 0,
66 	PASS
67 };
68 
69 /**< Test structure to define tests to run */
70 struct tests {
71 	struct test_config *testcfg;
72 	enum test_result (*testfn)(struct test_config *cfg);
73 };
74 
75 struct rdtsc_prof {
76 	uint64_t clk_start;
77 	uint64_t clk_min;               /**< min clocks */
78 	uint64_t clk_max;               /**< max clocks */
79 	uint64_t clk_avgc;              /**< count to calc average */
80 	double clk_avg;                 /**< cumulative sum to calc average */
81 	const char *name;
82 };
83 
84 static const uint64_t port_speed_bytes = (10ULL*1000ULL*1000ULL*1000ULL)/8ULL;
85 static double inv_cycles_per_byte;
86 
87 static void init_port_ts(uint64_t cpu_clock)
88 {
89 	double cycles_per_byte = (double)(cpu_clock) / (double)(port_speed_bytes);
90 	inv_cycles_per_byte = 1.0 / cycles_per_byte;
91 }
92 
93 static uint64_t get_port_ts(void)
94 {
95 	return (uint64_t)((double)rte_rdtsc() * inv_cycles_per_byte);
96 }
97 
98 static void rdtsc_prof_init(struct rdtsc_prof *p, const char *name)
99 {
100 	p->clk_min = (uint64_t)(-1LL);
101 	p->clk_max = 0;
102 	p->clk_avg = 0;
103 	p->clk_avgc = 0;
104 	p->name = name;
105 }
106 
107 static inline void rdtsc_prof_start(struct rdtsc_prof *p)
108 {
109 	p->clk_start = rte_rdtsc_precise();
110 }
111 
112 static inline void rdtsc_prof_end(struct rdtsc_prof *p)
113 {
114 	uint64_t clk_start = rte_rdtsc() - p->clk_start;
115 
116 	p->clk_avgc++;
117 	p->clk_avg += (double) clk_start;
118 
119 	if (clk_start > p->clk_max)
120 		p->clk_max = clk_start;
121 	if (clk_start < p->clk_min)
122 		p->clk_min = clk_start;
123 }
124 
125 static void rdtsc_prof_print(struct rdtsc_prof *p)
126 {
127 	if (p->clk_avgc > 0) {
128 		printf("RDTSC stats for %s: n=%" PRIu64 ", min=%" PRIu64
129 						",max=%" PRIu64 ", avg=%.1f\n",
130 			p->name,
131 			p->clk_avgc,
132 			p->clk_min,
133 			p->clk_max,
134 			(p->clk_avg / ((double) p->clk_avgc)));
135 	}
136 }
137 
138 static uint16_t rte_pie_get_active(const struct rte_pie_config *pie_cfg,
139 				    struct rte_pie *pie)
140 {
141     /**< Flag for activating/deactivating pie */
142 	RTE_SET_USED(pie_cfg);
143 	return pie->active;
144 }
145 
146 static void rte_pie_set_active(const struct rte_pie_config *pie_cfg,
147 					struct rte_pie *pie,
148 					uint16_t active)
149 {
150     /**< Flag for activating/deactivating pie */
151 	RTE_SET_USED(pie_cfg);
152 	pie->active = active;
153 }
154 
155 /**
156  * Read the drop probability
157  */
158 static double rte_pie_get_drop_prob(const struct rte_pie_config *pie_cfg,
159 				    struct rte_pie *pie)
160 {
161     /**< Current packet drop probability */
162 	RTE_SET_USED(pie_cfg);
163 	return pie->drop_prob;
164 }
165 
166 static double rte_pie_get_avg_dq_time(const struct rte_pie_config *pie_cfg,
167 				    struct rte_pie *pie)
168 {
169     /**< Current packet drop probability */
170 	RTE_SET_USED(pie_cfg);
171 	return pie->avg_dq_time;
172 }
173 
174 static double calc_drop_rate(uint32_t enqueued, uint32_t dropped)
175 {
176 	return (double)dropped / ((double)enqueued + (double)dropped);
177 }
178 
179 /**
180  *  check if drop rate matches drop probability within tolerance
181  */
182 static int check_drop_rate(double *diff, double drop_rate, double drop_prob,
183 							double tolerance)
184 {
185 	double abs_diff = 0.0;
186 	int ret = 1;
187 
188 	abs_diff = fabs(drop_rate - drop_prob);
189 	if ((int)abs_diff == 0) {
190 		*diff = 0.0;
191 	} else {
192 		*diff = (abs_diff / drop_prob) * 100.0;
193 		if (*diff > tolerance)
194 			ret = 0;
195 	}
196 	return ret;
197 }
198 
199 /**
200  * initialize the test rte_pie config
201  */
202 static enum test_result
203 test_rte_pie_init(struct test_config *tcfg)
204 {
205 	unsigned int i = 0;
206 
207 	tcfg->tvar->clk_freq = rte_get_timer_hz();
208 	init_port_ts(tcfg->tvar->clk_freq);
209 
210 	for (i = 0; i < tcfg->tconfig->num_cfg; i++) {
211 		if (rte_pie_config_init(&tcfg->tconfig->pconfig[i],
212 					(uint16_t)tcfg->tconfig->qdelay_ref,
213 					(uint16_t)tcfg->tconfig->dp_update_interval[i],
214 					(uint16_t)tcfg->tconfig->max_burst[i],
215 					(uint16_t)tcfg->tconfig->tailq_th) != 0) {
216 			return FAIL;
217 		}
218 	}
219 
220 	*tcfg->tqueue->qlen = 0;
221 	*tcfg->tvar->dropped = 0;
222 	*tcfg->tvar->enqueued = 0;
223 
224 	return PASS;
225 }
226 
227 /**
228  * enqueue until actual queue size reaches target level
229  */
230 static int
231 increase_qsize(struct rte_pie_config *pie_cfg,
232 				struct rte_pie *pie,
233 				uint32_t *qlen,
234 				uint32_t pkt_len,
235 				uint32_t attempts)
236 {
237 	uint32_t i = 0;
238 
239 		for (i = 0; i < attempts; i++) {
240 			int ret = 0;
241 
242 			/**
243 			 * enqueue
244 			 */
245 			ret = rte_pie_enqueue(pie_cfg, pie, *qlen, pkt_len, get_port_ts());
246 			/**
247 			 * check if target actual queue size has been reached
248 			 */
249 			if (ret == 0)
250 				return 0;
251 		}
252 		/**
253 		 * no success
254 		 */
255 		return -1;
256 }
257 
258 /**
259  * functional test enqueue/dequeue packets
260  */
261 static void
262 enqueue_dequeue_func(struct rte_pie_config *pie_cfg,
263 					struct rte_pie *pie,
264 					uint32_t *qlen,
265 					uint32_t num_ops,
266 					uint32_t *enqueued,
267 					uint32_t *dropped)
268 {
269 	uint32_t i = 0;
270 
271 	for (i = 0; i < num_ops; i++) {
272 		int ret = 0;
273 
274 		/**
275 		 * enqueue
276 		 */
277 		ret = rte_pie_enqueue(pie_cfg, pie, *qlen, sizeof(uint32_t),
278 							get_port_ts());
279 		if (ret == 0)
280 			(*enqueued)++;
281 		else
282 			(*dropped)++;
283 	}
284 }
285 
286 /**
287  * setup default values for the Functional test structures
288  */
289 static struct rte_pie_config ft_wpconfig[1];
290 static struct rte_pie ft_rtdata[1];
291 static uint32_t  ft_q[] = {0};
292 static uint32_t  ft_dropped[] = {0};
293 static uint32_t  ft_enqueued[] = {0};
294 static uint16_t ft_max_burst[] = {64};
295 static uint16_t ft_dp_update_interval[] = {150};
296 
297 static struct test_rte_pie_config ft_tconfig =  {
298 	.pconfig = ft_wpconfig,
299 	.num_cfg = RTE_DIM(ft_wpconfig),
300 	.qdelay_ref = 15,
301 	.dp_update_interval = ft_dp_update_interval,
302 	.max_burst = ft_max_burst,
303 	.tailq_th = 15,
304 };
305 
306 static struct test_queue ft_tqueue = {
307 	.pdata_in = ft_rtdata,
308 	.num_queues = RTE_DIM(ft_rtdata),
309 	.qlen = ft_q,
310 	.q_ramp_up = 10,
311 	.drop_tolerance = 0,
312 };
313 
314 static struct test_var ft_tvar = {
315 	.num_iterations = 0,
316 	.num_ops = 10000,
317 	.clk_freq = 0,
318 	.dropped = ft_dropped,
319 	.enqueued = ft_enqueued,
320 };
321 
322 /**
323  * Test F1: functional test 1
324  */
325 static uint32_t ft_tlevels[] =  {6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66,
326 				72, 78, 84, 90, 96, 102, 108, 114, 120, 126, 132, 138, 144};
327 
328 static struct test_config func_test_config1 = {
329 	.ifname = "functional test interface",
330 	.msg = "functional test : use one pie configuration\n\n",
331 	.htxt = "                "
332 	"drop probability "
333 	"enqueued    "
334 	"dropped     "
335 	"drop prob % "
336 	"drop rate % "
337 	"diff %      "
338 	"tolerance % "
339 	"active  "
340 	"\n",
341 	.tconfig = &ft_tconfig,
342 	.tqueue = &ft_tqueue,
343 	.tvar = &ft_tvar,
344 	.tlevel = ft_tlevels,
345 };
346 
347 static enum test_result func_test1(struct test_config *tcfg)
348 {
349 	enum test_result result = PASS;
350 	uint32_t i = 0;
351 
352 	printf("%s", tcfg->msg);
353 
354 	if (test_rte_pie_init(tcfg) != PASS) {
355 		result = FAIL;
356 		goto out;
357 	}
358 
359 	printf("%s", tcfg->htxt);
360 
361 	/**
362 	 * reset rte_pie run-time data
363 	 */
364 	rte_pie_rt_data_init(tcfg->tqueue->pdata_in);
365 	rte_pie_set_active(NULL, tcfg->tqueue->pdata_in, 1);
366 	*tcfg->tvar->enqueued = 0;
367 	*tcfg->tvar->dropped = 0;
368 
369 	if (increase_qsize(&tcfg->tconfig->pconfig[i],
370 				tcfg->tqueue->pdata_in,
371 				tcfg->tqueue->qlen,
372 				tcfg->tlevel[i],
373 				tcfg->tqueue->q_ramp_up) != 0) {
374 		fprintf(stderr, "Fail: increase qsize\n");
375 		result = FAIL;
376 		goto out;
377 	}
378 
379 	for (i = 0; i < RTE_DIM(ft_tlevels); i++) {
380 		const char *label = NULL;
381 		uint16_t prob = 0;
382 		uint16_t active = 0;
383 		double drop_rate = 1.0;
384 		double drop_prob = 0.0;
385 		double diff = 0.0;
386 
387 		enqueue_dequeue_func(&tcfg->tconfig->pconfig[i],
388 				     tcfg->tqueue->pdata_in,
389 				     tcfg->tqueue->qlen,
390 				     tcfg->tvar->num_ops,
391 				     tcfg->tvar->enqueued,
392 				     tcfg->tvar->dropped);
393 
394 		drop_rate = calc_drop_rate(*tcfg->tvar->enqueued,
395 							*tcfg->tvar->dropped);
396 		drop_prob = rte_pie_get_drop_prob(NULL, tcfg->tqueue->pdata_in);
397 
398 		if (drop_prob != 0) {
399 			fprintf(stderr, "Fail: check drop prob\n");
400 			result = FAIL;
401 		}
402 
403 		if (drop_rate != 0) {
404 			fprintf(stderr, "Fail: check drop rate\n");
405 			result = FAIL;
406 		}
407 
408 		label = "Summary           ";
409 		active = rte_pie_get_active(NULL, tcfg->tqueue->pdata_in);
410 		printf("%s%-16u%-12u%-12u%-12.4lf%-12.4lf%-12.4lf%-12.4lf%-8i\n",
411 				label, prob, *tcfg->tvar->enqueued, *tcfg->tvar->dropped,
412 				drop_prob * 100.0, drop_rate * 100.0, diff,
413 				(double)tcfg->tqueue->drop_tolerance, active);
414 	}
415 out:
416 	return result;
417 }
418 
419 /**
420  * Test F2: functional test 2
421  */
422 static uint32_t ft2_tlevel[] = {127};
423 static uint16_t ft2_max_burst[] = {1, 2, 8, 16, 32, 64, 128, 256, 512, 1024};
424 static uint16_t ft2_dp_update_interval[] = {
425 				10, 20, 50, 150, 300, 600, 900, 1200, 1500, 3000};
426 static struct rte_pie_config ft2_pconfig[10];
427 
428 static struct test_rte_pie_config ft2_tconfig =  {
429 	.pconfig = ft2_pconfig,
430 	.num_cfg = RTE_DIM(ft2_pconfig),
431 	.qdelay_ref = 15,
432 	.dp_update_interval = ft2_dp_update_interval,
433 	.max_burst = ft2_max_burst,
434 	.tailq_th = 15,
435 };
436 
437 static struct test_config func_test_config2 = {
438 	.ifname = "functional test 2 interface",
439 	.msg = "functional test 2 : use several PIE configurations,\n"
440 	"		    compare drop rate to drop probability\n\n",
441 	.htxt = "PIE config     "
442 	"avg queue size "
443 	"enqueued       "
444 	"dropped        "
445 	"drop prob %    "
446 	"drop rate %    "
447 	"diff %         "
448 	"tolerance %    "
449 	"\n",
450 	.tconfig = &ft2_tconfig,
451 	.tqueue = &ft_tqueue,
452 	.tvar = &ft_tvar,
453 	.tlevel = ft2_tlevel,
454 };
455 
456 static enum test_result func_test2(struct test_config *tcfg)
457 {
458 	enum test_result result = PASS;
459 	uint32_t i = 0;
460 
461 	printf("%s", tcfg->msg);
462 
463 	printf("%s", tcfg->htxt);
464 
465 	for (i = 0; i < tcfg->tconfig->num_cfg; i++) {
466 		uint32_t avg = 0;
467 		double drop_rate = 0.0;
468 		double drop_prob = 0.0;
469 		double diff = 0.0;
470 
471 		if (test_rte_pie_init(tcfg) != PASS) {
472 			result = FAIL;
473 			goto out;
474 		}
475 
476 		rte_pie_rt_data_init(tcfg->tqueue->pdata_in);
477 		rte_pie_set_active(NULL, tcfg->tqueue->pdata_in, 1);
478 		*tcfg->tvar->enqueued = 0;
479 		*tcfg->tvar->dropped = 0;
480 
481 		if (increase_qsize(&tcfg->tconfig->pconfig[i],
482 					tcfg->tqueue->pdata_in,
483 					tcfg->tqueue->qlen,
484 					*tcfg->tlevel,
485 					tcfg->tqueue->q_ramp_up) != 0) {
486 			result = FAIL;
487 			goto out;
488 		}
489 
490 		enqueue_dequeue_func(&tcfg->tconfig->pconfig[i],
491 				     tcfg->tqueue->pdata_in,
492 				     tcfg->tqueue->qlen,
493 				     tcfg->tvar->num_ops,
494 				     tcfg->tvar->enqueued,
495 				     tcfg->tvar->dropped);
496 
497 		avg = rte_pie_get_avg_dq_time(NULL, tcfg->tqueue->pdata_in);
498 
499 		drop_rate = calc_drop_rate(*tcfg->tvar->enqueued,
500 							*tcfg->tvar->dropped);
501 		drop_prob = rte_pie_get_drop_prob(NULL, tcfg->tqueue->pdata_in);
502 
503 		if (!check_drop_rate(&diff, drop_rate, drop_prob,
504 				 (double)tcfg->tqueue->drop_tolerance)) {
505 			fprintf(stderr, "Fail: drop rate outside tolerance\n");
506 			result = FAIL;
507 		}
508 
509 		printf("%-15u%-15u%-15u%-15u%-15.4lf%-15.4lf%-15.4lf%-15.4lf\n",
510 				i, avg, *tcfg->tvar->enqueued, *tcfg->tvar->dropped,
511 				drop_prob * 100.0, drop_rate * 100.0, diff,
512 				(double)tcfg->tqueue->drop_tolerance);
513 	}
514 out:
515 	return result;
516 }
517 
518 static uint32_t ft3_qlen[] = {100};
519 
520 static struct test_rte_pie_config ft3_tconfig =  {
521 	.pconfig = ft_wpconfig,
522 	.num_cfg = RTE_DIM(ft_wpconfig),
523 	.qdelay_ref = 15,
524 	.dp_update_interval = ft_dp_update_interval,
525 	.max_burst = ft_max_burst,
526 	.tailq_th = 15,
527 };
528 
529 static struct test_queue ft3_tqueue = {
530 	.pdata_in = ft_rtdata,
531 	.num_queues = RTE_DIM(ft_rtdata),
532 	.qlen = ft3_qlen,
533 	.q_ramp_up = 10,
534 	.drop_tolerance = 0,
535 };
536 
537 static struct test_var ft3_tvar = {
538 	.num_iterations = 0,
539 	.num_ops = 10000,
540 	.clk_freq = 0,
541 	.dropped = ft_dropped,
542 	.enqueued = ft_enqueued,
543 };
544 
545 /**
546  * Test F3: functional test 3
547  */
548 static uint32_t ft3_tlevels[] =  {64, 127, 222};
549 
550 static struct test_config func_test_config3 = {
551 	.ifname = "functional test interface",
552 	.msg = "functional test 2 : use one pie configuration\n"
553 			"using non zero qlen\n\n",
554 	.htxt = "                "
555 	"drop probability "
556 	"enqueued    "
557 	"dropped     "
558 	"drop prob % "
559 	"drop rate % "
560 	"diff %      "
561 	"tolerance % "
562 	"active  "
563 	"\n",
564 	.tconfig = &ft3_tconfig,
565 	.tqueue = &ft3_tqueue,
566 	.tvar = &ft3_tvar,
567 	.tlevel = ft3_tlevels,
568 };
569 
570 static enum test_result func_test3(struct test_config *tcfg)
571 {
572 	enum test_result result = PASS;
573 	uint32_t i = 0;
574 
575 	printf("%s", tcfg->msg);
576 
577 	if (test_rte_pie_init(tcfg) != PASS) {
578 		result = FAIL;
579 		goto out;
580 	}
581 
582 	printf("%s", tcfg->htxt);
583 
584 	/**
585 	 * reset rte_pie run-time data
586 	 */
587 	rte_pie_rt_data_init(tcfg->tqueue->pdata_in);
588 	rte_pie_set_active(NULL, tcfg->tqueue->pdata_in, 1);
589 	*tcfg->tvar->enqueued = 0;
590 	*tcfg->tvar->dropped = 0;
591 
592 	if (increase_qsize(&tcfg->tconfig->pconfig[i],
593 				tcfg->tqueue->pdata_in,
594 				tcfg->tqueue->qlen,
595 				tcfg->tlevel[i],
596 				tcfg->tqueue->q_ramp_up) != 0) {
597 		fprintf(stderr, "Fail: increase qsize\n");
598 		result = FAIL;
599 		goto out;
600 	}
601 
602 	for (i = 0; i < RTE_DIM(ft_tlevels); i++) {
603 		const char *label = NULL;
604 		uint16_t prob = 0;
605 		uint16_t active = 0;
606 		double drop_rate = 1.0;
607 		double drop_prob = 0.0;
608 		double diff = 0.0;
609 
610 		enqueue_dequeue_func(&tcfg->tconfig->pconfig[i],
611 				     tcfg->tqueue->pdata_in,
612 				     tcfg->tqueue->qlen,
613 				     tcfg->tvar->num_ops,
614 				     tcfg->tvar->enqueued,
615 				     tcfg->tvar->dropped);
616 
617 		drop_rate = calc_drop_rate(*tcfg->tvar->enqueued,
618 						*tcfg->tvar->dropped);
619 		drop_prob = rte_pie_get_drop_prob(NULL, tcfg->tqueue->pdata_in);
620 
621 		if (drop_prob != 0) {
622 			fprintf(stderr, "Fail: check drop prob\n");
623 			result = FAIL;
624 		}
625 
626 		if (drop_rate != 0) {
627 			fprintf(stderr, "Fail: check drop rate\n");
628 			result = FAIL;
629 		}
630 
631 		label = "Summary           ";
632 		active = rte_pie_get_active(NULL, tcfg->tqueue->pdata_in);
633 		printf("%s%-16u%-12u%-12u%-12.4lf%-12.4lf%-12.4lf%-12.4lf%-8i\n",
634 				label, prob, *tcfg->tvar->enqueued, *tcfg->tvar->dropped,
635 				drop_prob * 100.0, drop_rate * 100.0, diff,
636 				(double)tcfg->tqueue->drop_tolerance, active);
637 	}
638 out:
639 	return result;
640 }
641 
642 /**
643  * setup default values for the Performance test structures
644  */
645 static struct rte_pie_config pt_wrconfig[1];
646 static struct rte_pie pt_rtdata[1];
647 static struct rte_pie pt_wtdata[1];
648 static uint32_t pt_q[] = {0};
649 static uint32_t pt_dropped[] = {0};
650 static uint32_t pt_enqueued[] = {0};
651 static uint32_t pt_dequeued[] = {0};
652 static uint16_t pt_max_burst[] = {64};
653 static uint16_t pt_dp_update_interval[] = {150};
654 
655 static struct test_rte_pie_config pt_tconfig =  {
656 	.pconfig = pt_wrconfig,
657 	.num_cfg = RTE_DIM(pt_wrconfig),
658 	.qdelay_ref = 15,
659 	.dp_update_interval = pt_dp_update_interval,
660 	.max_burst = pt_max_burst,
661 	.tailq_th = 150,
662 };
663 
664 static struct test_queue pt_tqueue = {
665 	.pdata_in = pt_rtdata,
666 	.num_queues = RTE_DIM(pt_rtdata),
667 	.qlen = pt_q,
668 	.q_ramp_up = 1000000,
669 	.drop_tolerance = 0,  /* 0 percent */
670 };
671 
672 static struct test_rte_pie_config pt_tconfig2 =  {
673 	.pconfig = pt_wrconfig,
674 	.num_cfg = RTE_DIM(pt_wrconfig),
675 	.qdelay_ref = 15,
676 	.dp_update_interval = pt_dp_update_interval,
677 	.max_burst = pt_max_burst,
678 	.tailq_th = 150,
679 };
680 
681 static struct test_queue pt_tqueue2 = {
682 	.pdata_in = pt_rtdata,
683 	.pdata_out = pt_wtdata,
684 	.num_queues = RTE_DIM(pt_rtdata),
685 	.qlen = pt_q,
686 	.q_ramp_up = 1000000,
687 	.drop_tolerance = 0,  /* 0 percent */
688 };
689 
690 /**
691  * enqueue/dequeue packets
692  * aka
693  *  rte_sched_port_enqueue(port, in_mbufs, 10);
694  *	rte_sched_port_dequeue(port, out_mbufs, 10);
695  */
696 static void enqueue_dequeue_perf(struct rte_pie_config *pie_cfg,
697 				 struct rte_pie *pie_in,
698 				 struct rte_pie *pie_out,
699 				 uint32_t *qlen,
700 				 uint32_t num_ops,
701 				 uint32_t *enqueued,
702 				 uint32_t *dropped,
703 				 uint32_t *dequeued,
704 				 struct rdtsc_prof *prof)
705 {
706 	uint32_t i = 0;
707 
708 	if (pie_cfg == NULL) {
709 		printf("%s: Error: PIE configuration cannot be empty.\n", __func__);
710 		return;
711 	}
712 
713 	if (pie_in == NULL) {
714 		printf("%s: Error: PIE enqueue data cannot be empty.\n", __func__);
715 		return;
716 	}
717 
718 	for (i = 0; i < num_ops; i++) {
719 		uint64_t ts = 0;
720 		int ret = 0;
721 
722 		/**
723 		 * enqueue
724 		 */
725 		ts = get_port_ts();
726 		rdtsc_prof_start(prof);
727 		ret = rte_pie_enqueue(pie_cfg, pie_in, *qlen,
728 								1000*sizeof(uint32_t), ts);
729 		rdtsc_prof_end(prof);
730 
731 		if (ret == 0)
732 			(*enqueued)++;
733 		else
734 			(*dropped)++;
735 
736 		if (pie_out != NULL) {
737 			ts = get_port_ts();
738 			rdtsc_prof_start(prof);
739 			rte_pie_dequeue(pie_out, 1000*sizeof(uint32_t), ts);
740 			rdtsc_prof_end(prof);
741 
742 			(*dequeued)++;
743 		}
744 	}
745 }
746 
747 /**
748  * Setup test structures for tests P1
749  * performance tests 1
750  */
751 static uint32_t pt1_tlevel[] = {80};
752 
753 static struct test_var perf1_tvar = {
754 	.num_iterations = 0,
755 	.num_ops = 30000,
756 	.clk_freq = 0,
757 	.dropped = pt_dropped,
758 	.enqueued = pt_enqueued
759 };
760 
761 static struct test_config perf_test_config = {
762 	.ifname = "performance test 1 interface",
763 	.msg = "performance test 1 : use one PIE configuration,\n"
764 	"		     measure enqueue performance\n\n",
765 	.tconfig = &pt_tconfig,
766 	.tqueue = &pt_tqueue,
767 	.tvar = &perf1_tvar,
768 	.tlevel = pt1_tlevel,
769 };
770 
771 /**
772  * Performance test function to measure enqueue performance.
773  *
774  */
775 static enum test_result perf_test(struct test_config *tcfg)
776 {
777 	enum test_result result = PASS;
778 	struct rdtsc_prof prof = {0, 0, 0, 0, 0.0, NULL};
779 	uint32_t total = 0;
780 
781 	printf("%s", tcfg->msg);
782 
783 	rdtsc_prof_init(&prof, "enqueue");
784 
785 	if (test_rte_pie_init(tcfg) != PASS) {
786 		result = FAIL;
787 		goto out;
788 	}
789 
790 	/**
791 	 * initialize the rte_pie run time data structure
792 	 */
793 	rte_pie_rt_data_init(tcfg->tqueue->pdata_in);
794 	rte_pie_set_active(NULL, tcfg->tqueue->pdata_in, 1);
795 	*tcfg->tvar->enqueued = 0;
796 	*tcfg->tvar->dropped = 0;
797 
798 	enqueue_dequeue_perf(tcfg->tconfig->pconfig,
799 			     tcfg->tqueue->pdata_in,
800 				 NULL,
801 			     tcfg->tqueue->qlen,
802 			     tcfg->tvar->num_ops,
803 			     tcfg->tvar->enqueued,
804 			     tcfg->tvar->dropped,
805 				 tcfg->tvar->dequeued,
806 			     &prof);
807 
808 	total = *tcfg->tvar->enqueued + *tcfg->tvar->dropped;
809 
810 	printf("\ntotal: %u, enqueued: %u (%.2lf%%), dropped: %u (%.2lf%%)\n",
811 			total, *tcfg->tvar->enqueued,
812 			((double)(*tcfg->tvar->enqueued) / (double)total) * 100.0,
813 			*tcfg->tvar->dropped,
814 			((double)(*tcfg->tvar->dropped) / (double)total) * 100.0);
815 
816 	rdtsc_prof_print(&prof);
817 out:
818 	return result;
819 }
820 
821 
822 
823 /**
824  * Setup test structures for tests P2
825  * performance tests 2
826  */
827 static uint32_t pt2_tlevel[] = {80};
828 
829 static struct test_var perf2_tvar = {
830 	.num_iterations = 0,
831 	.num_ops = 30000,
832 	.clk_freq = 0,
833 	.dropped = pt_dropped,
834 	.enqueued = pt_enqueued,
835 	.dequeued = pt_dequeued
836 };
837 
838 static struct test_config perf_test_config2 = {
839 	.ifname = "performance test 2 interface",
840 	.msg = "performance test 2 : use one PIE configuration,\n"
841 	"		     measure enqueue & dequeue performance\n\n",
842 	.tconfig = &pt_tconfig2,
843 	.tqueue = &pt_tqueue2,
844 	.tvar = &perf2_tvar,
845 	.tlevel = pt2_tlevel,
846 };
847 
848 /**
849  * Performance test function to measure enqueue & dequeue performance.
850  *
851  */
852 static enum test_result perf_test2(struct test_config *tcfg)
853 {
854 	enum test_result result = PASS;
855 	struct rdtsc_prof prof = {0, 0, 0, 0, 0.0, NULL};
856 	uint32_t total = 0;
857 
858 	printf("%s", tcfg->msg);
859 
860 	rdtsc_prof_init(&prof, "enqueue");
861 
862 	if (test_rte_pie_init(tcfg) != PASS) {
863 		result = FAIL;
864 		goto out;
865 	}
866 
867 	/**
868 	 * initialize the rte_pie run time data structure
869 	 */
870 	rte_pie_rt_data_init(tcfg->tqueue->pdata_in);
871 	rte_pie_set_active(NULL, tcfg->tqueue->pdata_in, 1);
872 	*tcfg->tvar->enqueued = 0;
873 	*tcfg->tvar->dequeued = 0;
874 	*tcfg->tvar->dropped = 0;
875 
876 	enqueue_dequeue_perf(tcfg->tconfig->pconfig,
877 				 tcfg->tqueue->pdata_in,
878 				 tcfg->tqueue->pdata_out,
879 				 tcfg->tqueue->qlen,
880 				 tcfg->tvar->num_ops,
881 				 tcfg->tvar->enqueued,
882 				 tcfg->tvar->dropped,
883 				 tcfg->tvar->dequeued,
884 				 &prof);
885 
886 	total = *tcfg->tvar->enqueued + *tcfg->tvar->dropped;
887 
888 	printf("\ntotal: %u, dequeued: %u (%.2lf%%), dropped: %u (%.2lf%%)\n",
889 			total, *tcfg->tvar->dequeued,
890 			((double)(*tcfg->tvar->dequeued) / (double)total) * 100.0,
891 			*tcfg->tvar->dropped,
892 			((double)(*tcfg->tvar->dropped) / (double)total) * 100.0);
893 
894 	rdtsc_prof_print(&prof);
895 out:
896 	return result;
897 }
898 
899 /**
900  * define the functional tests to be executed fast
901  */
902 struct tests func_pie_tests_quick[] = {
903 	{ &func_test_config1, func_test1 },
904 	{ &func_test_config2, func_test2 },
905 };
906 
907 /**
908  * define the functional and performance tests to be executed
909  */
910 struct tests func_pie_tests[] = {
911 	{ &func_test_config1, func_test1 },
912 	{ &func_test_config2, func_test2 },
913 	{ &func_test_config3, func_test3 },
914 };
915 
916 struct tests perf_pie_tests[] = {
917 	{ &perf_test_config, perf_test },
918 	{ &perf_test_config2, perf_test2 },
919 };
920 
921 /**
922  * function to execute the required pie tests
923  */
924 static void run_tests(struct tests *test_type, uint32_t test_count,
925 						uint32_t *num_tests, uint32_t *num_pass)
926 {
927 	enum test_result result = PASS;
928 	uint32_t i = 0;
929 	static const char *bar_str = "-------------------------------------"
930 						"-------------------------------------------";
931 	static const char *bar_pass_str = "-------------------------------------"
932 						"<pass>-------------------------------------";
933 	static const char *bar_fail_str = "-------------------------------------"
934 						"<fail>-------------------------------------";
935 
936 	for (i = 0; i < test_count; i++) {
937 		printf("\n%s\n", bar_str);
938 		result = test_type[i].testfn(test_type[i].testcfg);
939 		(*num_tests)++;
940 		if (result == PASS) {
941 			(*num_pass)++;
942 				printf("%s\n", bar_pass_str);
943 		} else {
944 			printf("%s\n", bar_fail_str);
945 		}
946 	}
947 }
948 
949 /**
950  * check if functions accept invalid parameters
951  *
952  * First, all functions will be called without initialized PIE
953  * Then, all of them will be called with NULL/invalid parameters
954  *
955  * Some functions are not tested as they are performance-critical and thus
956  * don't do any parameter checking.
957  */
958 static int
959 test_invalid_parameters(void)
960 {
961 	struct rte_pie_config config;
962 	static const char *shf_str = "rte_pie_config_init should have failed!";
963 	static const char *shf_rt_str = "rte_pie_rt_data_init should have failed!";
964 
965 	/* NULL config */
966 	if (rte_pie_rt_data_init(NULL) == 0) {
967 		printf("%i: %s\n", __LINE__, shf_rt_str);
968 		return -1;
969 	}
970 
971 	/* NULL config */
972 	if (rte_pie_config_init(NULL, 0, 0, 0, 0) == 0) {
973 		printf("%i%s\n", __LINE__, shf_str);
974 		return -1;
975 	}
976 
977 	/* qdelay_ref <= 0 */
978 	if (rte_pie_config_init(&config, 0, 1, 1, 1) == 0) {
979 		printf("%i%s\n", __LINE__, shf_str);
980 		return -1;
981 	}
982 
983 	/* dp_update_interval <= 0 */
984 	if (rte_pie_config_init(&config, 1, 0, 1, 1) == 0) {
985 		printf("%i%s\n", __LINE__, shf_str);
986 		return -1;
987 	}
988 
989 	/* max_burst <= 0 */
990 	if (rte_pie_config_init(&config, 1, 1, 0, 1) == 0) {
991 		printf("%i%s\n", __LINE__, shf_str);
992 		return -1;
993 	}
994 
995 	/* tailq_th <= 0 */
996 	if (rte_pie_config_init(&config, 1, 1, 1, 0) == 0) {
997 		printf("%i%s\n", __LINE__, shf_str);
998 		return -1;
999 	}
1000 
1001 	RTE_SET_USED(config);
1002 
1003 	return 0;
1004 }
1005 
1006 static void
1007 show_stats(const uint32_t num_tests, const uint32_t num_pass)
1008 {
1009 	if (num_pass == num_tests)
1010 		printf("[total: %u, pass: %u]\n", num_tests, num_pass);
1011 	else
1012 		printf("[total: %u, pass: %u, fail: %u]\n", num_tests, num_pass,
1013 		       num_tests - num_pass);
1014 }
1015 
1016 static int
1017 tell_the_result(const uint32_t num_tests, const uint32_t num_pass)
1018 {
1019 	return (num_pass == num_tests) ? 0 : 1;
1020 }
1021 
1022 static int
1023 test_pie(void)
1024 {
1025 	uint32_t num_tests = 0;
1026 	uint32_t num_pass = 0;
1027 
1028 	if (test_invalid_parameters() < 0)
1029 		return -1;
1030 
1031 	run_tests(func_pie_tests_quick, RTE_DIM(func_pie_tests_quick),
1032 		  &num_tests, &num_pass);
1033 	show_stats(num_tests, num_pass);
1034 	return tell_the_result(num_tests, num_pass);
1035 }
1036 
1037 static int
1038 test_pie_perf(void)
1039 {
1040 	uint32_t num_tests = 0;
1041 	uint32_t num_pass = 0;
1042 
1043 	run_tests(perf_pie_tests, RTE_DIM(perf_pie_tests), &num_tests, &num_pass);
1044 	show_stats(num_tests, num_pass);
1045 	return tell_the_result(num_tests, num_pass);
1046 }
1047 
1048 static int
1049 test_pie_all(void)
1050 {
1051 	uint32_t num_tests = 0;
1052 	uint32_t num_pass = 0;
1053 
1054 	if (test_invalid_parameters() < 0)
1055 		return -1;
1056 
1057 	run_tests(func_pie_tests, RTE_DIM(func_pie_tests), &num_tests, &num_pass);
1058 	run_tests(perf_pie_tests, RTE_DIM(perf_pie_tests), &num_tests, &num_pass);
1059 	show_stats(num_tests, num_pass);
1060 	return tell_the_result(num_tests, num_pass);
1061 }
1062 
1063 REGISTER_TEST_COMMAND(pie_autotest, test_pie);
1064 REGISTER_TEST_COMMAND(pie_perf, test_pie_perf);
1065 REGISTER_TEST_COMMAND(pie_all, test_pie_all);
1066