xref: /dpdk/app/test-bbdev/test_bbdev_perf.c (revision 7bd6f76ee678ec6aa81cb53562f852a43e842718)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2017 Intel Corporation
3  */
4 
5 #include <stdio.h>
6 #include <inttypes.h>
7 #include <math.h>
8 
9 #include <rte_eal.h>
10 #include <rte_common.h>
11 #include <rte_dev.h>
12 #include <rte_launch.h>
13 #include <rte_bbdev.h>
14 #include <rte_cycles.h>
15 #include <rte_lcore.h>
16 #include <rte_malloc.h>
17 #include <rte_random.h>
18 #include <rte_hexdump.h>
19 
20 #include "main.h"
21 #include "test_bbdev_vector.h"
22 
23 #define GET_SOCKET(socket_id) (((socket_id) == SOCKET_ID_ANY) ? 0 : (socket_id))
24 
25 #define MAX_QUEUES RTE_MAX_LCORE
26 
27 #define OPS_CACHE_SIZE 256U
28 #define OPS_POOL_SIZE_MIN 511U /* 0.5K per queue */
29 
30 #define SYNC_WAIT 0
31 #define SYNC_START 1
32 
33 #define INVALID_QUEUE_ID -1
34 
35 static struct test_bbdev_vector test_vector;
36 
37 /* Switch between PMD and Interrupt for throughput TC */
38 static bool intr_enabled;
39 
40 /* Represents tested active devices */
41 static struct active_device {
42 	const char *driver_name;
43 	uint8_t dev_id;
44 	uint16_t supported_ops;
45 	uint16_t queue_ids[MAX_QUEUES];
46 	uint16_t nb_queues;
47 	struct rte_mempool *ops_mempool;
48 	struct rte_mempool *in_mbuf_pool;
49 	struct rte_mempool *hard_out_mbuf_pool;
50 	struct rte_mempool *soft_out_mbuf_pool;
51 } active_devs[RTE_BBDEV_MAX_DEVS];
52 
53 static uint8_t nb_active_devs;
54 
55 /* Data buffers used by BBDEV ops */
56 struct test_buffers {
57 	struct rte_bbdev_op_data *inputs;
58 	struct rte_bbdev_op_data *hard_outputs;
59 	struct rte_bbdev_op_data *soft_outputs;
60 };
61 
62 /* Operation parameters specific for given test case */
63 struct test_op_params {
64 	struct rte_mempool *mp;
65 	struct rte_bbdev_dec_op *ref_dec_op;
66 	struct rte_bbdev_enc_op *ref_enc_op;
67 	uint16_t burst_sz;
68 	uint16_t num_to_process;
69 	uint16_t num_lcores;
70 	int vector_mask;
71 	rte_atomic16_t sync;
72 	struct test_buffers q_bufs[RTE_MAX_NUMA_NODES][MAX_QUEUES];
73 };
74 
75 /* Contains per lcore params */
76 struct thread_params {
77 	uint8_t dev_id;
78 	uint16_t queue_id;
79 	uint64_t start_time;
80 	double mops;
81 	double mbps;
82 	rte_atomic16_t nb_dequeued;
83 	rte_atomic16_t processing_status;
84 	struct test_op_params *op_params;
85 };
86 
87 #ifdef RTE_BBDEV_OFFLOAD_COST
88 /* Stores time statistics */
89 struct test_time_stats {
90 	/* Stores software enqueue total working time */
91 	uint64_t enq_sw_tot_time;
92 	/* Stores minimum value of software enqueue working time */
93 	uint64_t enq_sw_min_time;
94 	/* Stores maximum value of software enqueue working time */
95 	uint64_t enq_sw_max_time;
96 	/* Stores turbo enqueue total working time */
97 	uint64_t enq_tur_tot_time;
98 	/* Stores minimum value of turbo enqueue working time */
99 	uint64_t enq_tur_min_time;
100 	/* Stores maximum value of turbo enqueue working time */
101 	uint64_t enq_tur_max_time;
102 	/* Stores dequeue total working time */
103 	uint64_t deq_tot_time;
104 	/* Stores minimum value of dequeue working time */
105 	uint64_t deq_min_time;
106 	/* Stores maximum value of dequeue working time */
107 	uint64_t deq_max_time;
108 };
109 #endif
110 
111 typedef int (test_case_function)(struct active_device *ad,
112 		struct test_op_params *op_params);
113 
114 static inline void
115 set_avail_op(struct active_device *ad, enum rte_bbdev_op_type op_type)
116 {
117 	ad->supported_ops |= (1 << op_type);
118 }
119 
120 static inline bool
121 is_avail_op(struct active_device *ad, enum rte_bbdev_op_type op_type)
122 {
123 	return ad->supported_ops & (1 << op_type);
124 }
125 
126 static inline bool
127 flags_match(uint32_t flags_req, uint32_t flags_present)
128 {
129 	return (flags_req & flags_present) == flags_req;
130 }
131 
132 static void
133 clear_soft_out_cap(uint32_t *op_flags)
134 {
135 	*op_flags &= ~RTE_BBDEV_TURBO_SOFT_OUTPUT;
136 	*op_flags &= ~RTE_BBDEV_TURBO_POS_LLR_1_BIT_SOFT_OUT;
137 	*op_flags &= ~RTE_BBDEV_TURBO_NEG_LLR_1_BIT_SOFT_OUT;
138 }
139 
140 static int
141 check_dev_cap(const struct rte_bbdev_info *dev_info)
142 {
143 	unsigned int i;
144 	unsigned int nb_inputs, nb_soft_outputs, nb_hard_outputs;
145 	const struct rte_bbdev_op_cap *op_cap = dev_info->drv.capabilities;
146 
147 	nb_inputs = test_vector.entries[DATA_INPUT].nb_segments;
148 	nb_soft_outputs = test_vector.entries[DATA_SOFT_OUTPUT].nb_segments;
149 	nb_hard_outputs = test_vector.entries[DATA_HARD_OUTPUT].nb_segments;
150 
151 	for (i = 0; op_cap->type != RTE_BBDEV_OP_NONE; ++i, ++op_cap) {
152 		if (op_cap->type != test_vector.op_type)
153 			continue;
154 
155 		if (op_cap->type == RTE_BBDEV_OP_TURBO_DEC) {
156 			const struct rte_bbdev_op_cap_turbo_dec *cap =
157 					&op_cap->cap.turbo_dec;
158 			/* Ignore lack of soft output capability, just skip
159 			 * checking if soft output is valid.
160 			 */
161 			if ((test_vector.turbo_dec.op_flags &
162 					RTE_BBDEV_TURBO_SOFT_OUTPUT) &&
163 					!(cap->capability_flags &
164 					RTE_BBDEV_TURBO_SOFT_OUTPUT)) {
165 				printf(
166 					"WARNING: Device \"%s\" does not support soft output - soft output flags will be ignored.\n",
167 					dev_info->dev_name);
168 				clear_soft_out_cap(
169 					&test_vector.turbo_dec.op_flags);
170 			}
171 
172 			if (!flags_match(test_vector.turbo_dec.op_flags,
173 					cap->capability_flags))
174 				return TEST_FAILED;
175 			if (nb_inputs > cap->num_buffers_src) {
176 				printf("Too many inputs defined: %u, max: %u\n",
177 					nb_inputs, cap->num_buffers_src);
178 				return TEST_FAILED;
179 			}
180 			if (nb_soft_outputs > cap->num_buffers_soft_out &&
181 					(test_vector.turbo_dec.op_flags &
182 					RTE_BBDEV_TURBO_SOFT_OUTPUT)) {
183 				printf(
184 					"Too many soft outputs defined: %u, max: %u\n",
185 						nb_soft_outputs,
186 						cap->num_buffers_soft_out);
187 				return TEST_FAILED;
188 			}
189 			if (nb_hard_outputs > cap->num_buffers_hard_out) {
190 				printf(
191 					"Too many hard outputs defined: %u, max: %u\n",
192 						nb_hard_outputs,
193 						cap->num_buffers_hard_out);
194 				return TEST_FAILED;
195 			}
196 			if (intr_enabled && !(cap->capability_flags &
197 					RTE_BBDEV_TURBO_DEC_INTERRUPTS)) {
198 				printf(
199 					"Dequeue interrupts are not supported!\n");
200 				return TEST_FAILED;
201 			}
202 
203 			return TEST_SUCCESS;
204 		} else if (op_cap->type == RTE_BBDEV_OP_TURBO_ENC) {
205 			const struct rte_bbdev_op_cap_turbo_enc *cap =
206 					&op_cap->cap.turbo_enc;
207 
208 			if (!flags_match(test_vector.turbo_enc.op_flags,
209 					cap->capability_flags))
210 				return TEST_FAILED;
211 			if (nb_inputs > cap->num_buffers_src) {
212 				printf("Too many inputs defined: %u, max: %u\n",
213 					nb_inputs, cap->num_buffers_src);
214 				return TEST_FAILED;
215 			}
216 			if (nb_hard_outputs > cap->num_buffers_dst) {
217 				printf(
218 					"Too many hard outputs defined: %u, max: %u\n",
219 					nb_hard_outputs, cap->num_buffers_src);
220 				return TEST_FAILED;
221 			}
222 			if (intr_enabled && !(cap->capability_flags &
223 					RTE_BBDEV_TURBO_ENC_INTERRUPTS)) {
224 				printf(
225 					"Dequeue interrupts are not supported!\n");
226 				return TEST_FAILED;
227 			}
228 
229 			return TEST_SUCCESS;
230 		}
231 	}
232 
233 	if ((i == 0) && (test_vector.op_type == RTE_BBDEV_OP_NONE))
234 		return TEST_SUCCESS; /* Special case for NULL device */
235 
236 	return TEST_FAILED;
237 }
238 
239 /* calculates optimal mempool size not smaller than the val */
240 static unsigned int
241 optimal_mempool_size(unsigned int val)
242 {
243 	return rte_align32pow2(val + 1) - 1;
244 }
245 
246 /* allocates mbuf mempool for inputs and outputs */
247 static struct rte_mempool *
248 create_mbuf_pool(struct op_data_entries *entries, uint8_t dev_id,
249 		int socket_id, unsigned int mbuf_pool_size,
250 		const char *op_type_str)
251 {
252 	unsigned int i;
253 	uint32_t max_seg_sz = 0;
254 	char pool_name[RTE_MEMPOOL_NAMESIZE];
255 
256 	/* find max input segment size */
257 	for (i = 0; i < entries->nb_segments; ++i)
258 		if (entries->segments[i].length > max_seg_sz)
259 			max_seg_sz = entries->segments[i].length;
260 
261 	snprintf(pool_name, sizeof(pool_name), "%s_pool_%u", op_type_str,
262 			dev_id);
263 	return rte_pktmbuf_pool_create(pool_name, mbuf_pool_size, 0, 0,
264 			RTE_MAX(max_seg_sz + RTE_PKTMBUF_HEADROOM,
265 			(unsigned int)RTE_MBUF_DEFAULT_BUF_SIZE), socket_id);
266 }
267 
268 static int
269 create_mempools(struct active_device *ad, int socket_id,
270 		enum rte_bbdev_op_type org_op_type, uint16_t num_ops)
271 {
272 	struct rte_mempool *mp;
273 	unsigned int ops_pool_size, mbuf_pool_size = 0;
274 	char pool_name[RTE_MEMPOOL_NAMESIZE];
275 	const char *op_type_str;
276 	enum rte_bbdev_op_type op_type = org_op_type;
277 
278 	struct op_data_entries *in = &test_vector.entries[DATA_INPUT];
279 	struct op_data_entries *hard_out =
280 			&test_vector.entries[DATA_HARD_OUTPUT];
281 	struct op_data_entries *soft_out =
282 			&test_vector.entries[DATA_SOFT_OUTPUT];
283 
284 	/* allocate ops mempool */
285 	ops_pool_size = optimal_mempool_size(RTE_MAX(
286 			/* Ops used plus 1 reference op */
287 			RTE_MAX((unsigned int)(ad->nb_queues * num_ops + 1),
288 			/* Minimal cache size plus 1 reference op */
289 			(unsigned int)(1.5 * rte_lcore_count() *
290 					OPS_CACHE_SIZE + 1)),
291 			OPS_POOL_SIZE_MIN));
292 
293 	if (org_op_type == RTE_BBDEV_OP_NONE)
294 		op_type = RTE_BBDEV_OP_TURBO_ENC;
295 
296 	op_type_str = rte_bbdev_op_type_str(op_type);
297 	TEST_ASSERT_NOT_NULL(op_type_str, "Invalid op type: %u", op_type);
298 
299 	snprintf(pool_name, sizeof(pool_name), "%s_pool_%u", op_type_str,
300 			ad->dev_id);
301 	mp = rte_bbdev_op_pool_create(pool_name, op_type,
302 			ops_pool_size, OPS_CACHE_SIZE, socket_id);
303 	TEST_ASSERT_NOT_NULL(mp,
304 			"ERROR Failed to create %u items ops pool for dev %u on socket %u.",
305 			ops_pool_size,
306 			ad->dev_id,
307 			socket_id);
308 	ad->ops_mempool = mp;
309 
310 	/* Do not create inputs and outputs mbufs for BaseBand Null Device */
311 	if (org_op_type == RTE_BBDEV_OP_NONE)
312 		return TEST_SUCCESS;
313 
314 	/* Inputs */
315 	mbuf_pool_size = optimal_mempool_size(ops_pool_size * in->nb_segments);
316 	mp = create_mbuf_pool(in, ad->dev_id, socket_id, mbuf_pool_size, "in");
317 	TEST_ASSERT_NOT_NULL(mp,
318 			"ERROR Failed to create %u items input pktmbuf pool for dev %u on socket %u.",
319 			mbuf_pool_size,
320 			ad->dev_id,
321 			socket_id);
322 	ad->in_mbuf_pool = mp;
323 
324 	/* Hard outputs */
325 	mbuf_pool_size = optimal_mempool_size(ops_pool_size *
326 			hard_out->nb_segments);
327 	mp = create_mbuf_pool(hard_out, ad->dev_id, socket_id, mbuf_pool_size,
328 			"hard_out");
329 	TEST_ASSERT_NOT_NULL(mp,
330 			"ERROR Failed to create %u items hard output pktmbuf pool for dev %u on socket %u.",
331 			mbuf_pool_size,
332 			ad->dev_id,
333 			socket_id);
334 	ad->hard_out_mbuf_pool = mp;
335 
336 	if (soft_out->nb_segments == 0)
337 		return TEST_SUCCESS;
338 
339 	/* Soft outputs */
340 	mbuf_pool_size = optimal_mempool_size(ops_pool_size *
341 			soft_out->nb_segments);
342 	mp = create_mbuf_pool(soft_out, ad->dev_id, socket_id, mbuf_pool_size,
343 			"soft_out");
344 	TEST_ASSERT_NOT_NULL(mp,
345 			"ERROR Failed to create %uB soft output pktmbuf pool for dev %u on socket %u.",
346 			mbuf_pool_size,
347 			ad->dev_id,
348 			socket_id);
349 	ad->soft_out_mbuf_pool = mp;
350 
351 	return 0;
352 }
353 
354 static int
355 add_bbdev_dev(uint8_t dev_id, struct rte_bbdev_info *info,
356 		struct test_bbdev_vector *vector)
357 {
358 	int ret;
359 	unsigned int queue_id;
360 	struct rte_bbdev_queue_conf qconf;
361 	struct active_device *ad = &active_devs[nb_active_devs];
362 	unsigned int nb_queues;
363 	enum rte_bbdev_op_type op_type = vector->op_type;
364 
365 	nb_queues = RTE_MIN(rte_lcore_count(), info->drv.max_num_queues);
366 	/* setup device */
367 	ret = rte_bbdev_setup_queues(dev_id, nb_queues, info->socket_id);
368 	if (ret < 0) {
369 		printf("rte_bbdev_setup_queues(%u, %u, %d) ret %i\n",
370 				dev_id, nb_queues, info->socket_id, ret);
371 		return TEST_FAILED;
372 	}
373 
374 	/* configure interrupts if needed */
375 	if (intr_enabled) {
376 		ret = rte_bbdev_intr_enable(dev_id);
377 		if (ret < 0) {
378 			printf("rte_bbdev_intr_enable(%u) ret %i\n", dev_id,
379 					ret);
380 			return TEST_FAILED;
381 		}
382 	}
383 
384 	/* setup device queues */
385 	qconf.socket = info->socket_id;
386 	qconf.queue_size = info->drv.default_queue_conf.queue_size;
387 	qconf.priority = 0;
388 	qconf.deferred_start = 0;
389 	qconf.op_type = op_type;
390 
391 	for (queue_id = 0; queue_id < nb_queues; ++queue_id) {
392 		ret = rte_bbdev_queue_configure(dev_id, queue_id, &qconf);
393 		if (ret != 0) {
394 			printf(
395 					"Allocated all queues (id=%u) at prio%u on dev%u\n",
396 					queue_id, qconf.priority, dev_id);
397 			qconf.priority++;
398 			ret = rte_bbdev_queue_configure(ad->dev_id, queue_id,
399 					&qconf);
400 		}
401 		if (ret != 0) {
402 			printf("All queues on dev %u allocated: %u\n",
403 					dev_id, queue_id);
404 			break;
405 		}
406 		ad->queue_ids[queue_id] = queue_id;
407 	}
408 	TEST_ASSERT(queue_id != 0,
409 			"ERROR Failed to configure any queues on dev %u",
410 			dev_id);
411 	ad->nb_queues = queue_id;
412 
413 	set_avail_op(ad, op_type);
414 
415 	return TEST_SUCCESS;
416 }
417 
418 static int
419 add_active_device(uint8_t dev_id, struct rte_bbdev_info *info,
420 		struct test_bbdev_vector *vector)
421 {
422 	int ret;
423 
424 	active_devs[nb_active_devs].driver_name = info->drv.driver_name;
425 	active_devs[nb_active_devs].dev_id = dev_id;
426 
427 	ret = add_bbdev_dev(dev_id, info, vector);
428 	if (ret == TEST_SUCCESS)
429 		++nb_active_devs;
430 	return ret;
431 }
432 
433 static uint8_t
434 populate_active_devices(void)
435 {
436 	int ret;
437 	uint8_t dev_id;
438 	uint8_t nb_devs_added = 0;
439 	struct rte_bbdev_info info;
440 
441 	RTE_BBDEV_FOREACH(dev_id) {
442 		rte_bbdev_info_get(dev_id, &info);
443 
444 		if (check_dev_cap(&info)) {
445 			printf(
446 				"Device %d (%s) does not support specified capabilities\n",
447 					dev_id, info.dev_name);
448 			continue;
449 		}
450 
451 		ret = add_active_device(dev_id, &info, &test_vector);
452 		if (ret != 0) {
453 			printf("Adding active bbdev %s skipped\n",
454 					info.dev_name);
455 			continue;
456 		}
457 		nb_devs_added++;
458 	}
459 
460 	return nb_devs_added;
461 }
462 
463 static int
464 read_test_vector(void)
465 {
466 	int ret;
467 
468 	memset(&test_vector, 0, sizeof(test_vector));
469 	printf("Test vector file = %s\n", get_vector_filename());
470 	ret = test_bbdev_vector_read(get_vector_filename(), &test_vector);
471 	TEST_ASSERT_SUCCESS(ret, "Failed to parse file %s\n",
472 			get_vector_filename());
473 
474 	return TEST_SUCCESS;
475 }
476 
477 static int
478 testsuite_setup(void)
479 {
480 	TEST_ASSERT_SUCCESS(read_test_vector(), "Test suite setup failed\n");
481 
482 	if (populate_active_devices() == 0) {
483 		printf("No suitable devices found!\n");
484 		return TEST_SKIPPED;
485 	}
486 
487 	return TEST_SUCCESS;
488 }
489 
490 static int
491 interrupt_testsuite_setup(void)
492 {
493 	TEST_ASSERT_SUCCESS(read_test_vector(), "Test suite setup failed\n");
494 
495 	/* Enable interrupts */
496 	intr_enabled = true;
497 
498 	/* Special case for NULL device (RTE_BBDEV_OP_NONE) */
499 	if (populate_active_devices() == 0 ||
500 			test_vector.op_type == RTE_BBDEV_OP_NONE) {
501 		intr_enabled = false;
502 		printf("No suitable devices found!\n");
503 		return TEST_SKIPPED;
504 	}
505 
506 	return TEST_SUCCESS;
507 }
508 
509 static void
510 testsuite_teardown(void)
511 {
512 	uint8_t dev_id;
513 
514 	/* Unconfigure devices */
515 	RTE_BBDEV_FOREACH(dev_id)
516 		rte_bbdev_close(dev_id);
517 
518 	/* Clear active devices structs. */
519 	memset(active_devs, 0, sizeof(active_devs));
520 	nb_active_devs = 0;
521 }
522 
523 static int
524 ut_setup(void)
525 {
526 	uint8_t i, dev_id;
527 
528 	for (i = 0; i < nb_active_devs; i++) {
529 		dev_id = active_devs[i].dev_id;
530 		/* reset bbdev stats */
531 		TEST_ASSERT_SUCCESS(rte_bbdev_stats_reset(dev_id),
532 				"Failed to reset stats of bbdev %u", dev_id);
533 		/* start the device */
534 		TEST_ASSERT_SUCCESS(rte_bbdev_start(dev_id),
535 				"Failed to start bbdev %u", dev_id);
536 	}
537 
538 	return TEST_SUCCESS;
539 }
540 
541 static void
542 ut_teardown(void)
543 {
544 	uint8_t i, dev_id;
545 	struct rte_bbdev_stats stats;
546 
547 	for (i = 0; i < nb_active_devs; i++) {
548 		dev_id = active_devs[i].dev_id;
549 		/* read stats and print */
550 		rte_bbdev_stats_get(dev_id, &stats);
551 		/* Stop the device */
552 		rte_bbdev_stop(dev_id);
553 	}
554 }
555 
556 static int
557 init_op_data_objs(struct rte_bbdev_op_data *bufs,
558 		struct op_data_entries *ref_entries,
559 		struct rte_mempool *mbuf_pool, const uint16_t n,
560 		enum op_data_type op_type, uint16_t min_alignment)
561 {
562 	int ret;
563 	unsigned int i, j;
564 
565 	for (i = 0; i < n; ++i) {
566 		char *data;
567 		struct op_data_buf *seg = &ref_entries->segments[0];
568 		struct rte_mbuf *m_head = rte_pktmbuf_alloc(mbuf_pool);
569 		TEST_ASSERT_NOT_NULL(m_head,
570 				"Not enough mbufs in %d data type mbuf pool (needed %u, available %u)",
571 				op_type, n * ref_entries->nb_segments,
572 				mbuf_pool->size);
573 
574 		bufs[i].data = m_head;
575 		bufs[i].offset = 0;
576 		bufs[i].length = 0;
577 
578 		if (op_type == DATA_INPUT) {
579 			data = rte_pktmbuf_append(m_head, seg->length);
580 			TEST_ASSERT_NOT_NULL(data,
581 					"Couldn't append %u bytes to mbuf from %d data type mbuf pool",
582 					seg->length, op_type);
583 
584 			TEST_ASSERT(data == RTE_PTR_ALIGN(data, min_alignment),
585 					"Data addr in mbuf (%p) is not aligned to device min alignment (%u)",
586 					data, min_alignment);
587 			rte_memcpy(data, seg->addr, seg->length);
588 			bufs[i].length += seg->length;
589 
590 
591 			for (j = 1; j < ref_entries->nb_segments; ++j) {
592 				struct rte_mbuf *m_tail =
593 						rte_pktmbuf_alloc(mbuf_pool);
594 				TEST_ASSERT_NOT_NULL(m_tail,
595 						"Not enough mbufs in %d data type mbuf pool (needed %u, available %u)",
596 						op_type,
597 						n * ref_entries->nb_segments,
598 						mbuf_pool->size);
599 				seg += 1;
600 
601 				data = rte_pktmbuf_append(m_tail, seg->length);
602 				TEST_ASSERT_NOT_NULL(data,
603 						"Couldn't append %u bytes to mbuf from %d data type mbuf pool",
604 						seg->length, op_type);
605 
606 				TEST_ASSERT(data == RTE_PTR_ALIGN(data,
607 						min_alignment),
608 						"Data addr in mbuf (%p) is not aligned to device min alignment (%u)",
609 						data, min_alignment);
610 				rte_memcpy(data, seg->addr, seg->length);
611 				bufs[i].length += seg->length;
612 
613 				ret = rte_pktmbuf_chain(m_head, m_tail);
614 				TEST_ASSERT_SUCCESS(ret,
615 						"Couldn't chain mbufs from %d data type mbuf pool",
616 						op_type);
617 			}
618 		}
619 	}
620 
621 	return 0;
622 }
623 
624 static int
625 allocate_buffers_on_socket(struct rte_bbdev_op_data **buffers, const int len,
626 		const int socket)
627 {
628 	int i;
629 
630 	*buffers = rte_zmalloc_socket(NULL, len, 0, socket);
631 	if (*buffers == NULL) {
632 		printf("WARNING: Failed to allocate op_data on socket %d\n",
633 				socket);
634 		/* try to allocate memory on other detected sockets */
635 		for (i = 0; i < socket; i++) {
636 			*buffers = rte_zmalloc_socket(NULL, len, 0, i);
637 			if (*buffers != NULL)
638 				break;
639 		}
640 	}
641 
642 	return (*buffers == NULL) ? TEST_FAILED : TEST_SUCCESS;
643 }
644 
645 static void
646 limit_input_llr_val_range(struct rte_bbdev_op_data *input_ops,
647 		uint16_t n, int8_t max_llr_modulus)
648 {
649 	uint16_t i, byte_idx;
650 
651 	for (i = 0; i < n; ++i) {
652 		struct rte_mbuf *m = input_ops[i].data;
653 		while (m != NULL) {
654 			int8_t *llr = rte_pktmbuf_mtod_offset(m, int8_t *,
655 					input_ops[i].offset);
656 			for (byte_idx = 0; byte_idx < input_ops[i].length;
657 					++byte_idx)
658 				llr[byte_idx] = round((double)max_llr_modulus *
659 						llr[byte_idx] / INT8_MAX);
660 
661 			m = m->next;
662 		}
663 	}
664 }
665 
666 static int
667 fill_queue_buffers(struct test_op_params *op_params,
668 		struct rte_mempool *in_mp, struct rte_mempool *hard_out_mp,
669 		struct rte_mempool *soft_out_mp, uint16_t queue_id,
670 		const struct rte_bbdev_op_cap *capabilities,
671 		uint16_t min_alignment, const int socket_id)
672 {
673 	int ret;
674 	enum op_data_type type;
675 	const uint16_t n = op_params->num_to_process;
676 
677 	struct rte_mempool *mbuf_pools[DATA_NUM_TYPES] = {
678 		in_mp,
679 		soft_out_mp,
680 		hard_out_mp,
681 	};
682 
683 	struct rte_bbdev_op_data **queue_ops[DATA_NUM_TYPES] = {
684 		&op_params->q_bufs[socket_id][queue_id].inputs,
685 		&op_params->q_bufs[socket_id][queue_id].soft_outputs,
686 		&op_params->q_bufs[socket_id][queue_id].hard_outputs,
687 	};
688 
689 	for (type = DATA_INPUT; type < DATA_NUM_TYPES; ++type) {
690 		struct op_data_entries *ref_entries =
691 				&test_vector.entries[type];
692 		if (ref_entries->nb_segments == 0)
693 			continue;
694 
695 		ret = allocate_buffers_on_socket(queue_ops[type],
696 				n * sizeof(struct rte_bbdev_op_data),
697 				socket_id);
698 		TEST_ASSERT_SUCCESS(ret,
699 				"Couldn't allocate memory for rte_bbdev_op_data structs");
700 
701 		ret = init_op_data_objs(*queue_ops[type], ref_entries,
702 				mbuf_pools[type], n, type, min_alignment);
703 		TEST_ASSERT_SUCCESS(ret,
704 				"Couldn't init rte_bbdev_op_data structs");
705 	}
706 
707 	if (test_vector.op_type == RTE_BBDEV_OP_TURBO_DEC)
708 		limit_input_llr_val_range(*queue_ops[DATA_INPUT], n,
709 			capabilities->cap.turbo_dec.max_llr_modulus);
710 
711 	return 0;
712 }
713 
714 static void
715 free_buffers(struct active_device *ad, struct test_op_params *op_params)
716 {
717 	unsigned int i, j;
718 
719 	rte_mempool_free(ad->ops_mempool);
720 	rte_mempool_free(ad->in_mbuf_pool);
721 	rte_mempool_free(ad->hard_out_mbuf_pool);
722 	rte_mempool_free(ad->soft_out_mbuf_pool);
723 
724 	for (i = 0; i < rte_lcore_count(); ++i) {
725 		for (j = 0; j < RTE_MAX_NUMA_NODES; ++j) {
726 			rte_free(op_params->q_bufs[j][i].inputs);
727 			rte_free(op_params->q_bufs[j][i].hard_outputs);
728 			rte_free(op_params->q_bufs[j][i].soft_outputs);
729 		}
730 	}
731 }
732 
733 static void
734 copy_reference_dec_op(struct rte_bbdev_dec_op **ops, unsigned int n,
735 		unsigned int start_idx,
736 		struct rte_bbdev_op_data *inputs,
737 		struct rte_bbdev_op_data *hard_outputs,
738 		struct rte_bbdev_op_data *soft_outputs,
739 		struct rte_bbdev_dec_op *ref_op)
740 {
741 	unsigned int i;
742 	struct rte_bbdev_op_turbo_dec *turbo_dec = &ref_op->turbo_dec;
743 
744 	for (i = 0; i < n; ++i) {
745 		if (turbo_dec->code_block_mode == 0) {
746 			ops[i]->turbo_dec.tb_params.ea =
747 					turbo_dec->tb_params.ea;
748 			ops[i]->turbo_dec.tb_params.eb =
749 					turbo_dec->tb_params.eb;
750 			ops[i]->turbo_dec.tb_params.k_pos =
751 					turbo_dec->tb_params.k_pos;
752 			ops[i]->turbo_dec.tb_params.k_neg =
753 					turbo_dec->tb_params.k_neg;
754 			ops[i]->turbo_dec.tb_params.c =
755 					turbo_dec->tb_params.c;
756 			ops[i]->turbo_dec.tb_params.c_neg =
757 					turbo_dec->tb_params.c_neg;
758 			ops[i]->turbo_dec.tb_params.cab =
759 					turbo_dec->tb_params.cab;
760 		} else {
761 			ops[i]->turbo_dec.cb_params.e = turbo_dec->cb_params.e;
762 			ops[i]->turbo_dec.cb_params.k = turbo_dec->cb_params.k;
763 		}
764 
765 		ops[i]->turbo_dec.ext_scale = turbo_dec->ext_scale;
766 		ops[i]->turbo_dec.iter_max = turbo_dec->iter_max;
767 		ops[i]->turbo_dec.iter_min = turbo_dec->iter_min;
768 		ops[i]->turbo_dec.op_flags = turbo_dec->op_flags;
769 		ops[i]->turbo_dec.rv_index = turbo_dec->rv_index;
770 		ops[i]->turbo_dec.num_maps = turbo_dec->num_maps;
771 		ops[i]->turbo_dec.code_block_mode = turbo_dec->code_block_mode;
772 
773 		ops[i]->turbo_dec.hard_output = hard_outputs[start_idx + i];
774 		ops[i]->turbo_dec.input = inputs[start_idx + i];
775 		if (soft_outputs != NULL)
776 			ops[i]->turbo_dec.soft_output =
777 				soft_outputs[start_idx + i];
778 	}
779 }
780 
781 static void
782 copy_reference_enc_op(struct rte_bbdev_enc_op **ops, unsigned int n,
783 		unsigned int start_idx,
784 		struct rte_bbdev_op_data *inputs,
785 		struct rte_bbdev_op_data *outputs,
786 		struct rte_bbdev_enc_op *ref_op)
787 {
788 	unsigned int i;
789 	struct rte_bbdev_op_turbo_enc *turbo_enc = &ref_op->turbo_enc;
790 	for (i = 0; i < n; ++i) {
791 		if (turbo_enc->code_block_mode == 0) {
792 			ops[i]->turbo_enc.tb_params.ea =
793 					turbo_enc->tb_params.ea;
794 			ops[i]->turbo_enc.tb_params.eb =
795 					turbo_enc->tb_params.eb;
796 			ops[i]->turbo_enc.tb_params.k_pos =
797 					turbo_enc->tb_params.k_pos;
798 			ops[i]->turbo_enc.tb_params.k_neg =
799 					turbo_enc->tb_params.k_neg;
800 			ops[i]->turbo_enc.tb_params.c =
801 					turbo_enc->tb_params.c;
802 			ops[i]->turbo_enc.tb_params.c_neg =
803 					turbo_enc->tb_params.c_neg;
804 			ops[i]->turbo_enc.tb_params.cab =
805 					turbo_enc->tb_params.cab;
806 			ops[i]->turbo_enc.tb_params.ncb_pos =
807 					turbo_enc->tb_params.ncb_pos;
808 			ops[i]->turbo_enc.tb_params.ncb_neg =
809 					turbo_enc->tb_params.ncb_neg;
810 			ops[i]->turbo_enc.tb_params.r = turbo_enc->tb_params.r;
811 		} else {
812 			ops[i]->turbo_enc.cb_params.e = turbo_enc->cb_params.e;
813 			ops[i]->turbo_enc.cb_params.k = turbo_enc->cb_params.k;
814 			ops[i]->turbo_enc.cb_params.ncb =
815 					turbo_enc->cb_params.ncb;
816 		}
817 		ops[i]->turbo_enc.rv_index = turbo_enc->rv_index;
818 		ops[i]->turbo_enc.op_flags = turbo_enc->op_flags;
819 		ops[i]->turbo_enc.code_block_mode = turbo_enc->code_block_mode;
820 
821 		ops[i]->turbo_enc.output = outputs[start_idx + i];
822 		ops[i]->turbo_enc.input = inputs[start_idx + i];
823 	}
824 }
825 
826 static int
827 check_dec_status_and_ordering(struct rte_bbdev_dec_op *op,
828 		unsigned int order_idx, const int expected_status)
829 {
830 	TEST_ASSERT(op->status == expected_status,
831 			"op_status (%d) != expected_status (%d)",
832 			op->status, expected_status);
833 
834 	TEST_ASSERT((void *)(uintptr_t)order_idx == op->opaque_data,
835 			"Ordering error, expected %p, got %p",
836 			(void *)(uintptr_t)order_idx, op->opaque_data);
837 
838 	return TEST_SUCCESS;
839 }
840 
841 static int
842 check_enc_status_and_ordering(struct rte_bbdev_enc_op *op,
843 		unsigned int order_idx, const int expected_status)
844 {
845 	TEST_ASSERT(op->status == expected_status,
846 			"op_status (%d) != expected_status (%d)",
847 			op->status, expected_status);
848 
849 	TEST_ASSERT((void *)(uintptr_t)order_idx == op->opaque_data,
850 			"Ordering error, expected %p, got %p",
851 			(void *)(uintptr_t)order_idx, op->opaque_data);
852 
853 	return TEST_SUCCESS;
854 }
855 
856 static inline int
857 validate_op_chain(struct rte_bbdev_op_data *op,
858 		struct op_data_entries *orig_op)
859 {
860 	uint8_t i;
861 	struct rte_mbuf *m = op->data;
862 	uint8_t nb_dst_segments = orig_op->nb_segments;
863 
864 	TEST_ASSERT(nb_dst_segments == m->nb_segs,
865 			"Number of segments differ in original (%u) and filled (%u) op",
866 			nb_dst_segments, m->nb_segs);
867 
868 	for (i = 0; i < nb_dst_segments; ++i) {
869 		/* Apply offset to the first mbuf segment */
870 		uint16_t offset = (i == 0) ? op->offset : 0;
871 		uint16_t data_len = m->data_len - offset;
872 
873 		TEST_ASSERT(orig_op->segments[i].length == data_len,
874 				"Length of segment differ in original (%u) and filled (%u) op",
875 				orig_op->segments[i].length, data_len);
876 		TEST_ASSERT_BUFFERS_ARE_EQUAL(orig_op->segments[i].addr,
877 				rte_pktmbuf_mtod_offset(m, uint32_t *, offset),
878 				data_len,
879 				"Output buffers (CB=%u) are not equal", i);
880 		m = m->next;
881 	}
882 
883 	return TEST_SUCCESS;
884 }
885 
886 static int
887 validate_dec_buffers(struct rte_bbdev_dec_op *ref_op, struct test_buffers *bufs,
888 		const uint16_t num_to_process)
889 {
890 	int i;
891 
892 	struct op_data_entries *hard_data_orig =
893 			&test_vector.entries[DATA_HARD_OUTPUT];
894 	struct op_data_entries *soft_data_orig =
895 			&test_vector.entries[DATA_SOFT_OUTPUT];
896 
897 	for (i = 0; i < num_to_process; i++) {
898 		TEST_ASSERT_SUCCESS(validate_op_chain(&bufs->hard_outputs[i],
899 				hard_data_orig),
900 				"Hard output buffers are not equal");
901 		if (ref_op->turbo_dec.op_flags &
902 				RTE_BBDEV_TURBO_SOFT_OUTPUT)
903 			TEST_ASSERT_SUCCESS(validate_op_chain(
904 					&bufs->soft_outputs[i],
905 					soft_data_orig),
906 					"Soft output buffers are not equal");
907 	}
908 
909 	return TEST_SUCCESS;
910 }
911 
912 static int
913 validate_enc_buffers(struct test_buffers *bufs, const uint16_t num_to_process)
914 {
915 	int i;
916 
917 	struct op_data_entries *hard_data_orig =
918 			&test_vector.entries[DATA_HARD_OUTPUT];
919 
920 	for (i = 0; i < num_to_process; i++)
921 		TEST_ASSERT_SUCCESS(validate_op_chain(&bufs->hard_outputs[i],
922 				hard_data_orig), "");
923 
924 	return TEST_SUCCESS;
925 }
926 
927 static int
928 validate_dec_op(struct rte_bbdev_dec_op **ops, const uint16_t n,
929 		struct rte_bbdev_dec_op *ref_op, const int vector_mask)
930 {
931 	unsigned int i;
932 	int ret;
933 	struct op_data_entries *hard_data_orig =
934 			&test_vector.entries[DATA_HARD_OUTPUT];
935 	struct op_data_entries *soft_data_orig =
936 			&test_vector.entries[DATA_SOFT_OUTPUT];
937 	struct rte_bbdev_op_turbo_dec *ops_td;
938 	struct rte_bbdev_op_data *hard_output;
939 	struct rte_bbdev_op_data *soft_output;
940 	struct rte_bbdev_op_turbo_dec *ref_td = &ref_op->turbo_dec;
941 
942 	for (i = 0; i < n; ++i) {
943 		ops_td = &ops[i]->turbo_dec;
944 		hard_output = &ops_td->hard_output;
945 		soft_output = &ops_td->soft_output;
946 
947 		if (vector_mask & TEST_BBDEV_VF_EXPECTED_ITER_COUNT)
948 			TEST_ASSERT(ops_td->iter_count <= ref_td->iter_count,
949 					"Returned iter_count (%d) > expected iter_count (%d)",
950 					ops_td->iter_count, ref_td->iter_count);
951 		ret = check_dec_status_and_ordering(ops[i], i, ref_op->status);
952 		TEST_ASSERT_SUCCESS(ret,
953 				"Checking status and ordering for decoder failed");
954 
955 		TEST_ASSERT_SUCCESS(validate_op_chain(hard_output,
956 				hard_data_orig),
957 				"Hard output buffers (CB=%u) are not equal",
958 				i);
959 
960 		if (ref_op->turbo_dec.op_flags & RTE_BBDEV_TURBO_SOFT_OUTPUT)
961 			TEST_ASSERT_SUCCESS(validate_op_chain(soft_output,
962 					soft_data_orig),
963 					"Soft output buffers (CB=%u) are not equal",
964 					i);
965 	}
966 
967 	return TEST_SUCCESS;
968 }
969 
970 static int
971 validate_enc_op(struct rte_bbdev_enc_op **ops, const uint16_t n,
972 		struct rte_bbdev_enc_op *ref_op)
973 {
974 	unsigned int i;
975 	int ret;
976 	struct op_data_entries *hard_data_orig =
977 			&test_vector.entries[DATA_HARD_OUTPUT];
978 
979 	for (i = 0; i < n; ++i) {
980 		ret = check_enc_status_and_ordering(ops[i], i, ref_op->status);
981 		TEST_ASSERT_SUCCESS(ret,
982 				"Checking status and ordering for encoder failed");
983 		TEST_ASSERT_SUCCESS(validate_op_chain(
984 				&ops[i]->turbo_enc.output,
985 				hard_data_orig),
986 				"Output buffers (CB=%u) are not equal",
987 				i);
988 	}
989 
990 	return TEST_SUCCESS;
991 }
992 
993 static void
994 create_reference_dec_op(struct rte_bbdev_dec_op *op)
995 {
996 	unsigned int i;
997 	struct op_data_entries *entry;
998 
999 	op->turbo_dec = test_vector.turbo_dec;
1000 	entry = &test_vector.entries[DATA_INPUT];
1001 	for (i = 0; i < entry->nb_segments; ++i)
1002 		op->turbo_dec.input.length +=
1003 				entry->segments[i].length;
1004 }
1005 
1006 static void
1007 create_reference_enc_op(struct rte_bbdev_enc_op *op)
1008 {
1009 	unsigned int i;
1010 	struct op_data_entries *entry;
1011 
1012 	op->turbo_enc = test_vector.turbo_enc;
1013 	entry = &test_vector.entries[DATA_INPUT];
1014 	for (i = 0; i < entry->nb_segments; ++i)
1015 		op->turbo_enc.input.length +=
1016 				entry->segments[i].length;
1017 }
1018 
1019 static int
1020 init_test_op_params(struct test_op_params *op_params,
1021 		enum rte_bbdev_op_type op_type, const int expected_status,
1022 		const int vector_mask, struct rte_mempool *ops_mp,
1023 		uint16_t burst_sz, uint16_t num_to_process, uint16_t num_lcores)
1024 {
1025 	int ret = 0;
1026 	if (op_type == RTE_BBDEV_OP_TURBO_DEC)
1027 		ret = rte_bbdev_dec_op_alloc_bulk(ops_mp,
1028 				&op_params->ref_dec_op, 1);
1029 	else
1030 		ret = rte_bbdev_enc_op_alloc_bulk(ops_mp,
1031 				&op_params->ref_enc_op, 1);
1032 
1033 	TEST_ASSERT_SUCCESS(ret, "rte_bbdev_op_alloc_bulk() failed");
1034 
1035 	op_params->mp = ops_mp;
1036 	op_params->burst_sz = burst_sz;
1037 	op_params->num_to_process = num_to_process;
1038 	op_params->num_lcores = num_lcores;
1039 	op_params->vector_mask = vector_mask;
1040 	if (op_type == RTE_BBDEV_OP_TURBO_DEC)
1041 		op_params->ref_dec_op->status = expected_status;
1042 	else if (op_type == RTE_BBDEV_OP_TURBO_ENC)
1043 		op_params->ref_enc_op->status = expected_status;
1044 
1045 	return 0;
1046 }
1047 
1048 static int
1049 run_test_case_on_device(test_case_function *test_case_func, uint8_t dev_id,
1050 		struct test_op_params *op_params)
1051 {
1052 	int t_ret, f_ret, socket_id = SOCKET_ID_ANY;
1053 	unsigned int i;
1054 	struct active_device *ad;
1055 	unsigned int burst_sz = get_burst_sz();
1056 	enum rte_bbdev_op_type op_type = test_vector.op_type;
1057 	const struct rte_bbdev_op_cap *capabilities = NULL;
1058 
1059 	ad = &active_devs[dev_id];
1060 
1061 	/* Check if device supports op_type */
1062 	if (!is_avail_op(ad, test_vector.op_type))
1063 		return TEST_SUCCESS;
1064 
1065 	struct rte_bbdev_info info;
1066 	rte_bbdev_info_get(ad->dev_id, &info);
1067 	socket_id = GET_SOCKET(info.socket_id);
1068 
1069 	f_ret = create_mempools(ad, socket_id, op_type,
1070 			get_num_ops());
1071 	if (f_ret != TEST_SUCCESS) {
1072 		printf("Couldn't create mempools");
1073 		goto fail;
1074 	}
1075 	if (op_type == RTE_BBDEV_OP_NONE)
1076 		op_type = RTE_BBDEV_OP_TURBO_ENC;
1077 
1078 	f_ret = init_test_op_params(op_params, test_vector.op_type,
1079 			test_vector.expected_status,
1080 			test_vector.mask,
1081 			ad->ops_mempool,
1082 			burst_sz,
1083 			get_num_ops(),
1084 			get_num_lcores());
1085 	if (f_ret != TEST_SUCCESS) {
1086 		printf("Couldn't init test op params");
1087 		goto fail;
1088 	}
1089 
1090 	if (test_vector.op_type == RTE_BBDEV_OP_TURBO_DEC) {
1091 		/* Find Decoder capabilities */
1092 		const struct rte_bbdev_op_cap *cap = info.drv.capabilities;
1093 		while (cap->type != RTE_BBDEV_OP_NONE) {
1094 			if (cap->type == RTE_BBDEV_OP_TURBO_DEC) {
1095 				capabilities = cap;
1096 				break;
1097 			}
1098 		}
1099 		TEST_ASSERT_NOT_NULL(capabilities,
1100 				"Couldn't find Decoder capabilities");
1101 
1102 		create_reference_dec_op(op_params->ref_dec_op);
1103 	} else if (test_vector.op_type == RTE_BBDEV_OP_TURBO_ENC)
1104 		create_reference_enc_op(op_params->ref_enc_op);
1105 
1106 	for (i = 0; i < ad->nb_queues; ++i) {
1107 		f_ret = fill_queue_buffers(op_params,
1108 				ad->in_mbuf_pool,
1109 				ad->hard_out_mbuf_pool,
1110 				ad->soft_out_mbuf_pool,
1111 				ad->queue_ids[i],
1112 				capabilities,
1113 				info.drv.min_alignment,
1114 				socket_id);
1115 		if (f_ret != TEST_SUCCESS) {
1116 			printf("Couldn't init queue buffers");
1117 			goto fail;
1118 		}
1119 	}
1120 
1121 	/* Run test case function */
1122 	t_ret = test_case_func(ad, op_params);
1123 
1124 	/* Free active device resources and return */
1125 	free_buffers(ad, op_params);
1126 	return t_ret;
1127 
1128 fail:
1129 	free_buffers(ad, op_params);
1130 	return TEST_FAILED;
1131 }
1132 
1133 /* Run given test function per active device per supported op type
1134  * per burst size.
1135  */
1136 static int
1137 run_test_case(test_case_function *test_case_func)
1138 {
1139 	int ret = 0;
1140 	uint8_t dev;
1141 
1142 	/* Alloc op_params */
1143 	struct test_op_params *op_params = rte_zmalloc(NULL,
1144 			sizeof(struct test_op_params), RTE_CACHE_LINE_SIZE);
1145 	TEST_ASSERT_NOT_NULL(op_params, "Failed to alloc %zuB for op_params",
1146 			RTE_ALIGN(sizeof(struct test_op_params),
1147 				RTE_CACHE_LINE_SIZE));
1148 
1149 	/* For each device run test case function */
1150 	for (dev = 0; dev < nb_active_devs; ++dev)
1151 		ret |= run_test_case_on_device(test_case_func, dev, op_params);
1152 
1153 	rte_free(op_params);
1154 
1155 	return ret;
1156 }
1157 
1158 static void
1159 dequeue_event_callback(uint16_t dev_id,
1160 		enum rte_bbdev_event_type event, void *cb_arg,
1161 		void *ret_param)
1162 {
1163 	int ret;
1164 	uint16_t i;
1165 	uint64_t total_time;
1166 	uint16_t deq, burst_sz, num_to_process;
1167 	uint16_t queue_id = INVALID_QUEUE_ID;
1168 	struct rte_bbdev_dec_op *dec_ops[MAX_BURST];
1169 	struct rte_bbdev_enc_op *enc_ops[MAX_BURST];
1170 	struct test_buffers *bufs;
1171 	struct rte_bbdev_info info;
1172 
1173 	/* Input length in bytes, million operations per second,
1174 	 * million bits per second.
1175 	 */
1176 	double in_len;
1177 
1178 	struct thread_params *tp = cb_arg;
1179 	RTE_SET_USED(ret_param);
1180 	queue_id = tp->queue_id;
1181 
1182 	/* Find matching thread params using queue_id */
1183 	for (i = 0; i < MAX_QUEUES; ++i, ++tp)
1184 		if (tp->queue_id == queue_id)
1185 			break;
1186 
1187 	if (i == MAX_QUEUES) {
1188 		printf("%s: Queue_id from interrupt details was not found!\n",
1189 				__func__);
1190 		return;
1191 	}
1192 
1193 	if (unlikely(event != RTE_BBDEV_EVENT_DEQUEUE)) {
1194 		rte_atomic16_set(&tp->processing_status, TEST_FAILED);
1195 		printf(
1196 			"Dequeue interrupt handler called for incorrect event!\n");
1197 		return;
1198 	}
1199 
1200 	burst_sz = tp->op_params->burst_sz;
1201 	num_to_process = tp->op_params->num_to_process;
1202 
1203 	if (test_vector.op_type == RTE_BBDEV_OP_TURBO_DEC)
1204 		deq = rte_bbdev_dequeue_dec_ops(dev_id, queue_id, dec_ops,
1205 				burst_sz);
1206 	else
1207 		deq = rte_bbdev_dequeue_enc_ops(dev_id, queue_id, enc_ops,
1208 				burst_sz);
1209 
1210 	if (deq < burst_sz) {
1211 		printf(
1212 			"After receiving the interrupt all operations should be dequeued. Expected: %u, got: %u\n",
1213 			burst_sz, deq);
1214 		rte_atomic16_set(&tp->processing_status, TEST_FAILED);
1215 		return;
1216 	}
1217 
1218 	if (rte_atomic16_read(&tp->nb_dequeued) + deq < num_to_process) {
1219 		rte_atomic16_add(&tp->nb_dequeued, deq);
1220 		return;
1221 	}
1222 
1223 	total_time = rte_rdtsc_precise() - tp->start_time;
1224 
1225 	rte_bbdev_info_get(dev_id, &info);
1226 
1227 	bufs = &tp->op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id];
1228 
1229 	ret = TEST_SUCCESS;
1230 	if (test_vector.op_type == RTE_BBDEV_OP_TURBO_DEC)
1231 		ret = validate_dec_buffers(tp->op_params->ref_dec_op, bufs,
1232 				num_to_process);
1233 	else if (test_vector.op_type == RTE_BBDEV_OP_TURBO_ENC)
1234 		ret = validate_enc_buffers(bufs, num_to_process);
1235 
1236 	if (ret) {
1237 		printf("Buffers validation failed\n");
1238 		rte_atomic16_set(&tp->processing_status, TEST_FAILED);
1239 	}
1240 
1241 	switch (test_vector.op_type) {
1242 	case RTE_BBDEV_OP_TURBO_DEC:
1243 		in_len = tp->op_params->ref_dec_op->turbo_dec.input.length;
1244 		break;
1245 	case RTE_BBDEV_OP_TURBO_ENC:
1246 		in_len = tp->op_params->ref_enc_op->turbo_enc.input.length;
1247 		break;
1248 	case RTE_BBDEV_OP_NONE:
1249 		in_len = 0.0;
1250 		break;
1251 	default:
1252 		printf("Unknown op type: %d\n", test_vector.op_type);
1253 		rte_atomic16_set(&tp->processing_status, TEST_FAILED);
1254 		return;
1255 	}
1256 
1257 	tp->mops = ((double)num_to_process / 1000000.0) /
1258 			((double)total_time / (double)rte_get_tsc_hz());
1259 	tp->mbps = ((double)num_to_process * in_len * 8 / 1000000.0) /
1260 			((double)total_time / (double)rte_get_tsc_hz());
1261 
1262 	rte_atomic16_add(&tp->nb_dequeued, deq);
1263 }
1264 
1265 static int
1266 throughput_intr_lcore_dec(void *arg)
1267 {
1268 	struct thread_params *tp = arg;
1269 	unsigned int enqueued;
1270 	struct rte_bbdev_dec_op *ops[MAX_BURST];
1271 	const uint16_t queue_id = tp->queue_id;
1272 	const uint16_t burst_sz = tp->op_params->burst_sz;
1273 	const uint16_t num_to_process = tp->op_params->num_to_process;
1274 	struct test_buffers *bufs = NULL;
1275 	unsigned int allocs_failed = 0;
1276 	struct rte_bbdev_info info;
1277 	int ret;
1278 
1279 	TEST_ASSERT_SUCCESS((burst_sz > MAX_BURST),
1280 			"BURST_SIZE should be <= %u", MAX_BURST);
1281 
1282 	TEST_ASSERT_SUCCESS(rte_bbdev_queue_intr_enable(tp->dev_id, queue_id),
1283 			"Failed to enable interrupts for dev: %u, queue_id: %u",
1284 			tp->dev_id, queue_id);
1285 
1286 	rte_bbdev_info_get(tp->dev_id, &info);
1287 	bufs = &tp->op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id];
1288 
1289 	rte_atomic16_clear(&tp->processing_status);
1290 	rte_atomic16_clear(&tp->nb_dequeued);
1291 
1292 	while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT)
1293 		rte_pause();
1294 
1295 	tp->start_time = rte_rdtsc_precise();
1296 	for (enqueued = 0; enqueued < num_to_process;) {
1297 
1298 		uint16_t num_to_enq = burst_sz;
1299 
1300 		if (unlikely(num_to_process - enqueued < num_to_enq))
1301 			num_to_enq = num_to_process - enqueued;
1302 
1303 		ret = rte_bbdev_dec_op_alloc_bulk(tp->op_params->mp, ops,
1304 				num_to_enq);
1305 		if (ret != 0) {
1306 			allocs_failed++;
1307 			continue;
1308 		}
1309 
1310 		if (test_vector.op_type != RTE_BBDEV_OP_NONE)
1311 			copy_reference_dec_op(ops, num_to_enq, enqueued,
1312 					bufs->inputs,
1313 					bufs->hard_outputs,
1314 					bufs->soft_outputs,
1315 					tp->op_params->ref_dec_op);
1316 
1317 		enqueued += rte_bbdev_enqueue_dec_ops(tp->dev_id, queue_id, ops,
1318 				num_to_enq);
1319 
1320 		rte_bbdev_dec_op_free_bulk(ops, num_to_enq);
1321 	}
1322 
1323 	if (allocs_failed > 0)
1324 		printf("WARNING: op allocations failed: %u times\n",
1325 				allocs_failed);
1326 
1327 	return TEST_SUCCESS;
1328 }
1329 
1330 static int
1331 throughput_intr_lcore_enc(void *arg)
1332 {
1333 	struct thread_params *tp = arg;
1334 	unsigned int enqueued;
1335 	struct rte_bbdev_enc_op *ops[MAX_BURST];
1336 	const uint16_t queue_id = tp->queue_id;
1337 	const uint16_t burst_sz = tp->op_params->burst_sz;
1338 	const uint16_t num_to_process = tp->op_params->num_to_process;
1339 	struct test_buffers *bufs = NULL;
1340 	unsigned int allocs_failed = 0;
1341 	struct rte_bbdev_info info;
1342 	int ret;
1343 
1344 	TEST_ASSERT_SUCCESS((burst_sz > MAX_BURST),
1345 			"BURST_SIZE should be <= %u", MAX_BURST);
1346 
1347 	TEST_ASSERT_SUCCESS(rte_bbdev_queue_intr_enable(tp->dev_id, queue_id),
1348 			"Failed to enable interrupts for dev: %u, queue_id: %u",
1349 			tp->dev_id, queue_id);
1350 
1351 	rte_bbdev_info_get(tp->dev_id, &info);
1352 	bufs = &tp->op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id];
1353 
1354 	rte_atomic16_clear(&tp->processing_status);
1355 	rte_atomic16_clear(&tp->nb_dequeued);
1356 
1357 	while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT)
1358 		rte_pause();
1359 
1360 	tp->start_time = rte_rdtsc_precise();
1361 	for (enqueued = 0; enqueued < num_to_process;) {
1362 
1363 		uint16_t num_to_enq = burst_sz;
1364 
1365 		if (unlikely(num_to_process - enqueued < num_to_enq))
1366 			num_to_enq = num_to_process - enqueued;
1367 
1368 		ret = rte_bbdev_enc_op_alloc_bulk(tp->op_params->mp, ops,
1369 				num_to_enq);
1370 		if (ret != 0) {
1371 			allocs_failed++;
1372 			continue;
1373 		}
1374 
1375 		if (test_vector.op_type != RTE_BBDEV_OP_NONE)
1376 			copy_reference_enc_op(ops, num_to_enq, enqueued,
1377 					bufs->inputs,
1378 					bufs->hard_outputs,
1379 					tp->op_params->ref_enc_op);
1380 
1381 		enqueued += rte_bbdev_enqueue_enc_ops(tp->dev_id, queue_id, ops,
1382 				num_to_enq);
1383 
1384 		rte_bbdev_enc_op_free_bulk(ops, num_to_enq);
1385 	}
1386 
1387 	if (allocs_failed > 0)
1388 		printf("WARNING: op allocations failed: %u times\n",
1389 				allocs_failed);
1390 
1391 	return TEST_SUCCESS;
1392 }
1393 
1394 static int
1395 throughput_pmd_lcore_dec(void *arg)
1396 {
1397 	struct thread_params *tp = arg;
1398 	unsigned int enqueued, dequeued;
1399 	struct rte_bbdev_dec_op *ops_enq[MAX_BURST], *ops_deq[MAX_BURST];
1400 	uint64_t total_time, start_time;
1401 	const uint16_t queue_id = tp->queue_id;
1402 	const uint16_t burst_sz = tp->op_params->burst_sz;
1403 	const uint16_t num_to_process = tp->op_params->num_to_process;
1404 	struct rte_bbdev_dec_op *ref_op = tp->op_params->ref_dec_op;
1405 	struct test_buffers *bufs = NULL;
1406 	unsigned int allocs_failed = 0;
1407 	int ret;
1408 	struct rte_bbdev_info info;
1409 
1410 	/* Input length in bytes, million operations per second, million bits
1411 	 * per second.
1412 	 */
1413 	double in_len;
1414 
1415 	TEST_ASSERT_SUCCESS((burst_sz > MAX_BURST),
1416 			"BURST_SIZE should be <= %u", MAX_BURST);
1417 
1418 	rte_bbdev_info_get(tp->dev_id, &info);
1419 	bufs = &tp->op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id];
1420 
1421 	while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT)
1422 		rte_pause();
1423 
1424 	start_time = rte_rdtsc_precise();
1425 	for (enqueued = 0, dequeued = 0; dequeued < num_to_process;) {
1426 		uint16_t deq;
1427 
1428 		if (likely(enqueued < num_to_process)) {
1429 
1430 			uint16_t num_to_enq = burst_sz;
1431 
1432 			if (unlikely(num_to_process - enqueued < num_to_enq))
1433 				num_to_enq = num_to_process - enqueued;
1434 
1435 			ret = rte_bbdev_dec_op_alloc_bulk(tp->op_params->mp,
1436 					ops_enq, num_to_enq);
1437 			if (ret != 0) {
1438 				allocs_failed++;
1439 				goto do_dequeue;
1440 			}
1441 
1442 			if (test_vector.op_type != RTE_BBDEV_OP_NONE)
1443 				copy_reference_dec_op(ops_enq, num_to_enq,
1444 						enqueued,
1445 						bufs->inputs,
1446 						bufs->hard_outputs,
1447 						bufs->soft_outputs,
1448 						ref_op);
1449 
1450 			enqueued += rte_bbdev_enqueue_dec_ops(tp->dev_id,
1451 					queue_id, ops_enq, num_to_enq);
1452 		}
1453 do_dequeue:
1454 		deq = rte_bbdev_dequeue_dec_ops(tp->dev_id, queue_id, ops_deq,
1455 				burst_sz);
1456 		dequeued += deq;
1457 		rte_bbdev_dec_op_free_bulk(ops_enq, deq);
1458 	}
1459 	total_time = rte_rdtsc_precise() - start_time;
1460 
1461 	if (allocs_failed > 0)
1462 		printf("WARNING: op allocations failed: %u times\n",
1463 				allocs_failed);
1464 
1465 	TEST_ASSERT(enqueued == dequeued, "enqueued (%u) != dequeued (%u)",
1466 			enqueued, dequeued);
1467 
1468 	if (test_vector.op_type != RTE_BBDEV_OP_NONE) {
1469 		ret = validate_dec_buffers(ref_op, bufs, num_to_process);
1470 		TEST_ASSERT_SUCCESS(ret, "Buffers validation failed");
1471 	}
1472 
1473 	in_len = ref_op->turbo_dec.input.length;
1474 	tp->mops = ((double)num_to_process / 1000000.0) /
1475 			((double)total_time / (double)rte_get_tsc_hz());
1476 	tp->mbps = ((double)num_to_process * in_len * 8 / 1000000.0) /
1477 			((double)total_time / (double)rte_get_tsc_hz());
1478 
1479 	return TEST_SUCCESS;
1480 }
1481 
1482 static int
1483 throughput_pmd_lcore_enc(void *arg)
1484 {
1485 	struct thread_params *tp = arg;
1486 	unsigned int enqueued, dequeued;
1487 	struct rte_bbdev_enc_op *ops_enq[MAX_BURST], *ops_deq[MAX_BURST];
1488 	uint64_t total_time, start_time;
1489 	const uint16_t queue_id = tp->queue_id;
1490 	const uint16_t burst_sz = tp->op_params->burst_sz;
1491 	const uint16_t num_to_process = tp->op_params->num_to_process;
1492 	struct rte_bbdev_enc_op *ref_op = tp->op_params->ref_enc_op;
1493 	struct test_buffers *bufs = NULL;
1494 	unsigned int allocs_failed = 0;
1495 	int ret;
1496 	struct rte_bbdev_info info;
1497 
1498 	/* Input length in bytes, million operations per second, million bits
1499 	 * per second.
1500 	 */
1501 	double in_len;
1502 
1503 	TEST_ASSERT_SUCCESS((burst_sz > MAX_BURST),
1504 			"BURST_SIZE should be <= %u", MAX_BURST);
1505 
1506 	rte_bbdev_info_get(tp->dev_id, &info);
1507 	bufs = &tp->op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id];
1508 
1509 	while (rte_atomic16_read(&tp->op_params->sync) == SYNC_WAIT)
1510 		rte_pause();
1511 
1512 	start_time = rte_rdtsc_precise();
1513 	for (enqueued = 0, dequeued = 0; dequeued < num_to_process;) {
1514 		uint16_t deq;
1515 
1516 		if (likely(enqueued < num_to_process)) {
1517 
1518 			uint16_t num_to_enq = burst_sz;
1519 
1520 			if (unlikely(num_to_process - enqueued < num_to_enq))
1521 				num_to_enq = num_to_process - enqueued;
1522 
1523 			ret = rte_bbdev_enc_op_alloc_bulk(tp->op_params->mp,
1524 					ops_enq, num_to_enq);
1525 			if (ret != 0) {
1526 				allocs_failed++;
1527 				goto do_dequeue;
1528 			}
1529 
1530 			if (test_vector.op_type != RTE_BBDEV_OP_NONE)
1531 				copy_reference_enc_op(ops_enq, num_to_enq,
1532 						enqueued,
1533 						bufs->inputs,
1534 						bufs->hard_outputs,
1535 						ref_op);
1536 
1537 			enqueued += rte_bbdev_enqueue_enc_ops(tp->dev_id,
1538 					queue_id, ops_enq, num_to_enq);
1539 		}
1540 do_dequeue:
1541 		deq = rte_bbdev_dequeue_enc_ops(tp->dev_id, queue_id, ops_deq,
1542 				burst_sz);
1543 		dequeued += deq;
1544 		rte_bbdev_enc_op_free_bulk(ops_enq, deq);
1545 	}
1546 	total_time = rte_rdtsc_precise() - start_time;
1547 
1548 	if (allocs_failed > 0)
1549 		printf("WARNING: op allocations failed: %u times\n",
1550 				allocs_failed);
1551 
1552 	TEST_ASSERT(enqueued == dequeued, "enqueued (%u) != dequeued (%u)",
1553 			enqueued, dequeued);
1554 
1555 	if (test_vector.op_type != RTE_BBDEV_OP_NONE) {
1556 		ret = validate_enc_buffers(bufs, num_to_process);
1557 		TEST_ASSERT_SUCCESS(ret, "Buffers validation failed");
1558 	}
1559 
1560 	in_len = ref_op->turbo_enc.input.length;
1561 
1562 	tp->mops = ((double)num_to_process / 1000000.0) /
1563 			((double)total_time / (double)rte_get_tsc_hz());
1564 	tp->mbps = ((double)num_to_process * in_len * 8 / 1000000.0) /
1565 			((double)total_time / (double)rte_get_tsc_hz());
1566 
1567 	return TEST_SUCCESS;
1568 }
1569 static void
1570 print_throughput(struct thread_params *t_params, unsigned int used_cores)
1571 {
1572 	unsigned int lcore_id, iter = 0;
1573 	double total_mops = 0, total_mbps = 0;
1574 
1575 	RTE_LCORE_FOREACH(lcore_id) {
1576 		if (iter++ >= used_cores)
1577 			break;
1578 		printf("\tlcore_id: %u, throughput: %.8lg MOPS, %.8lg Mbps\n",
1579 		lcore_id, t_params[lcore_id].mops, t_params[lcore_id].mbps);
1580 		total_mops += t_params[lcore_id].mops;
1581 		total_mbps += t_params[lcore_id].mbps;
1582 	}
1583 	printf(
1584 		"\n\tTotal stats for %u cores: throughput: %.8lg MOPS, %.8lg Mbps\n",
1585 		used_cores, total_mops, total_mbps);
1586 }
1587 
1588 /*
1589  * Test function that determines how long an enqueue + dequeue of a burst
1590  * takes on available lcores.
1591  */
1592 static int
1593 throughput_test(struct active_device *ad,
1594 		struct test_op_params *op_params)
1595 {
1596 	int ret;
1597 	unsigned int lcore_id, used_cores = 0;
1598 	struct thread_params t_params[MAX_QUEUES];
1599 	struct rte_bbdev_info info;
1600 	lcore_function_t *throughput_function;
1601 	struct thread_params *tp;
1602 	uint16_t num_lcores;
1603 	const char *op_type_str;
1604 
1605 	rte_bbdev_info_get(ad->dev_id, &info);
1606 
1607 	op_type_str = rte_bbdev_op_type_str(test_vector.op_type);
1608 	TEST_ASSERT_NOT_NULL(op_type_str, "Invalid op type: %u",
1609 			test_vector.op_type);
1610 
1611 	printf(
1612 		"Throughput test: dev: %s, nb_queues: %u, burst size: %u, num ops: %u, num_lcores: %u, op type: %s, int mode: %s, GHz: %lg\n",
1613 			info.dev_name, ad->nb_queues, op_params->burst_sz,
1614 			op_params->num_to_process, op_params->num_lcores,
1615 			op_type_str,
1616 			intr_enabled ? "Interrupt mode" : "PMD mode",
1617 			(double)rte_get_tsc_hz() / 1000000000.0);
1618 
1619 	/* Set number of lcores */
1620 	num_lcores = (ad->nb_queues < (op_params->num_lcores))
1621 			? ad->nb_queues
1622 			: op_params->num_lcores;
1623 
1624 	if (intr_enabled) {
1625 		if (test_vector.op_type == RTE_BBDEV_OP_TURBO_DEC)
1626 			throughput_function = throughput_intr_lcore_dec;
1627 		else
1628 			throughput_function = throughput_intr_lcore_enc;
1629 
1630 		/* Dequeue interrupt callback registration */
1631 		ret = rte_bbdev_callback_register(ad->dev_id,
1632 				RTE_BBDEV_EVENT_DEQUEUE, dequeue_event_callback,
1633 				&t_params);
1634 		if (ret < 0)
1635 			return ret;
1636 	} else {
1637 		if (test_vector.op_type == RTE_BBDEV_OP_TURBO_DEC)
1638 			throughput_function = throughput_pmd_lcore_dec;
1639 		else
1640 			throughput_function = throughput_pmd_lcore_enc;
1641 	}
1642 
1643 	rte_atomic16_set(&op_params->sync, SYNC_WAIT);
1644 
1645 	t_params[rte_lcore_id()].dev_id = ad->dev_id;
1646 	t_params[rte_lcore_id()].op_params = op_params;
1647 	t_params[rte_lcore_id()].queue_id =
1648 			ad->queue_ids[used_cores++];
1649 
1650 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
1651 		if (used_cores >= num_lcores)
1652 			break;
1653 
1654 		t_params[lcore_id].dev_id = ad->dev_id;
1655 		t_params[lcore_id].op_params = op_params;
1656 		t_params[lcore_id].queue_id = ad->queue_ids[used_cores++];
1657 
1658 		rte_eal_remote_launch(throughput_function, &t_params[lcore_id],
1659 				lcore_id);
1660 	}
1661 
1662 	rte_atomic16_set(&op_params->sync, SYNC_START);
1663 	ret = throughput_function(&t_params[rte_lcore_id()]);
1664 
1665 	/* Master core is always used */
1666 	used_cores = 1;
1667 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
1668 		if (used_cores++ >= num_lcores)
1669 			break;
1670 
1671 		ret |= rte_eal_wait_lcore(lcore_id);
1672 	}
1673 
1674 	/* Return if test failed */
1675 	if (ret)
1676 		return ret;
1677 
1678 	/* Print throughput if interrupts are disabled and test passed */
1679 	if (!intr_enabled) {
1680 		if (test_vector.op_type != RTE_BBDEV_OP_NONE)
1681 			print_throughput(t_params, num_lcores);
1682 		return ret;
1683 	}
1684 
1685 	/* In interrupt TC we need to wait for the interrupt callback to deqeue
1686 	 * all pending operations. Skip waiting for queues which reported an
1687 	 * error using processing_status variable.
1688 	 * Wait for master lcore operations.
1689 	 */
1690 	tp = &t_params[rte_lcore_id()];
1691 	while ((rte_atomic16_read(&tp->nb_dequeued) <
1692 			op_params->num_to_process) &&
1693 			(rte_atomic16_read(&tp->processing_status) !=
1694 			TEST_FAILED))
1695 		rte_pause();
1696 
1697 	ret |= rte_atomic16_read(&tp->processing_status);
1698 
1699 	/* Wait for slave lcores operations */
1700 	used_cores = 1;
1701 	RTE_LCORE_FOREACH_SLAVE(lcore_id) {
1702 		tp = &t_params[lcore_id];
1703 		if (used_cores++ >= num_lcores)
1704 			break;
1705 
1706 		while ((rte_atomic16_read(&tp->nb_dequeued) <
1707 				op_params->num_to_process) &&
1708 				(rte_atomic16_read(&tp->processing_status) !=
1709 				TEST_FAILED))
1710 			rte_pause();
1711 
1712 		ret |= rte_atomic16_read(&tp->processing_status);
1713 	}
1714 
1715 	/* Print throughput if test passed */
1716 	if (!ret && test_vector.op_type != RTE_BBDEV_OP_NONE)
1717 		print_throughput(t_params, num_lcores);
1718 
1719 	return ret;
1720 }
1721 
1722 static int
1723 latency_test_dec(struct rte_mempool *mempool,
1724 		struct test_buffers *bufs, struct rte_bbdev_dec_op *ref_op,
1725 		int vector_mask, uint16_t dev_id, uint16_t queue_id,
1726 		const uint16_t num_to_process, uint16_t burst_sz,
1727 		uint64_t *total_time, uint64_t *min_time, uint64_t *max_time)
1728 {
1729 	int ret = TEST_SUCCESS;
1730 	uint16_t i, j, dequeued;
1731 	struct rte_bbdev_dec_op *ops_enq[MAX_BURST], *ops_deq[MAX_BURST];
1732 	uint64_t start_time = 0, last_time = 0;
1733 
1734 	for (i = 0, dequeued = 0; dequeued < num_to_process; ++i) {
1735 		uint16_t enq = 0, deq = 0;
1736 		bool first_time = true;
1737 		last_time = 0;
1738 
1739 		if (unlikely(num_to_process - dequeued < burst_sz))
1740 			burst_sz = num_to_process - dequeued;
1741 
1742 		ret = rte_bbdev_dec_op_alloc_bulk(mempool, ops_enq, burst_sz);
1743 		TEST_ASSERT_SUCCESS(ret,
1744 				"rte_bbdev_dec_op_alloc_bulk() failed");
1745 		if (test_vector.op_type != RTE_BBDEV_OP_NONE)
1746 			copy_reference_dec_op(ops_enq, burst_sz, dequeued,
1747 					bufs->inputs,
1748 					bufs->hard_outputs,
1749 					bufs->soft_outputs,
1750 					ref_op);
1751 
1752 		/* Set counter to validate the ordering */
1753 		for (j = 0; j < burst_sz; ++j)
1754 			ops_enq[j]->opaque_data = (void *)(uintptr_t)j;
1755 
1756 		start_time = rte_rdtsc_precise();
1757 
1758 		enq = rte_bbdev_enqueue_dec_ops(dev_id, queue_id, &ops_enq[enq],
1759 				burst_sz);
1760 		TEST_ASSERT(enq == burst_sz,
1761 				"Error enqueueing burst, expected %u, got %u",
1762 				burst_sz, enq);
1763 
1764 		/* Dequeue */
1765 		do {
1766 			deq += rte_bbdev_dequeue_dec_ops(dev_id, queue_id,
1767 					&ops_deq[deq], burst_sz - deq);
1768 			if (likely(first_time && (deq > 0))) {
1769 				last_time = rte_rdtsc_precise() - start_time;
1770 				first_time = false;
1771 			}
1772 		} while (unlikely(burst_sz != deq));
1773 
1774 		*max_time = RTE_MAX(*max_time, last_time);
1775 		*min_time = RTE_MIN(*min_time, last_time);
1776 		*total_time += last_time;
1777 
1778 		if (test_vector.op_type != RTE_BBDEV_OP_NONE) {
1779 			ret = validate_dec_op(ops_deq, burst_sz, ref_op,
1780 					vector_mask);
1781 			TEST_ASSERT_SUCCESS(ret, "Validation failed!");
1782 		}
1783 
1784 		rte_bbdev_dec_op_free_bulk(ops_enq, deq);
1785 		dequeued += deq;
1786 	}
1787 
1788 	return i;
1789 }
1790 
1791 static int
1792 latency_test_enc(struct rte_mempool *mempool,
1793 		struct test_buffers *bufs, struct rte_bbdev_enc_op *ref_op,
1794 		uint16_t dev_id, uint16_t queue_id,
1795 		const uint16_t num_to_process, uint16_t burst_sz,
1796 		uint64_t *total_time, uint64_t *min_time, uint64_t *max_time)
1797 {
1798 	int ret = TEST_SUCCESS;
1799 	uint16_t i, j, dequeued;
1800 	struct rte_bbdev_enc_op *ops_enq[MAX_BURST], *ops_deq[MAX_BURST];
1801 	uint64_t start_time = 0, last_time = 0;
1802 
1803 	for (i = 0, dequeued = 0; dequeued < num_to_process; ++i) {
1804 		uint16_t enq = 0, deq = 0;
1805 		bool first_time = true;
1806 		last_time = 0;
1807 
1808 		if (unlikely(num_to_process - dequeued < burst_sz))
1809 			burst_sz = num_to_process - dequeued;
1810 
1811 		ret = rte_bbdev_enc_op_alloc_bulk(mempool, ops_enq, burst_sz);
1812 		TEST_ASSERT_SUCCESS(ret,
1813 				"rte_bbdev_enc_op_alloc_bulk() failed");
1814 		if (test_vector.op_type != RTE_BBDEV_OP_NONE)
1815 			copy_reference_enc_op(ops_enq, burst_sz, dequeued,
1816 					bufs->inputs,
1817 					bufs->hard_outputs,
1818 					ref_op);
1819 
1820 		/* Set counter to validate the ordering */
1821 		for (j = 0; j < burst_sz; ++j)
1822 			ops_enq[j]->opaque_data = (void *)(uintptr_t)j;
1823 
1824 		start_time = rte_rdtsc_precise();
1825 
1826 		enq = rte_bbdev_enqueue_enc_ops(dev_id, queue_id, &ops_enq[enq],
1827 				burst_sz);
1828 		TEST_ASSERT(enq == burst_sz,
1829 				"Error enqueueing burst, expected %u, got %u",
1830 				burst_sz, enq);
1831 
1832 		/* Dequeue */
1833 		do {
1834 			deq += rte_bbdev_dequeue_enc_ops(dev_id, queue_id,
1835 					&ops_deq[deq], burst_sz - deq);
1836 			if (likely(first_time && (deq > 0))) {
1837 				last_time += rte_rdtsc_precise() - start_time;
1838 				first_time = false;
1839 			}
1840 		} while (unlikely(burst_sz != deq));
1841 
1842 		*max_time = RTE_MAX(*max_time, last_time);
1843 		*min_time = RTE_MIN(*min_time, last_time);
1844 		*total_time += last_time;
1845 
1846 		if (test_vector.op_type != RTE_BBDEV_OP_NONE) {
1847 			ret = validate_enc_op(ops_deq, burst_sz, ref_op);
1848 			TEST_ASSERT_SUCCESS(ret, "Validation failed!");
1849 		}
1850 
1851 		rte_bbdev_enc_op_free_bulk(ops_enq, deq);
1852 		dequeued += deq;
1853 	}
1854 
1855 	return i;
1856 }
1857 
1858 static int
1859 latency_test(struct active_device *ad,
1860 		struct test_op_params *op_params)
1861 {
1862 	int iter;
1863 	uint16_t burst_sz = op_params->burst_sz;
1864 	const uint16_t num_to_process = op_params->num_to_process;
1865 	const enum rte_bbdev_op_type op_type = test_vector.op_type;
1866 	const uint16_t queue_id = ad->queue_ids[0];
1867 	struct test_buffers *bufs = NULL;
1868 	struct rte_bbdev_info info;
1869 	uint64_t total_time, min_time, max_time;
1870 	const char *op_type_str;
1871 
1872 	total_time = max_time = 0;
1873 	min_time = UINT64_MAX;
1874 
1875 	TEST_ASSERT_SUCCESS((burst_sz > MAX_BURST),
1876 			"BURST_SIZE should be <= %u", MAX_BURST);
1877 
1878 	rte_bbdev_info_get(ad->dev_id, &info);
1879 	bufs = &op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id];
1880 
1881 	op_type_str = rte_bbdev_op_type_str(op_type);
1882 	TEST_ASSERT_NOT_NULL(op_type_str, "Invalid op type: %u", op_type);
1883 
1884 	printf(
1885 		"Validation/Latency test: dev: %s, burst size: %u, num ops: %u, op type: %s\n",
1886 			info.dev_name, burst_sz, num_to_process, op_type_str);
1887 
1888 	if (op_type == RTE_BBDEV_OP_TURBO_DEC)
1889 		iter = latency_test_dec(op_params->mp, bufs,
1890 				op_params->ref_dec_op, op_params->vector_mask,
1891 				ad->dev_id, queue_id, num_to_process,
1892 				burst_sz, &total_time, &min_time, &max_time);
1893 	else
1894 		iter = latency_test_enc(op_params->mp, bufs,
1895 				op_params->ref_enc_op, ad->dev_id, queue_id,
1896 				num_to_process, burst_sz, &total_time,
1897 				&min_time, &max_time);
1898 
1899 	if (iter <= 0)
1900 		return TEST_FAILED;
1901 
1902 	printf("\toperation latency:\n"
1903 			"\t\tavg latency: %lg cycles, %lg us\n"
1904 			"\t\tmin latency: %lg cycles, %lg us\n"
1905 			"\t\tmax latency: %lg cycles, %lg us\n",
1906 			(double)total_time / (double)iter,
1907 			(double)(total_time * 1000000) / (double)iter /
1908 			(double)rte_get_tsc_hz(), (double)min_time,
1909 			(double)(min_time * 1000000) / (double)rte_get_tsc_hz(),
1910 			(double)max_time, (double)(max_time * 1000000) /
1911 			(double)rte_get_tsc_hz());
1912 
1913 	return TEST_SUCCESS;
1914 }
1915 
1916 #ifdef RTE_BBDEV_OFFLOAD_COST
1917 static int
1918 get_bbdev_queue_stats(uint16_t dev_id, uint16_t queue_id,
1919 		struct rte_bbdev_stats *stats)
1920 {
1921 	struct rte_bbdev *dev = &rte_bbdev_devices[dev_id];
1922 	struct rte_bbdev_stats *q_stats;
1923 
1924 	if (queue_id >= dev->data->num_queues)
1925 		return -1;
1926 
1927 	q_stats = &dev->data->queues[queue_id].queue_stats;
1928 
1929 	stats->enqueued_count = q_stats->enqueued_count;
1930 	stats->dequeued_count = q_stats->dequeued_count;
1931 	stats->enqueue_err_count = q_stats->enqueue_err_count;
1932 	stats->dequeue_err_count = q_stats->dequeue_err_count;
1933 	stats->offload_time = q_stats->offload_time;
1934 
1935 	return 0;
1936 }
1937 
1938 static int
1939 offload_latency_test_dec(struct rte_mempool *mempool, struct test_buffers *bufs,
1940 		struct rte_bbdev_dec_op *ref_op, uint16_t dev_id,
1941 		uint16_t queue_id, const uint16_t num_to_process,
1942 		uint16_t burst_sz, struct test_time_stats *time_st)
1943 {
1944 	int i, dequeued, ret;
1945 	struct rte_bbdev_dec_op *ops_enq[MAX_BURST], *ops_deq[MAX_BURST];
1946 	uint64_t enq_start_time, deq_start_time;
1947 	uint64_t enq_sw_last_time, deq_last_time;
1948 	struct rte_bbdev_stats stats;
1949 
1950 	for (i = 0, dequeued = 0; dequeued < num_to_process; ++i) {
1951 		uint16_t enq = 0, deq = 0;
1952 
1953 		if (unlikely(num_to_process - dequeued < burst_sz))
1954 			burst_sz = num_to_process - dequeued;
1955 
1956 		rte_bbdev_dec_op_alloc_bulk(mempool, ops_enq, burst_sz);
1957 		if (test_vector.op_type != RTE_BBDEV_OP_NONE)
1958 			copy_reference_dec_op(ops_enq, burst_sz, dequeued,
1959 					bufs->inputs,
1960 					bufs->hard_outputs,
1961 					bufs->soft_outputs,
1962 					ref_op);
1963 
1964 		/* Start time meas for enqueue function offload latency */
1965 		enq_start_time = rte_rdtsc_precise();
1966 		do {
1967 			enq += rte_bbdev_enqueue_dec_ops(dev_id, queue_id,
1968 					&ops_enq[enq], burst_sz - enq);
1969 		} while (unlikely(burst_sz != enq));
1970 
1971 		ret = get_bbdev_queue_stats(dev_id, queue_id, &stats);
1972 		TEST_ASSERT_SUCCESS(ret,
1973 				"Failed to get stats for queue (%u) of device (%u)",
1974 				queue_id, dev_id);
1975 
1976 		enq_sw_last_time = rte_rdtsc_precise() - enq_start_time -
1977 				stats.offload_time;
1978 		time_st->enq_sw_max_time = RTE_MAX(time_st->enq_sw_max_time,
1979 				enq_sw_last_time);
1980 		time_st->enq_sw_min_time = RTE_MIN(time_st->enq_sw_min_time,
1981 				enq_sw_last_time);
1982 		time_st->enq_sw_tot_time += enq_sw_last_time;
1983 
1984 		time_st->enq_tur_max_time = RTE_MAX(time_st->enq_tur_max_time,
1985 				stats.offload_time);
1986 		time_st->enq_tur_min_time = RTE_MIN(time_st->enq_tur_min_time,
1987 				stats.offload_time);
1988 		time_st->enq_tur_tot_time += stats.offload_time;
1989 
1990 		/* ensure enqueue has been completed */
1991 		rte_delay_ms(10);
1992 
1993 		/* Start time meas for dequeue function offload latency */
1994 		deq_start_time = rte_rdtsc_precise();
1995 		/* Dequeue one operation */
1996 		do {
1997 			deq += rte_bbdev_dequeue_dec_ops(dev_id, queue_id,
1998 					&ops_deq[deq], 1);
1999 		} while (unlikely(deq != 1));
2000 
2001 		deq_last_time = rte_rdtsc_precise() - deq_start_time;
2002 		time_st->deq_max_time = RTE_MAX(time_st->deq_max_time,
2003 				deq_last_time);
2004 		time_st->deq_min_time = RTE_MIN(time_st->deq_min_time,
2005 				deq_last_time);
2006 		time_st->deq_tot_time += deq_last_time;
2007 
2008 		/* Dequeue remaining operations if needed*/
2009 		while (burst_sz != deq)
2010 			deq += rte_bbdev_dequeue_dec_ops(dev_id, queue_id,
2011 					&ops_deq[deq], burst_sz - deq);
2012 
2013 		rte_bbdev_dec_op_free_bulk(ops_enq, deq);
2014 		dequeued += deq;
2015 	}
2016 
2017 	return i;
2018 }
2019 
2020 static int
2021 offload_latency_test_enc(struct rte_mempool *mempool, struct test_buffers *bufs,
2022 		struct rte_bbdev_enc_op *ref_op, uint16_t dev_id,
2023 		uint16_t queue_id, const uint16_t num_to_process,
2024 		uint16_t burst_sz, struct test_time_stats *time_st)
2025 {
2026 	int i, dequeued, ret;
2027 	struct rte_bbdev_enc_op *ops_enq[MAX_BURST], *ops_deq[MAX_BURST];
2028 	uint64_t enq_start_time, deq_start_time;
2029 	uint64_t enq_sw_last_time, deq_last_time;
2030 	struct rte_bbdev_stats stats;
2031 
2032 	for (i = 0, dequeued = 0; dequeued < num_to_process; ++i) {
2033 		uint16_t enq = 0, deq = 0;
2034 
2035 		if (unlikely(num_to_process - dequeued < burst_sz))
2036 			burst_sz = num_to_process - dequeued;
2037 
2038 		rte_bbdev_enc_op_alloc_bulk(mempool, ops_enq, burst_sz);
2039 		if (test_vector.op_type != RTE_BBDEV_OP_NONE)
2040 			copy_reference_enc_op(ops_enq, burst_sz, dequeued,
2041 					bufs->inputs,
2042 					bufs->hard_outputs,
2043 					ref_op);
2044 
2045 		/* Start time meas for enqueue function offload latency */
2046 		enq_start_time = rte_rdtsc_precise();
2047 		do {
2048 			enq += rte_bbdev_enqueue_enc_ops(dev_id, queue_id,
2049 					&ops_enq[enq], burst_sz - enq);
2050 		} while (unlikely(burst_sz != enq));
2051 
2052 		ret = get_bbdev_queue_stats(dev_id, queue_id, &stats);
2053 		TEST_ASSERT_SUCCESS(ret,
2054 				"Failed to get stats for queue (%u) of device (%u)",
2055 				queue_id, dev_id);
2056 
2057 		enq_sw_last_time = rte_rdtsc_precise() - enq_start_time -
2058 				stats.offload_time;
2059 		time_st->enq_sw_max_time = RTE_MAX(time_st->enq_sw_max_time,
2060 				enq_sw_last_time);
2061 		time_st->enq_sw_min_time = RTE_MIN(time_st->enq_sw_min_time,
2062 				enq_sw_last_time);
2063 		time_st->enq_sw_tot_time += enq_sw_last_time;
2064 
2065 		time_st->enq_tur_max_time = RTE_MAX(time_st->enq_tur_max_time,
2066 				stats.offload_time);
2067 		time_st->enq_tur_min_time = RTE_MIN(time_st->enq_tur_min_time,
2068 				stats.offload_time);
2069 		time_st->enq_tur_tot_time += stats.offload_time;
2070 
2071 		/* ensure enqueue has been completed */
2072 		rte_delay_ms(10);
2073 
2074 		/* Start time meas for dequeue function offload latency */
2075 		deq_start_time = rte_rdtsc_precise();
2076 		/* Dequeue one operation */
2077 		do {
2078 			deq += rte_bbdev_dequeue_enc_ops(dev_id, queue_id,
2079 					&ops_deq[deq], 1);
2080 		} while (unlikely(deq != 1));
2081 
2082 		deq_last_time = rte_rdtsc_precise() - deq_start_time;
2083 		time_st->deq_max_time = RTE_MAX(time_st->deq_max_time,
2084 				deq_last_time);
2085 		time_st->deq_min_time = RTE_MIN(time_st->deq_min_time,
2086 				deq_last_time);
2087 		time_st->deq_tot_time += deq_last_time;
2088 
2089 		while (burst_sz != deq)
2090 			deq += rte_bbdev_dequeue_enc_ops(dev_id, queue_id,
2091 					&ops_deq[deq], burst_sz - deq);
2092 
2093 		rte_bbdev_enc_op_free_bulk(ops_enq, deq);
2094 		dequeued += deq;
2095 	}
2096 
2097 	return i;
2098 }
2099 #endif
2100 
2101 static int
2102 offload_cost_test(struct active_device *ad,
2103 		struct test_op_params *op_params)
2104 {
2105 #ifndef RTE_BBDEV_OFFLOAD_COST
2106 	RTE_SET_USED(ad);
2107 	RTE_SET_USED(op_params);
2108 	printf("Offload latency test is disabled.\n");
2109 	printf("Set RTE_BBDEV_OFFLOAD_COST to 'y' to turn the test on.\n");
2110 	return TEST_SKIPPED;
2111 #else
2112 	int iter;
2113 	uint16_t burst_sz = op_params->burst_sz;
2114 	const uint16_t num_to_process = op_params->num_to_process;
2115 	const enum rte_bbdev_op_type op_type = test_vector.op_type;
2116 	const uint16_t queue_id = ad->queue_ids[0];
2117 	struct test_buffers *bufs = NULL;
2118 	struct rte_bbdev_info info;
2119 	const char *op_type_str;
2120 	struct test_time_stats time_st;
2121 
2122 	memset(&time_st, 0, sizeof(struct test_time_stats));
2123 	time_st.enq_sw_min_time = UINT64_MAX;
2124 	time_st.enq_tur_min_time = UINT64_MAX;
2125 	time_st.deq_min_time = UINT64_MAX;
2126 
2127 	TEST_ASSERT_SUCCESS((burst_sz > MAX_BURST),
2128 			"BURST_SIZE should be <= %u", MAX_BURST);
2129 
2130 	rte_bbdev_info_get(ad->dev_id, &info);
2131 	bufs = &op_params->q_bufs[GET_SOCKET(info.socket_id)][queue_id];
2132 
2133 	op_type_str = rte_bbdev_op_type_str(op_type);
2134 	TEST_ASSERT_NOT_NULL(op_type_str, "Invalid op type: %u", op_type);
2135 
2136 	printf(
2137 		"Offload latency test: dev: %s, burst size: %u, num ops: %u, op type: %s\n",
2138 			info.dev_name, burst_sz, num_to_process, op_type_str);
2139 
2140 	if (op_type == RTE_BBDEV_OP_TURBO_DEC)
2141 		iter = offload_latency_test_dec(op_params->mp, bufs,
2142 				op_params->ref_dec_op, ad->dev_id, queue_id,
2143 				num_to_process, burst_sz, &time_st);
2144 	else
2145 		iter = offload_latency_test_enc(op_params->mp, bufs,
2146 				op_params->ref_enc_op, ad->dev_id, queue_id,
2147 				num_to_process, burst_sz, &time_st);
2148 
2149 	if (iter <= 0)
2150 		return TEST_FAILED;
2151 
2152 	printf("\tenq offload cost latency:\n"
2153 			"\t\tsoftware avg %lg cycles, %lg us\n"
2154 			"\t\tsoftware min %lg cycles, %lg us\n"
2155 			"\t\tsoftware max %lg cycles, %lg us\n"
2156 			"\t\tturbo avg %lg cycles, %lg us\n"
2157 			"\t\tturbo min %lg cycles, %lg us\n"
2158 			"\t\tturbo max %lg cycles, %lg us\n",
2159 			(double)time_st.enq_sw_tot_time / (double)iter,
2160 			(double)(time_st.enq_sw_tot_time * 1000000) /
2161 			(double)iter / (double)rte_get_tsc_hz(),
2162 			(double)time_st.enq_sw_min_time,
2163 			(double)(time_st.enq_sw_min_time * 1000000) /
2164 			rte_get_tsc_hz(), (double)time_st.enq_sw_max_time,
2165 			(double)(time_st.enq_sw_max_time * 1000000) /
2166 			rte_get_tsc_hz(), (double)time_st.enq_tur_tot_time /
2167 			(double)iter,
2168 			(double)(time_st.enq_tur_tot_time * 1000000) /
2169 			(double)iter / (double)rte_get_tsc_hz(),
2170 			(double)time_st.enq_tur_min_time,
2171 			(double)(time_st.enq_tur_min_time * 1000000) /
2172 			rte_get_tsc_hz(), (double)time_st.enq_tur_max_time,
2173 			(double)(time_st.enq_tur_max_time * 1000000) /
2174 			rte_get_tsc_hz());
2175 
2176 	printf("\tdeq offload cost latency - one op:\n"
2177 			"\t\tavg %lg cycles, %lg us\n"
2178 			"\t\tmin %lg cycles, %lg us\n"
2179 			"\t\tmax %lg cycles, %lg us\n",
2180 			(double)time_st.deq_tot_time / (double)iter,
2181 			(double)(time_st.deq_tot_time * 1000000) /
2182 			(double)iter / (double)rte_get_tsc_hz(),
2183 			(double)time_st.deq_min_time,
2184 			(double)(time_st.deq_min_time * 1000000) /
2185 			rte_get_tsc_hz(), (double)time_st.deq_max_time,
2186 			(double)(time_st.deq_max_time * 1000000) /
2187 			rte_get_tsc_hz());
2188 
2189 	return TEST_SUCCESS;
2190 #endif
2191 }
2192 
2193 #ifdef RTE_BBDEV_OFFLOAD_COST
2194 static int
2195 offload_latency_empty_q_test_dec(uint16_t dev_id, uint16_t queue_id,
2196 		const uint16_t num_to_process, uint16_t burst_sz,
2197 		uint64_t *deq_tot_time, uint64_t *deq_min_time,
2198 		uint64_t *deq_max_time)
2199 {
2200 	int i, deq_total;
2201 	struct rte_bbdev_dec_op *ops[MAX_BURST];
2202 	uint64_t deq_start_time, deq_last_time;
2203 
2204 	/* Test deq offload latency from an empty queue */
2205 
2206 	for (i = 0, deq_total = 0; deq_total < num_to_process;
2207 			++i, deq_total += burst_sz) {
2208 		deq_start_time = rte_rdtsc_precise();
2209 
2210 		if (unlikely(num_to_process - deq_total < burst_sz))
2211 			burst_sz = num_to_process - deq_total;
2212 		rte_bbdev_dequeue_dec_ops(dev_id, queue_id, ops, burst_sz);
2213 
2214 		deq_last_time = rte_rdtsc_precise() - deq_start_time;
2215 		*deq_max_time = RTE_MAX(*deq_max_time, deq_last_time);
2216 		*deq_min_time = RTE_MIN(*deq_min_time, deq_last_time);
2217 		*deq_tot_time += deq_last_time;
2218 	}
2219 
2220 	return i;
2221 }
2222 
2223 static int
2224 offload_latency_empty_q_test_enc(uint16_t dev_id, uint16_t queue_id,
2225 		const uint16_t num_to_process, uint16_t burst_sz,
2226 		uint64_t *deq_tot_time, uint64_t *deq_min_time,
2227 		uint64_t *deq_max_time)
2228 {
2229 	int i, deq_total;
2230 	struct rte_bbdev_enc_op *ops[MAX_BURST];
2231 	uint64_t deq_start_time, deq_last_time;
2232 
2233 	/* Test deq offload latency from an empty queue */
2234 	for (i = 0, deq_total = 0; deq_total < num_to_process;
2235 			++i, deq_total += burst_sz) {
2236 		deq_start_time = rte_rdtsc_precise();
2237 
2238 		if (unlikely(num_to_process - deq_total < burst_sz))
2239 			burst_sz = num_to_process - deq_total;
2240 		rte_bbdev_dequeue_enc_ops(dev_id, queue_id, ops, burst_sz);
2241 
2242 		deq_last_time = rte_rdtsc_precise() - deq_start_time;
2243 		*deq_max_time = RTE_MAX(*deq_max_time, deq_last_time);
2244 		*deq_min_time = RTE_MIN(*deq_min_time, deq_last_time);
2245 		*deq_tot_time += deq_last_time;
2246 	}
2247 
2248 	return i;
2249 }
2250 #endif
2251 
2252 static int
2253 offload_latency_empty_q_test(struct active_device *ad,
2254 		struct test_op_params *op_params)
2255 {
2256 #ifndef RTE_BBDEV_OFFLOAD_COST
2257 	RTE_SET_USED(ad);
2258 	RTE_SET_USED(op_params);
2259 	printf("Offload latency empty dequeue test is disabled.\n");
2260 	printf("Set RTE_BBDEV_OFFLOAD_COST to 'y' to turn the test on.\n");
2261 	return TEST_SKIPPED;
2262 #else
2263 	int iter;
2264 	uint64_t deq_tot_time, deq_min_time, deq_max_time;
2265 	uint16_t burst_sz = op_params->burst_sz;
2266 	const uint16_t num_to_process = op_params->num_to_process;
2267 	const enum rte_bbdev_op_type op_type = test_vector.op_type;
2268 	const uint16_t queue_id = ad->queue_ids[0];
2269 	struct rte_bbdev_info info;
2270 	const char *op_type_str;
2271 
2272 	deq_tot_time = deq_max_time = 0;
2273 	deq_min_time = UINT64_MAX;
2274 
2275 	TEST_ASSERT_SUCCESS((burst_sz > MAX_BURST),
2276 			"BURST_SIZE should be <= %u", MAX_BURST);
2277 
2278 	rte_bbdev_info_get(ad->dev_id, &info);
2279 
2280 	op_type_str = rte_bbdev_op_type_str(op_type);
2281 	TEST_ASSERT_NOT_NULL(op_type_str, "Invalid op type: %u", op_type);
2282 
2283 	printf(
2284 		"Offload latency empty dequeue test: dev: %s, burst size: %u, num ops: %u, op type: %s\n",
2285 			info.dev_name, burst_sz, num_to_process, op_type_str);
2286 
2287 	if (op_type == RTE_BBDEV_OP_TURBO_DEC)
2288 		iter = offload_latency_empty_q_test_dec(ad->dev_id, queue_id,
2289 				num_to_process, burst_sz, &deq_tot_time,
2290 				&deq_min_time, &deq_max_time);
2291 	else
2292 		iter = offload_latency_empty_q_test_enc(ad->dev_id, queue_id,
2293 				num_to_process, burst_sz, &deq_tot_time,
2294 				&deq_min_time, &deq_max_time);
2295 
2296 	if (iter <= 0)
2297 		return TEST_FAILED;
2298 
2299 	printf("\tempty deq offload\n"
2300 			"\t\tavg. latency: %lg cycles, %lg us\n"
2301 			"\t\tmin. latency: %lg cycles, %lg us\n"
2302 			"\t\tmax. latency: %lg cycles, %lg us\n",
2303 			(double)deq_tot_time / (double)iter,
2304 			(double)(deq_tot_time * 1000000) / (double)iter /
2305 			(double)rte_get_tsc_hz(), (double)deq_min_time,
2306 			(double)(deq_min_time * 1000000) / rte_get_tsc_hz(),
2307 			(double)deq_max_time, (double)(deq_max_time * 1000000) /
2308 			rte_get_tsc_hz());
2309 
2310 	return TEST_SUCCESS;
2311 #endif
2312 }
2313 
2314 static int
2315 throughput_tc(void)
2316 {
2317 	return run_test_case(throughput_test);
2318 }
2319 
2320 static int
2321 offload_cost_tc(void)
2322 {
2323 	return run_test_case(offload_cost_test);
2324 }
2325 
2326 static int
2327 offload_latency_empty_q_tc(void)
2328 {
2329 	return run_test_case(offload_latency_empty_q_test);
2330 }
2331 
2332 static int
2333 latency_tc(void)
2334 {
2335 	return run_test_case(latency_test);
2336 }
2337 
2338 static int
2339 interrupt_tc(void)
2340 {
2341 	return run_test_case(throughput_test);
2342 }
2343 
2344 static struct unit_test_suite bbdev_throughput_testsuite = {
2345 	.suite_name = "BBdev Throughput Tests",
2346 	.setup = testsuite_setup,
2347 	.teardown = testsuite_teardown,
2348 	.unit_test_cases = {
2349 		TEST_CASE_ST(ut_setup, ut_teardown, throughput_tc),
2350 		TEST_CASES_END() /**< NULL terminate unit test array */
2351 	}
2352 };
2353 
2354 static struct unit_test_suite bbdev_validation_testsuite = {
2355 	.suite_name = "BBdev Validation Tests",
2356 	.setup = testsuite_setup,
2357 	.teardown = testsuite_teardown,
2358 	.unit_test_cases = {
2359 		TEST_CASE_ST(ut_setup, ut_teardown, latency_tc),
2360 		TEST_CASES_END() /**< NULL terminate unit test array */
2361 	}
2362 };
2363 
2364 static struct unit_test_suite bbdev_latency_testsuite = {
2365 	.suite_name = "BBdev Latency Tests",
2366 	.setup = testsuite_setup,
2367 	.teardown = testsuite_teardown,
2368 	.unit_test_cases = {
2369 		TEST_CASE_ST(ut_setup, ut_teardown, latency_tc),
2370 		TEST_CASES_END() /**< NULL terminate unit test array */
2371 	}
2372 };
2373 
2374 static struct unit_test_suite bbdev_offload_cost_testsuite = {
2375 	.suite_name = "BBdev Offload Cost Tests",
2376 	.setup = testsuite_setup,
2377 	.teardown = testsuite_teardown,
2378 	.unit_test_cases = {
2379 		TEST_CASE_ST(ut_setup, ut_teardown, offload_cost_tc),
2380 		TEST_CASE_ST(ut_setup, ut_teardown, offload_latency_empty_q_tc),
2381 		TEST_CASES_END() /**< NULL terminate unit test array */
2382 	}
2383 };
2384 
2385 static struct unit_test_suite bbdev_interrupt_testsuite = {
2386 	.suite_name = "BBdev Interrupt Tests",
2387 	.setup = interrupt_testsuite_setup,
2388 	.teardown = testsuite_teardown,
2389 	.unit_test_cases = {
2390 		TEST_CASE_ST(ut_setup, ut_teardown, interrupt_tc),
2391 		TEST_CASES_END() /**< NULL terminate unit test array */
2392 	}
2393 };
2394 
2395 REGISTER_TEST_COMMAND(throughput, bbdev_throughput_testsuite);
2396 REGISTER_TEST_COMMAND(validation, bbdev_validation_testsuite);
2397 REGISTER_TEST_COMMAND(latency, bbdev_latency_testsuite);
2398 REGISTER_TEST_COMMAND(offload, bbdev_offload_cost_testsuite);
2399 REGISTER_TEST_COMMAND(interrupt, bbdev_interrupt_testsuite);
2400