xref: /dpdk/app/test-crypto-perf/main.c (revision dc348f2e81a94dd3b8a32c2f882483227796905d)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2016-2017 Intel Corporation
3  */
4 
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 
9 #include <rte_malloc.h>
10 #include <rte_random.h>
11 #include <rte_eal.h>
12 #include <rte_cryptodev.h>
13 #ifdef RTE_CRYPTO_SCHEDULER
14 #include <rte_cryptodev_scheduler.h>
15 #endif
16 
17 #include "cperf.h"
18 #include "cperf_options.h"
19 #include "cperf_test_vector_parsing.h"
20 #include "cperf_test_throughput.h"
21 #include "cperf_test_latency.h"
22 #include "cperf_test_verify.h"
23 #include "cperf_test_pmd_cyclecount.h"
24 
25 static struct {
26 	struct rte_mempool *sess_mp;
27 } session_pool_socket[RTE_MAX_NUMA_NODES];
28 
29 const char *cperf_test_type_strs[] = {
30 	[CPERF_TEST_TYPE_THROUGHPUT] = "throughput",
31 	[CPERF_TEST_TYPE_LATENCY] = "latency",
32 	[CPERF_TEST_TYPE_VERIFY] = "verify",
33 	[CPERF_TEST_TYPE_PMDCC] = "pmd-cyclecount"
34 };
35 
36 const char *cperf_op_type_strs[] = {
37 	[CPERF_CIPHER_ONLY] = "cipher-only",
38 	[CPERF_AUTH_ONLY] = "auth-only",
39 	[CPERF_CIPHER_THEN_AUTH] = "cipher-then-auth",
40 	[CPERF_AUTH_THEN_CIPHER] = "auth-then-cipher",
41 	[CPERF_AEAD] = "aead",
42 	[CPERF_PDCP] = "pdcp",
43 	[CPERF_DOCSIS] = "docsis",
44 	[CPERF_IPSEC] = "ipsec",
45 	[CPERF_ASYM_MODEX] = "modex"
46 };
47 
48 const struct cperf_test cperf_testmap[] = {
49 		[CPERF_TEST_TYPE_THROUGHPUT] = {
50 				cperf_throughput_test_constructor,
51 				cperf_throughput_test_runner,
52 				cperf_throughput_test_destructor
53 		},
54 		[CPERF_TEST_TYPE_LATENCY] = {
55 				cperf_latency_test_constructor,
56 				cperf_latency_test_runner,
57 				cperf_latency_test_destructor
58 		},
59 		[CPERF_TEST_TYPE_VERIFY] = {
60 				cperf_verify_test_constructor,
61 				cperf_verify_test_runner,
62 				cperf_verify_test_destructor
63 		},
64 		[CPERF_TEST_TYPE_PMDCC] = {
65 				cperf_pmd_cyclecount_test_constructor,
66 				cperf_pmd_cyclecount_test_runner,
67 				cperf_pmd_cyclecount_test_destructor
68 		}
69 };
70 
71 static int
72 create_asym_op_pool_socket(int32_t socket_id, uint32_t nb_sessions)
73 {
74 	char mp_name[RTE_MEMPOOL_NAMESIZE];
75 	struct rte_mempool *mpool = NULL;
76 
77 	if (session_pool_socket[socket_id].sess_mp == NULL) {
78 		snprintf(mp_name, RTE_MEMPOOL_NAMESIZE, "perf_asym_sess_pool%u",
79 			 socket_id);
80 		mpool = rte_cryptodev_asym_session_pool_create(mp_name,
81 				nb_sessions, 0, 0, socket_id);
82 		if (mpool == NULL) {
83 			printf("Cannot create pool \"%s\" on socket %d\n",
84 			       mp_name, socket_id);
85 			return -ENOMEM;
86 		}
87 		session_pool_socket[socket_id].sess_mp = mpool;
88 	}
89 	return 0;
90 }
91 
92 static int
93 fill_session_pool_socket(int32_t socket_id, uint32_t session_priv_size,
94 		uint32_t nb_sessions)
95 {
96 	char mp_name[RTE_MEMPOOL_NAMESIZE];
97 	struct rte_mempool *sess_mp;
98 
99 	if (session_pool_socket[socket_id].sess_mp == NULL) {
100 
101 		snprintf(mp_name, RTE_MEMPOOL_NAMESIZE,
102 			"sess_mp_%u", socket_id);
103 
104 		sess_mp = rte_cryptodev_sym_session_pool_create(mp_name,
105 					nb_sessions, session_priv_size, 0, 0,
106 					socket_id);
107 
108 		if (sess_mp == NULL) {
109 			printf("Cannot create pool \"%s\" on socket %d\n",
110 				mp_name, socket_id);
111 			return -ENOMEM;
112 		}
113 
114 		printf("Allocated pool \"%s\" on socket %d\n",
115 			mp_name, socket_id);
116 		session_pool_socket[socket_id].sess_mp = sess_mp;
117 	}
118 
119 	return 0;
120 }
121 
122 static int
123 cperf_initialize_cryptodev(struct cperf_options *opts, uint8_t *enabled_cdevs)
124 {
125 	uint8_t enabled_cdev_count = 0, nb_lcores, cdev_id;
126 	uint32_t sessions_needed = 0;
127 	unsigned int i, j;
128 	int ret;
129 
130 	enabled_cdev_count = rte_cryptodev_devices_get(opts->device_type,
131 			enabled_cdevs, RTE_CRYPTO_MAX_DEVS);
132 	if (enabled_cdev_count == 0) {
133 		printf("No crypto devices type %s available\n",
134 				opts->device_type);
135 		return -EINVAL;
136 	}
137 
138 	nb_lcores = rte_lcore_count() - 1;
139 
140 	if (nb_lcores < 1) {
141 		RTE_LOG(ERR, USER1,
142 			"Number of enabled cores need to be higher than 1\n");
143 		return -EINVAL;
144 	}
145 
146 	/*
147 	 * Use less number of devices,
148 	 * if there are more available than cores.
149 	 */
150 	if (enabled_cdev_count > nb_lcores)
151 		enabled_cdev_count = nb_lcores;
152 
153 	/* Create a mempool shared by all the devices */
154 	uint32_t max_sess_size = 0, sess_size;
155 
156 	for (cdev_id = 0; cdev_id < rte_cryptodev_count(); cdev_id++) {
157 		sess_size = rte_cryptodev_sym_get_private_session_size(cdev_id);
158 		if (sess_size > max_sess_size)
159 			max_sess_size = sess_size;
160 	}
161 #ifdef RTE_LIB_SECURITY
162 	for (cdev_id = 0; cdev_id < rte_cryptodev_count(); cdev_id++) {
163 		sess_size = rte_security_session_get_size(
164 				rte_cryptodev_get_sec_ctx(cdev_id));
165 		if (sess_size > max_sess_size)
166 			max_sess_size = sess_size;
167 	}
168 #endif
169 	/*
170 	 * Calculate number of needed queue pairs, based on the amount
171 	 * of available number of logical cores and crypto devices.
172 	 * For instance, if there are 4 cores and 2 crypto devices,
173 	 * 2 queue pairs will be set up per device.
174 	 */
175 	opts->nb_qps = (nb_lcores % enabled_cdev_count) ?
176 				(nb_lcores / enabled_cdev_count) + 1 :
177 				nb_lcores / enabled_cdev_count;
178 
179 	for (i = 0; i < enabled_cdev_count &&
180 			i < RTE_CRYPTO_MAX_DEVS; i++) {
181 		cdev_id = enabled_cdevs[i];
182 #ifdef RTE_CRYPTO_SCHEDULER
183 		/*
184 		 * If multi-core scheduler is used, limit the number
185 		 * of queue pairs to 1, as there is no way to know
186 		 * how many cores are being used by the PMD, and
187 		 * how many will be available for the application.
188 		 */
189 		if (!strcmp((const char *)opts->device_type, "crypto_scheduler") &&
190 				rte_cryptodev_scheduler_mode_get(cdev_id) ==
191 				CDEV_SCHED_MODE_MULTICORE)
192 			opts->nb_qps = 1;
193 #endif
194 
195 		struct rte_cryptodev_info cdev_info;
196 		uint8_t socket_id = rte_cryptodev_socket_id(cdev_id);
197 		/* range check the socket_id - negative values become big
198 		 * positive ones due to use of unsigned value
199 		 */
200 		if (socket_id >= RTE_MAX_NUMA_NODES)
201 			socket_id = 0;
202 
203 		rte_cryptodev_info_get(cdev_id, &cdev_info);
204 
205 		if (opts->op_type == CPERF_ASYM_MODEX) {
206 			if ((cdev_info.feature_flags &
207 			     RTE_CRYPTODEV_FF_ASYMMETRIC_CRYPTO) == 0)
208 				continue;
209 		}
210 
211 		if (opts->nb_qps > cdev_info.max_nb_queue_pairs) {
212 			printf("Number of needed queue pairs is higher "
213 				"than the maximum number of queue pairs "
214 				"per device.\n");
215 			printf("Lower the number of cores or increase "
216 				"the number of crypto devices\n");
217 			return -EINVAL;
218 		}
219 		struct rte_cryptodev_config conf = {
220 			.nb_queue_pairs = opts->nb_qps,
221 			.socket_id = socket_id,
222 		};
223 
224 		switch (opts->op_type) {
225 		case CPERF_ASYM_MODEX:
226 			conf.ff_disable |= (RTE_CRYPTODEV_FF_SECURITY |
227 					    RTE_CRYPTODEV_FF_SYMMETRIC_CRYPTO);
228 			break;
229 		case CPERF_CIPHER_ONLY:
230 		case CPERF_AUTH_ONLY:
231 		case CPERF_CIPHER_THEN_AUTH:
232 		case CPERF_AUTH_THEN_CIPHER:
233 		case CPERF_AEAD:
234 			conf.ff_disable |= RTE_CRYPTODEV_FF_SECURITY;
235 			/* Fall through */
236 		case CPERF_PDCP:
237 		case CPERF_DOCSIS:
238 		case CPERF_IPSEC:
239 			/* Fall through */
240 		default:
241 			conf.ff_disable |= RTE_CRYPTODEV_FF_ASYMMETRIC_CRYPTO;
242 		}
243 
244 		struct rte_cryptodev_qp_conf qp_conf = {
245 			.nb_descriptors = opts->nb_descriptors
246 		};
247 
248 		/**
249 		 * Device info specifies the min headroom and tailroom
250 		 * requirement for the crypto PMD. This need to be honoured
251 		 * by the application, while creating mbuf.
252 		 */
253 		if (opts->headroom_sz < cdev_info.min_mbuf_headroom_req) {
254 			/* Update headroom */
255 			opts->headroom_sz = cdev_info.min_mbuf_headroom_req;
256 		}
257 		if (opts->tailroom_sz < cdev_info.min_mbuf_tailroom_req) {
258 			/* Update tailroom */
259 			opts->tailroom_sz = cdev_info.min_mbuf_tailroom_req;
260 		}
261 
262 		/* Update segment size to include headroom & tailroom */
263 		opts->segment_sz += (opts->headroom_sz + opts->tailroom_sz);
264 
265 		uint32_t dev_max_nb_sess = cdev_info.sym.max_nb_sessions;
266 		/*
267 		 * Two sessions objects are required for each session
268 		 * (one for the header, one for the private data)
269 		 */
270 		if (!strcmp((const char *)opts->device_type,
271 					"crypto_scheduler")) {
272 #ifdef RTE_CRYPTO_SCHEDULER
273 			uint32_t nb_slaves =
274 				rte_cryptodev_scheduler_workers_get(cdev_id,
275 								NULL);
276 
277 			sessions_needed = enabled_cdev_count *
278 				opts->nb_qps * nb_slaves;
279 #endif
280 		} else
281 			sessions_needed = enabled_cdev_count * opts->nb_qps;
282 
283 		/*
284 		 * A single session is required per queue pair
285 		 * in each device
286 		 */
287 		if (dev_max_nb_sess != 0 && dev_max_nb_sess < opts->nb_qps) {
288 			RTE_LOG(ERR, USER1,
289 				"Device does not support at least "
290 				"%u sessions\n", opts->nb_qps);
291 			return -ENOTSUP;
292 		}
293 
294 		if (opts->op_type == CPERF_ASYM_MODEX)
295 			ret = create_asym_op_pool_socket(socket_id,
296 							 sessions_needed);
297 		else
298 			ret = fill_session_pool_socket(socket_id, max_sess_size,
299 						       sessions_needed);
300 		if (ret < 0)
301 			return ret;
302 
303 		qp_conf.mp_session = session_pool_socket[socket_id].sess_mp;
304 
305 		if (opts->op_type == CPERF_ASYM_MODEX) {
306 			qp_conf.mp_session = NULL;
307 		}
308 
309 		ret = rte_cryptodev_configure(cdev_id, &conf);
310 		if (ret < 0) {
311 			printf("Failed to configure cryptodev %u", cdev_id);
312 			return -EINVAL;
313 		}
314 
315 		for (j = 0; j < opts->nb_qps; j++) {
316 			ret = rte_cryptodev_queue_pair_setup(cdev_id, j,
317 				&qp_conf, socket_id);
318 			if (ret < 0) {
319 				printf("Failed to setup queue pair %u on "
320 					"cryptodev %u",	j, cdev_id);
321 				return -EINVAL;
322 			}
323 		}
324 
325 		ret = rte_cryptodev_start(cdev_id);
326 		if (ret < 0) {
327 			printf("Failed to start device %u: error %d\n",
328 					cdev_id, ret);
329 			return -EPERM;
330 		}
331 	}
332 
333 	return enabled_cdev_count;
334 }
335 
336 static int
337 cperf_verify_devices_capabilities(struct cperf_options *opts,
338 		uint8_t *enabled_cdevs, uint8_t nb_cryptodevs)
339 {
340 	struct rte_cryptodev_sym_capability_idx cap_idx;
341 	const struct rte_cryptodev_symmetric_capability *capability;
342 	struct rte_cryptodev_asym_capability_idx asym_cap_idx;
343 	const struct rte_cryptodev_asymmetric_xform_capability *asym_capability;
344 
345 
346 	uint8_t i, cdev_id;
347 	int ret;
348 
349 	for (i = 0; i < nb_cryptodevs; i++) {
350 
351 		cdev_id = enabled_cdevs[i];
352 
353 		if (opts->op_type == CPERF_ASYM_MODEX) {
354 			asym_cap_idx.type = RTE_CRYPTO_ASYM_XFORM_MODEX;
355 			asym_capability = rte_cryptodev_asym_capability_get(
356 				cdev_id, &asym_cap_idx);
357 			if (asym_capability == NULL)
358 				return -1;
359 
360 			ret = rte_cryptodev_asym_xform_capability_check_modlen(
361 				asym_capability, opts->modex_data->modulus.len);
362 			if (ret != 0)
363 				return ret;
364 
365 		}
366 
367 		if (opts->op_type == CPERF_AUTH_ONLY ||
368 				opts->op_type == CPERF_CIPHER_THEN_AUTH ||
369 				opts->op_type == CPERF_AUTH_THEN_CIPHER) {
370 
371 			cap_idx.type = RTE_CRYPTO_SYM_XFORM_AUTH;
372 			cap_idx.algo.auth = opts->auth_algo;
373 
374 			capability = rte_cryptodev_sym_capability_get(cdev_id,
375 					&cap_idx);
376 			if (capability == NULL)
377 				return -1;
378 
379 			ret = rte_cryptodev_sym_capability_check_auth(
380 					capability,
381 					opts->auth_key_sz,
382 					opts->digest_sz,
383 					opts->auth_iv_sz);
384 			if (ret != 0)
385 				return ret;
386 		}
387 
388 		if (opts->op_type == CPERF_CIPHER_ONLY ||
389 				opts->op_type == CPERF_CIPHER_THEN_AUTH ||
390 				opts->op_type == CPERF_AUTH_THEN_CIPHER) {
391 
392 			cap_idx.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
393 			cap_idx.algo.cipher = opts->cipher_algo;
394 
395 			capability = rte_cryptodev_sym_capability_get(cdev_id,
396 					&cap_idx);
397 			if (capability == NULL)
398 				return -1;
399 
400 			ret = rte_cryptodev_sym_capability_check_cipher(
401 					capability,
402 					opts->cipher_key_sz,
403 					opts->cipher_iv_sz);
404 			if (ret != 0)
405 				return ret;
406 		}
407 
408 		if (opts->op_type == CPERF_AEAD) {
409 
410 			cap_idx.type = RTE_CRYPTO_SYM_XFORM_AEAD;
411 			cap_idx.algo.aead = opts->aead_algo;
412 
413 			capability = rte_cryptodev_sym_capability_get(cdev_id,
414 					&cap_idx);
415 			if (capability == NULL)
416 				return -1;
417 
418 			ret = rte_cryptodev_sym_capability_check_aead(
419 					capability,
420 					opts->aead_key_sz,
421 					opts->digest_sz,
422 					opts->aead_aad_sz,
423 					opts->aead_iv_sz);
424 			if (ret != 0)
425 				return ret;
426 		}
427 	}
428 
429 	return 0;
430 }
431 
432 static int
433 cperf_check_test_vector(struct cperf_options *opts,
434 		struct cperf_test_vector *test_vec)
435 {
436 	if (opts->op_type == CPERF_CIPHER_ONLY) {
437 		if (opts->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
438 			if (test_vec->plaintext.data == NULL)
439 				return -1;
440 		} else {
441 			if (test_vec->plaintext.data == NULL)
442 				return -1;
443 			if (test_vec->plaintext.length < opts->max_buffer_size)
444 				return -1;
445 			if (test_vec->ciphertext.data == NULL)
446 				return -1;
447 			if (test_vec->ciphertext.length < opts->max_buffer_size)
448 				return -1;
449 			/* Cipher IV is only required for some algorithms */
450 			if (opts->cipher_iv_sz &&
451 					test_vec->cipher_iv.data == NULL)
452 				return -1;
453 			if (test_vec->cipher_iv.length != opts->cipher_iv_sz)
454 				return -1;
455 			if (test_vec->cipher_key.data == NULL)
456 				return -1;
457 			if (test_vec->cipher_key.length != opts->cipher_key_sz)
458 				return -1;
459 		}
460 	} else if (opts->op_type == CPERF_AUTH_ONLY) {
461 		if (opts->auth_algo != RTE_CRYPTO_AUTH_NULL) {
462 			if (test_vec->plaintext.data == NULL)
463 				return -1;
464 			if (test_vec->plaintext.length < opts->max_buffer_size)
465 				return -1;
466 			/* Auth key is only required for some algorithms */
467 			if (opts->auth_key_sz &&
468 					test_vec->auth_key.data == NULL)
469 				return -1;
470 			if (test_vec->auth_key.length != opts->auth_key_sz)
471 				return -1;
472 			if (test_vec->auth_iv.length != opts->auth_iv_sz)
473 				return -1;
474 			/* Auth IV is only required for some algorithms */
475 			if (opts->auth_iv_sz && test_vec->auth_iv.data == NULL)
476 				return -1;
477 			if (test_vec->digest.data == NULL)
478 				return -1;
479 			if (test_vec->digest.length < opts->digest_sz)
480 				return -1;
481 		}
482 
483 	} else if (opts->op_type == CPERF_CIPHER_THEN_AUTH ||
484 			opts->op_type == CPERF_AUTH_THEN_CIPHER) {
485 		if (opts->cipher_algo == RTE_CRYPTO_CIPHER_NULL) {
486 			if (test_vec->plaintext.data == NULL)
487 				return -1;
488 			if (test_vec->plaintext.length < opts->max_buffer_size)
489 				return -1;
490 		} else {
491 			if (test_vec->plaintext.data == NULL)
492 				return -1;
493 			if (test_vec->plaintext.length < opts->max_buffer_size)
494 				return -1;
495 			if (test_vec->ciphertext.data == NULL)
496 				return -1;
497 			if (test_vec->ciphertext.length < opts->max_buffer_size)
498 				return -1;
499 			if (test_vec->cipher_iv.data == NULL)
500 				return -1;
501 			if (test_vec->cipher_iv.length != opts->cipher_iv_sz)
502 				return -1;
503 			if (test_vec->cipher_key.data == NULL)
504 				return -1;
505 			if (test_vec->cipher_key.length != opts->cipher_key_sz)
506 				return -1;
507 		}
508 		if (opts->auth_algo != RTE_CRYPTO_AUTH_NULL) {
509 			if (test_vec->auth_key.data == NULL)
510 				return -1;
511 			if (test_vec->auth_key.length != opts->auth_key_sz)
512 				return -1;
513 			if (test_vec->auth_iv.length != opts->auth_iv_sz)
514 				return -1;
515 			/* Auth IV is only required for some algorithms */
516 			if (opts->auth_iv_sz && test_vec->auth_iv.data == NULL)
517 				return -1;
518 			if (test_vec->digest.data == NULL)
519 				return -1;
520 			if (test_vec->digest.length < opts->digest_sz)
521 				return -1;
522 		}
523 	} else if (opts->op_type == CPERF_AEAD) {
524 		if (test_vec->plaintext.data == NULL)
525 			return -1;
526 		if (test_vec->plaintext.length < opts->max_buffer_size)
527 			return -1;
528 		if (test_vec->ciphertext.data == NULL)
529 			return -1;
530 		if (test_vec->ciphertext.length < opts->max_buffer_size)
531 			return -1;
532 		if (test_vec->aead_key.data == NULL)
533 			return -1;
534 		if (test_vec->aead_key.length != opts->aead_key_sz)
535 			return -1;
536 		if (test_vec->aead_iv.data == NULL)
537 			return -1;
538 		if (test_vec->aead_iv.length != opts->aead_iv_sz)
539 			return -1;
540 		if (test_vec->aad.data == NULL)
541 			return -1;
542 		if (test_vec->aad.length != opts->aead_aad_sz)
543 			return -1;
544 		if (test_vec->digest.data == NULL)
545 			return -1;
546 		if (test_vec->digest.length < opts->digest_sz)
547 			return -1;
548 	}
549 	return 0;
550 }
551 
552 int
553 main(int argc, char **argv)
554 {
555 	struct cperf_options opts = {0};
556 	struct cperf_test_vector *t_vec = NULL;
557 	struct cperf_op_fns op_fns;
558 	void *ctx[RTE_MAX_LCORE] = { };
559 	int nb_cryptodevs = 0;
560 	uint16_t total_nb_qps = 0;
561 	uint8_t cdev_id, i;
562 	uint8_t enabled_cdevs[RTE_CRYPTO_MAX_DEVS] = { 0 };
563 
564 	uint8_t buffer_size_idx = 0;
565 
566 	int ret;
567 	uint32_t lcore_id;
568 
569 	/* Initialise DPDK EAL */
570 	ret = rte_eal_init(argc, argv);
571 	if (ret < 0)
572 		rte_exit(EXIT_FAILURE, "Invalid EAL arguments!\n");
573 	argc -= ret;
574 	argv += ret;
575 
576 	cperf_options_default(&opts);
577 
578 	ret = cperf_options_parse(&opts, argc, argv);
579 	if (ret) {
580 		RTE_LOG(ERR, USER1, "Parsing one or more user options failed\n");
581 		goto err;
582 	}
583 
584 	ret = cperf_options_check(&opts);
585 	if (ret) {
586 		RTE_LOG(ERR, USER1,
587 				"Checking one or more user options failed\n");
588 		goto err;
589 	}
590 
591 	nb_cryptodevs = cperf_initialize_cryptodev(&opts, enabled_cdevs);
592 
593 	if (!opts.silent)
594 		cperf_options_dump(&opts);
595 
596 	if (nb_cryptodevs < 1) {
597 		RTE_LOG(ERR, USER1, "Failed to initialise requested crypto "
598 				"device type\n");
599 		nb_cryptodevs = 0;
600 		goto err;
601 	}
602 
603 	ret = cperf_verify_devices_capabilities(&opts, enabled_cdevs,
604 			nb_cryptodevs);
605 	if (ret) {
606 		RTE_LOG(ERR, USER1, "Crypto device type does not support "
607 				"capabilities requested\n");
608 		goto err;
609 	}
610 
611 	if (opts.test_file != NULL) {
612 		t_vec = cperf_test_vector_get_from_file(&opts);
613 		if (t_vec == NULL) {
614 			RTE_LOG(ERR, USER1,
615 					"Failed to create test vector for"
616 					" specified file\n");
617 			goto err;
618 		}
619 
620 		if (cperf_check_test_vector(&opts, t_vec)) {
621 			RTE_LOG(ERR, USER1, "Incomplete necessary test vectors"
622 					"\n");
623 			goto err;
624 		}
625 	} else {
626 		t_vec = cperf_test_vector_get_dummy(&opts);
627 		if (t_vec == NULL) {
628 			RTE_LOG(ERR, USER1,
629 					"Failed to create test vector for"
630 					" specified algorithms\n");
631 			goto err;
632 		}
633 	}
634 
635 	ret = cperf_get_op_functions(&opts, &op_fns);
636 	if (ret) {
637 		RTE_LOG(ERR, USER1, "Failed to find function ops set for "
638 				"specified algorithms combination\n");
639 		goto err;
640 	}
641 
642 	if (!opts.silent && opts.test != CPERF_TEST_TYPE_THROUGHPUT &&
643 			opts.test != CPERF_TEST_TYPE_LATENCY)
644 		show_test_vector(t_vec);
645 
646 	total_nb_qps = nb_cryptodevs * opts.nb_qps;
647 
648 	i = 0;
649 	uint8_t qp_id = 0, cdev_index = 0;
650 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
651 
652 		if (i == total_nb_qps)
653 			break;
654 
655 		cdev_id = enabled_cdevs[cdev_index];
656 
657 		uint8_t socket_id = rte_cryptodev_socket_id(cdev_id);
658 
659 		ctx[i] = cperf_testmap[opts.test].constructor(
660 				session_pool_socket[socket_id].sess_mp,
661 				cdev_id, qp_id,
662 				&opts, t_vec, &op_fns);
663 		if (ctx[i] == NULL) {
664 			RTE_LOG(ERR, USER1, "Test run constructor failed\n");
665 			goto err;
666 		}
667 		qp_id = (qp_id + 1) % opts.nb_qps;
668 		if (qp_id == 0)
669 			cdev_index++;
670 		i++;
671 	}
672 
673 	if (opts.imix_distribution_count != 0) {
674 		uint8_t buffer_size_count = opts.buffer_size_count;
675 		uint16_t distribution_total[buffer_size_count];
676 		uint32_t op_idx;
677 		uint32_t test_average_size = 0;
678 		const uint32_t *buffer_size_list = opts.buffer_size_list;
679 		const uint32_t *imix_distribution_list = opts.imix_distribution_list;
680 
681 		opts.imix_buffer_sizes = rte_malloc(NULL,
682 					sizeof(uint32_t) * opts.pool_sz,
683 					0);
684 		/*
685 		 * Calculate accumulated distribution of
686 		 * probabilities per packet size
687 		 */
688 		distribution_total[0] = imix_distribution_list[0];
689 		for (i = 1; i < buffer_size_count; i++)
690 			distribution_total[i] = imix_distribution_list[i] +
691 				distribution_total[i-1];
692 
693 		/* Calculate a random sequence of packet sizes, based on distribution */
694 		for (op_idx = 0; op_idx < opts.pool_sz; op_idx++) {
695 			uint16_t random_number = rte_rand() %
696 				distribution_total[buffer_size_count - 1];
697 			for (i = 0; i < buffer_size_count; i++)
698 				if (random_number < distribution_total[i])
699 					break;
700 
701 			opts.imix_buffer_sizes[op_idx] = buffer_size_list[i];
702 		}
703 
704 		/* Calculate average buffer size for the IMIX distribution */
705 		for (i = 0; i < buffer_size_count; i++)
706 			test_average_size += buffer_size_list[i] *
707 				imix_distribution_list[i];
708 
709 		opts.test_buffer_size = test_average_size /
710 				distribution_total[buffer_size_count - 1];
711 
712 		i = 0;
713 		RTE_LCORE_FOREACH_WORKER(lcore_id) {
714 
715 			if (i == total_nb_qps)
716 				break;
717 
718 			rte_eal_remote_launch(cperf_testmap[opts.test].runner,
719 				ctx[i], lcore_id);
720 			i++;
721 		}
722 		i = 0;
723 		RTE_LCORE_FOREACH_WORKER(lcore_id) {
724 
725 			if (i == total_nb_qps)
726 				break;
727 			ret |= rte_eal_wait_lcore(lcore_id);
728 			i++;
729 		}
730 
731 		if (ret != EXIT_SUCCESS)
732 			goto err;
733 	} else {
734 
735 		/* Get next size from range or list */
736 		if (opts.inc_buffer_size != 0)
737 			opts.test_buffer_size = opts.min_buffer_size;
738 		else
739 			opts.test_buffer_size = opts.buffer_size_list[0];
740 
741 		while (opts.test_buffer_size <= opts.max_buffer_size) {
742 			i = 0;
743 			RTE_LCORE_FOREACH_WORKER(lcore_id) {
744 
745 				if (i == total_nb_qps)
746 					break;
747 
748 				rte_eal_remote_launch(cperf_testmap[opts.test].runner,
749 					ctx[i], lcore_id);
750 				i++;
751 			}
752 			i = 0;
753 			RTE_LCORE_FOREACH_WORKER(lcore_id) {
754 
755 				if (i == total_nb_qps)
756 					break;
757 				ret |= rte_eal_wait_lcore(lcore_id);
758 				i++;
759 			}
760 
761 			if (ret != EXIT_SUCCESS)
762 				goto err;
763 
764 			/* Get next size from range or list */
765 			if (opts.inc_buffer_size != 0)
766 				opts.test_buffer_size += opts.inc_buffer_size;
767 			else {
768 				if (++buffer_size_idx == opts.buffer_size_count)
769 					break;
770 				opts.test_buffer_size =
771 					opts.buffer_size_list[buffer_size_idx];
772 			}
773 		}
774 	}
775 
776 	i = 0;
777 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
778 
779 		if (i == total_nb_qps)
780 			break;
781 
782 		cperf_testmap[opts.test].destructor(ctx[i]);
783 		i++;
784 	}
785 
786 	for (i = 0; i < nb_cryptodevs &&
787 			i < RTE_CRYPTO_MAX_DEVS; i++) {
788 		rte_cryptodev_stop(enabled_cdevs[i]);
789 		ret = rte_cryptodev_close(enabled_cdevs[i]);
790 		if (ret)
791 			RTE_LOG(ERR, USER1,
792 					"Crypto device close error %d\n", ret);
793 	}
794 
795 	free_test_vector(t_vec, &opts);
796 
797 	printf("\n");
798 	return EXIT_SUCCESS;
799 
800 err:
801 	i = 0;
802 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
803 		if (i == total_nb_qps)
804 			break;
805 
806 		if (ctx[i] && cperf_testmap[opts.test].destructor)
807 			cperf_testmap[opts.test].destructor(ctx[i]);
808 		i++;
809 	}
810 
811 	for (i = 0; i < nb_cryptodevs &&
812 			i < RTE_CRYPTO_MAX_DEVS; i++) {
813 		rte_cryptodev_stop(enabled_cdevs[i]);
814 		ret = rte_cryptodev_close(enabled_cdevs[i]);
815 		if (ret)
816 			RTE_LOG(ERR, USER1,
817 					"Crypto device close error %d\n", ret);
818 
819 	}
820 	rte_free(opts.imix_buffer_sizes);
821 	free_test_vector(t_vec, &opts);
822 
823 	printf("\n");
824 	return EXIT_FAILURE;
825 }
826