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