xref: /dpdk/app/test-compress-perf/main.c (revision 72c64a3492ba7b41bc1074e016684643c30be04d)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Intel Corporation
3  */
4 
5 #include <stdlib.h>
6 #include <signal.h>
7 #include <sys/types.h>
8 #include <unistd.h>
9 
10 #include <rte_malloc.h>
11 #include <rte_eal.h>
12 #include <rte_log.h>
13 #include <rte_compressdev.h>
14 
15 #include "comp_perf.h"
16 #include "comp_perf_options.h"
17 #include "comp_perf_test_common.h"
18 #include "comp_perf_test_cyclecount.h"
19 #include "comp_perf_test_throughput.h"
20 #include "comp_perf_test_verify.h"
21 
22 #define NUM_MAX_XFORMS 16
23 #define NUM_MAX_INFLIGHT_OPS 512
24 
25 __extension__
26 const char *comp_perf_test_type_strs[] = {
27 	[CPERF_TEST_TYPE_THROUGHPUT] = "throughput",
28 	[CPERF_TEST_TYPE_VERIFY] = "verify",
29 	[CPERF_TEST_TYPE_PMDCC] = "pmd-cyclecount"
30 };
31 
32 __extension__
33 static const struct cperf_test cperf_testmap[] = {
34 	[CPERF_TEST_TYPE_THROUGHPUT] = {
35 			cperf_throughput_test_constructor,
36 			cperf_throughput_test_runner,
37 			cperf_throughput_test_destructor
38 
39 	},
40 	[CPERF_TEST_TYPE_VERIFY] = {
41 			cperf_verify_test_constructor,
42 			cperf_verify_test_runner,
43 			cperf_verify_test_destructor
44 	},
45 
46 	[CPERF_TEST_TYPE_PMDCC] = {
47 			cperf_cyclecount_test_constructor,
48 			cperf_cyclecount_test_runner,
49 			cperf_cyclecount_test_destructor
50 	}
51 };
52 
53 static struct comp_test_data *test_data;
54 
55 static int
comp_perf_check_capabilities(struct comp_test_data * test_data,uint8_t cdev_id)56 comp_perf_check_capabilities(struct comp_test_data *test_data, uint8_t cdev_id)
57 {
58 	const struct rte_compressdev_capabilities *cap;
59 
60 	cap = rte_compressdev_capability_get(cdev_id, test_data->test_algo);
61 
62 	if (cap == NULL) {
63 		RTE_LOG(ERR, USER1,
64 			"Compress device does not support %u algorithm\n",
65 			test_data->test_algo);
66 		return -1;
67 	}
68 
69 	uint64_t comp_flags = cap->comp_feature_flags;
70 
71 	/* Algorithm type */
72 	switch (test_data->test_algo) {
73 	case RTE_COMP_ALGO_DEFLATE:
74 		/* Huffman encoding */
75 		if (test_data->huffman_enc == RTE_COMP_HUFFMAN_FIXED &&
76 		    (comp_flags & RTE_COMP_FF_HUFFMAN_FIXED) == 0) {
77 			RTE_LOG(ERR, USER1,
78 				"Compress device does not supported Fixed Huffman\n");
79 			return -1;
80 		}
81 
82 		if (test_data->huffman_enc == RTE_COMP_HUFFMAN_DYNAMIC &&
83 		    (comp_flags & RTE_COMP_FF_HUFFMAN_DYNAMIC) == 0) {
84 			RTE_LOG(ERR, USER1,
85 				"Compress device does not supported Dynamic Huffman\n");
86 			return -1;
87 		}
88 		break;
89 	case RTE_COMP_ALGO_LZ4:
90 		/* LZ4 flags */
91 		if ((test_data->lz4_flags & RTE_COMP_LZ4_FLAG_BLOCK_CHECKSUM) &&
92 		    (comp_flags & RTE_COMP_FF_LZ4_BLOCK_WITH_CHECKSUM) == 0) {
93 			RTE_LOG(ERR, USER1,
94 				"Compress device does not support LZ4 block with checksum\n");
95 			return -1;
96 		}
97 
98 		if ((test_data->lz4_flags &
99 		     RTE_COMP_LZ4_FLAG_BLOCK_INDEPENDENCE) &&
100 		    (comp_flags & RTE_COMP_FF_LZ4_BLOCK_INDEPENDENCE) == 0) {
101 			RTE_LOG(ERR, USER1,
102 				"Compress device does not support LZ4 independent blocks\n");
103 			return -1;
104 		}
105 		break;
106 	case RTE_COMP_ALGO_LZS:
107 	case RTE_COMP_ALGO_NULL:
108 		break;
109 	default:
110 		return -1;
111 	}
112 
113 	/* Window size */
114 	if (test_data->window_sz != -1) {
115 		if (param_range_check(test_data->window_sz, &cap->window_size)
116 				< 0) {
117 			RTE_LOG(ERR, USER1,
118 				"Compress device does not support "
119 				"this window size\n");
120 			return -1;
121 		}
122 	} else
123 		/* Set window size to PMD maximum if none was specified */
124 		test_data->window_sz = cap->window_size.max;
125 
126 	/* Check if chained mbufs is supported */
127 	if (test_data->max_sgl_segs > 1  &&
128 			(comp_flags & RTE_COMP_FF_OOP_SGL_IN_SGL_OUT) == 0) {
129 		RTE_LOG(INFO, USER1, "Compress device does not support "
130 				"chained mbufs. Max SGL segments set to 1\n");
131 		test_data->max_sgl_segs = 1;
132 	}
133 
134 	/* Level 0 support */
135 	if (test_data->level_lst.min == 0 &&
136 			(comp_flags & RTE_COMP_FF_NONCOMPRESSED_BLOCKS) == 0) {
137 		RTE_LOG(ERR, USER1, "Compress device does not support "
138 				"level 0 (no compression)\n");
139 		return -1;
140 	}
141 
142 	return 0;
143 }
144 
145 static int
comp_perf_initialize_compressdev(struct comp_test_data * test_data,uint8_t * enabled_cdevs)146 comp_perf_initialize_compressdev(struct comp_test_data *test_data,
147 				 uint8_t *enabled_cdevs)
148 {
149 	uint8_t enabled_cdev_count, nb_lcores, cdev_id;
150 	unsigned int i, j;
151 	int ret;
152 
153 	enabled_cdev_count = rte_compressdev_devices_get(test_data->driver_name,
154 			enabled_cdevs, RTE_COMPRESS_MAX_DEVS);
155 	if (enabled_cdev_count == 0) {
156 		RTE_LOG(ERR, USER1, "No compress devices type %s available,"
157 				    " please check the list of specified devices in EAL section\n",
158 				test_data->driver_name);
159 		return -EINVAL;
160 	}
161 
162 	nb_lcores = rte_lcore_count() - 1;
163 	/*
164 	 * Use fewer devices,
165 	 * if there are more available than cores.
166 	 */
167 	if (enabled_cdev_count > nb_lcores) {
168 		if (nb_lcores == 0) {
169 			RTE_LOG(ERR, USER1, "Cannot run with 0 cores! Increase the number of cores\n");
170 			return -EINVAL;
171 		}
172 		enabled_cdev_count = nb_lcores;
173 		RTE_LOG(INFO, USER1,
174 			"There's more available devices than cores!"
175 			" The number of devices has been aligned to %d cores\n",
176 			nb_lcores);
177 	}
178 
179 	/*
180 	 * Calculate number of needed queue pairs, based on the amount
181 	 * of available number of logical cores and compression devices.
182 	 * For instance, if there are 4 cores and 2 compression devices,
183 	 * 2 queue pairs will be set up per device.
184 	 * One queue pair per one core.
185 	 * if e.g.: there're 3 cores and 2 compression devices,
186 	 * 2 queue pairs will be set up per device but one queue pair
187 	 * will left unused in the last one device
188 	 */
189 	test_data->nb_qps = (nb_lcores % enabled_cdev_count) ?
190 				(nb_lcores / enabled_cdev_count) + 1 :
191 				nb_lcores / enabled_cdev_count;
192 
193 	for (i = 0; i < enabled_cdev_count &&
194 			i < RTE_COMPRESS_MAX_DEVS; i++,
195 					nb_lcores -= test_data->nb_qps) {
196 		cdev_id = enabled_cdevs[i];
197 
198 		struct rte_compressdev_info cdev_info;
199 		int socket_id = rte_compressdev_socket_id(cdev_id);
200 
201 		rte_compressdev_info_get(cdev_id, &cdev_info);
202 		if (cdev_info.max_nb_queue_pairs &&
203 			test_data->nb_qps > cdev_info.max_nb_queue_pairs) {
204 			RTE_LOG(ERR, USER1,
205 				"Number of needed queue pairs is higher "
206 				"than the maximum number of queue pairs "
207 				"per device.\n");
208 			RTE_LOG(ERR, USER1,
209 				"Lower the number of cores or increase "
210 				"the number of crypto devices\n");
211 			return -EINVAL;
212 		}
213 
214 		if (comp_perf_check_capabilities(test_data, cdev_id) < 0)
215 			return -EINVAL;
216 
217 		/* Configure compressdev */
218 		struct rte_compressdev_config config = {
219 			.socket_id = socket_id,
220 			.nb_queue_pairs = nb_lcores > test_data->nb_qps
221 					? test_data->nb_qps : nb_lcores,
222 			.max_nb_priv_xforms = NUM_MAX_XFORMS,
223 			.max_nb_streams = 0
224 		};
225 		test_data->nb_qps = config.nb_queue_pairs;
226 
227 		if (rte_compressdev_configure(cdev_id, &config) < 0) {
228 			RTE_LOG(ERR, USER1, "Device configuration failed\n");
229 			return -EINVAL;
230 		}
231 
232 		for (j = 0; j < test_data->nb_qps; j++) {
233 			ret = rte_compressdev_queue_pair_setup(cdev_id, j,
234 					NUM_MAX_INFLIGHT_OPS, socket_id);
235 			if (ret < 0) {
236 				RTE_LOG(ERR, USER1,
237 			      "Failed to setup queue pair %u on compressdev %u",
238 					j, cdev_id);
239 				return -EINVAL;
240 			}
241 		}
242 
243 		ret = rte_compressdev_start(cdev_id);
244 		if (ret < 0) {
245 			RTE_LOG(ERR, USER1,
246 				"Failed to start device %u: error %d\n",
247 				cdev_id, ret);
248 			return -EPERM;
249 		}
250 	}
251 
252 	return enabled_cdev_count;
253 }
254 
255 static int
comp_perf_dump_input_data(struct comp_test_data * test_data)256 comp_perf_dump_input_data(struct comp_test_data *test_data)
257 {
258 	FILE *f = fopen(test_data->input_file, "r");
259 	int ret = -1;
260 
261 	if (f == NULL) {
262 		RTE_LOG(ERR, USER1, "Input file could not be opened\n");
263 		return -1;
264 	}
265 
266 	if (fseek(f, 0, SEEK_END) != 0) {
267 		RTE_LOG(ERR, USER1, "Size of input could not be calculated\n");
268 		goto end;
269 	}
270 	size_t actual_file_sz = ftell(f);
271 	/* If extended input data size has not been set,
272 	 * input data size = file size
273 	 */
274 
275 	if (test_data->input_data_sz == 0)
276 		test_data->input_data_sz = actual_file_sz;
277 
278 	if (test_data->input_data_sz <= 0 || actual_file_sz <= 0 ||
279 			fseek(f, 0, SEEK_SET) != 0) {
280 		RTE_LOG(ERR, USER1, "Size of input could not be calculated\n");
281 		goto end;
282 	}
283 
284 	if (!(test_data->test_op & COMPRESS) &&
285 	    test_data->input_data_sz >
286 	    (size_t) test_data->seg_sz * (size_t) test_data->max_sgl_segs) {
287 		RTE_LOG(ERR, USER1,
288 			"Size of input must be less than total segments\n");
289 		goto end;
290 	}
291 
292 	test_data->input_data = rte_zmalloc_socket(NULL,
293 				test_data->input_data_sz, 0, rte_socket_id());
294 
295 	if (test_data->input_data == NULL) {
296 		RTE_LOG(ERR, USER1, "Memory to hold the data from the input "
297 				"file could not be allocated\n");
298 		goto end;
299 	}
300 
301 	size_t remaining_data = test_data->input_data_sz;
302 	uint8_t *data = test_data->input_data;
303 
304 	while (remaining_data > 0) {
305 		size_t data_to_read = RTE_MIN(remaining_data, actual_file_sz);
306 
307 		if (fread(data, data_to_read, 1, f) != 1) {
308 			RTE_LOG(ERR, USER1, "Input file could not be read\n");
309 			goto end;
310 		}
311 		if (fseek(f, 0, SEEK_SET) != 0) {
312 			RTE_LOG(ERR, USER1,
313 				"Size of input could not be calculated\n");
314 			goto end;
315 		}
316 		remaining_data -= data_to_read;
317 		data += data_to_read;
318 	}
319 
320 	printf("\n");
321 	if (test_data->input_data_sz > actual_file_sz)
322 		RTE_LOG(INFO, USER1,
323 		  "%zu bytes read from file %s, extending the file %.2f times\n",
324 			test_data->input_data_sz, test_data->input_file,
325 			(double)test_data->input_data_sz/actual_file_sz);
326 	else
327 		RTE_LOG(INFO, USER1,
328 			"%zu bytes read from file %s\n",
329 			test_data->input_data_sz, test_data->input_file);
330 
331 	ret = 0;
332 
333 end:
334 	fclose(f);
335 	return ret;
336 }
337 
338 static void
comp_perf_cleanup_on_signal(int signalNumber __rte_unused)339 comp_perf_cleanup_on_signal(int signalNumber __rte_unused)
340 {
341 	test_data->perf_comp_force_stop = 1;
342 }
343 
344 static void
comp_perf_register_cleanup_on_signal(void)345 comp_perf_register_cleanup_on_signal(void)
346 {
347 	signal(SIGTERM, comp_perf_cleanup_on_signal);
348 	signal(SIGINT, comp_perf_cleanup_on_signal);
349 }
350 
351 int
main(int argc,char ** argv)352 main(int argc, char **argv)
353 {
354 	uint8_t level_idx = 0;
355 	int ret, i;
356 	void *ctx[RTE_MAX_LCORE] = {};
357 	uint8_t enabled_cdevs[RTE_COMPRESS_MAX_DEVS];
358 	int nb_compressdevs = 0;
359 	uint16_t total_nb_qps = 0;
360 	uint8_t cdev_id;
361 	uint32_t lcore_id;
362 
363 	/* Initialise DPDK EAL */
364 	ret = rte_eal_init(argc, argv);
365 	if (ret < 0)
366 		rte_exit(EXIT_FAILURE, "Invalid EAL arguments!\n");
367 	argc -= ret;
368 	argv += ret;
369 
370 	test_data = rte_zmalloc_socket(NULL, sizeof(struct comp_test_data),
371 					0, rte_socket_id());
372 
373 	if (test_data == NULL)
374 		rte_exit(EXIT_FAILURE, "Cannot reserve memory in socket %d\n",
375 				rte_socket_id());
376 
377 	comp_perf_register_cleanup_on_signal();
378 
379 	ret = EXIT_SUCCESS;
380 	test_data->cleanup = ST_TEST_DATA;
381 	comp_perf_options_default(test_data);
382 
383 	if (comp_perf_options_parse(test_data, argc, argv) < 0) {
384 		RTE_LOG(ERR, USER1,
385 			"Parsing one or more user options failed\n");
386 		ret = EXIT_FAILURE;
387 		goto end;
388 	}
389 
390 	if (comp_perf_options_check(test_data) < 0) {
391 		ret = EXIT_FAILURE;
392 		goto end;
393 	}
394 
395 	nb_compressdevs =
396 		comp_perf_initialize_compressdev(test_data, enabled_cdevs);
397 
398 	if (nb_compressdevs < 1) {
399 		ret = EXIT_FAILURE;
400 		goto end;
401 	}
402 
403 	test_data->cleanup = ST_COMPDEV;
404 	if (comp_perf_dump_input_data(test_data) < 0) {
405 		ret = EXIT_FAILURE;
406 		goto end;
407 	}
408 
409 	test_data->cleanup = ST_INPUT_DATA;
410 
411 	if (test_data->level_lst.inc != 0)
412 		test_data->level = test_data->level_lst.min;
413 	else
414 		test_data->level = test_data->level_lst.list[0];
415 
416 	printf("\nApp uses socket: %u\n", rte_socket_id());
417 	printf("Burst size = %u\n", test_data->burst_sz);
418 	printf("Input data size = %zu\n", test_data->input_data_sz);
419 	if (test_data->test == CPERF_TEST_TYPE_PMDCC)
420 		printf("Cycle-count delay = %u [us]\n",
421 		       test_data->cyclecount_delay);
422 
423 	test_data->cleanup = ST_DURING_TEST;
424 	total_nb_qps = nb_compressdevs * test_data->nb_qps;
425 
426 	i = 0;
427 	uint8_t qp_id = 0, cdev_index = 0;
428 
429 	RTE_LCORE_FOREACH_WORKER(lcore_id) {
430 
431 		if (i == total_nb_qps)
432 			break;
433 
434 		cdev_id = enabled_cdevs[cdev_index];
435 		ctx[i] = cperf_testmap[test_data->test].constructor(
436 							cdev_id, qp_id,
437 							test_data);
438 		if (ctx[i] == NULL) {
439 			RTE_LOG(ERR, USER1, "Test run constructor failed\n");
440 			goto end;
441 		}
442 		qp_id = (qp_id + 1) % test_data->nb_qps;
443 		if (qp_id == 0)
444 			cdev_index++;
445 		i++;
446 	}
447 
448 	print_test_dynamics(test_data);
449 
450 	while (test_data->level <= test_data->level_lst.max) {
451 
452 		i = 0;
453 		RTE_LCORE_FOREACH_WORKER(lcore_id) {
454 
455 			if (i == total_nb_qps)
456 				break;
457 
458 			rte_eal_remote_launch(
459 					cperf_testmap[test_data->test].runner,
460 					ctx[i], lcore_id);
461 			i++;
462 		}
463 		i = 0;
464 		RTE_LCORE_FOREACH_WORKER(lcore_id) {
465 
466 			if (i == total_nb_qps)
467 				break;
468 			ret |= rte_eal_wait_lcore(lcore_id);
469 			i++;
470 		}
471 
472 		if (ret != EXIT_SUCCESS)
473 			break;
474 
475 		if (test_data->level_lst.inc != 0)
476 			test_data->level += test_data->level_lst.inc;
477 		else {
478 			if (++level_idx == test_data->level_lst.count)
479 				break;
480 			test_data->level = test_data->level_lst.list[level_idx];
481 		}
482 	}
483 
484 end:
485 	switch (test_data->cleanup) {
486 
487 	case ST_DURING_TEST:
488 		i = 0;
489 		RTE_LCORE_FOREACH_WORKER(lcore_id) {
490 			if (i == total_nb_qps)
491 				break;
492 
493 			if (ctx[i] && cperf_testmap[test_data->test].destructor)
494 				cperf_testmap[test_data->test].destructor(
495 									ctx[i]);
496 			i++;
497 		}
498 		/* fallthrough */
499 	case ST_INPUT_DATA:
500 		rte_free(test_data->input_data);
501 		/* fallthrough */
502 	case ST_COMPDEV:
503 		for (i = 0; i < nb_compressdevs &&
504 		     i < RTE_COMPRESS_MAX_DEVS; i++) {
505 			rte_compressdev_stop(enabled_cdevs[i]);
506 			rte_compressdev_close(enabled_cdevs[i]);
507 		}
508 		/* fallthrough */
509 	case ST_TEST_DATA:
510 		rte_free(test_data);
511 		/* fallthrough */
512 	case ST_CLEAR:
513 	default:
514 		i = rte_eal_cleanup();
515 		if (i) {
516 			RTE_LOG(ERR, USER1,
517 				"Error from rte_eal_cleanup(), %d\n", i);
518 			ret = i;
519 		}
520 		break;
521 	}
522 	return ret;
523 }
524 
525 __rte_weak void *
cperf_cyclecount_test_constructor(uint8_t dev_id __rte_unused,uint16_t qp_id __rte_unused,struct comp_test_data * options __rte_unused)526 cperf_cyclecount_test_constructor(uint8_t dev_id __rte_unused,
527 				 uint16_t qp_id __rte_unused,
528 				 struct comp_test_data *options __rte_unused)
529 {
530 	RTE_LOG(INFO, USER1, "Cycle count test is not supported yet\n");
531 	return NULL;
532 }
533 
534 __rte_weak void
cperf_cyclecount_test_destructor(void * arg __rte_unused)535 cperf_cyclecount_test_destructor(void *arg __rte_unused)
536 {
537 	RTE_LOG(INFO, USER1, "Something wrong happened!!!\n");
538 }
539 
540 __rte_weak int
cperf_cyclecount_test_runner(void * test_ctx __rte_unused)541 cperf_cyclecount_test_runner(void *test_ctx __rte_unused)
542 {
543 	return 0;
544 }
545 
546 __rte_weak void *
cperf_throughput_test_constructor(uint8_t dev_id __rte_unused,uint16_t qp_id __rte_unused,struct comp_test_data * options __rte_unused)547 cperf_throughput_test_constructor(uint8_t dev_id __rte_unused,
548 				 uint16_t qp_id __rte_unused,
549 				 struct comp_test_data *options __rte_unused)
550 {
551 	RTE_LOG(INFO, USER1, "Benchmark test is not supported yet\n");
552 	return NULL;
553 }
554 
555 __rte_weak void
cperf_throughput_test_destructor(void * arg __rte_unused)556 cperf_throughput_test_destructor(void *arg __rte_unused)
557 {
558 
559 }
560 
561 __rte_weak int
cperf_throughput_test_runner(void * test_ctx __rte_unused)562 cperf_throughput_test_runner(void *test_ctx __rte_unused)
563 {
564 	return 0;
565 }
566 __rte_weak void *
cperf_verify_test_constructor(uint8_t dev_id __rte_unused,uint16_t qp_id __rte_unused,struct comp_test_data * options __rte_unused)567 cperf_verify_test_constructor(uint8_t dev_id __rte_unused,
568 				 uint16_t qp_id __rte_unused,
569 				 struct comp_test_data *options __rte_unused)
570 {
571 	RTE_LOG(INFO, USER1, "Verify test is not supported yet\n");
572 	return NULL;
573 }
574 
575 __rte_weak void
cperf_verify_test_destructor(void * arg __rte_unused)576 cperf_verify_test_destructor(void *arg __rte_unused)
577 {
578 
579 }
580 
581 __rte_weak int
cperf_verify_test_runner(void * test_ctx __rte_unused)582 cperf_verify_test_runner(void *test_ctx __rte_unused)
583 {
584 	return 0;
585 }
586