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