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