1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018 Intel Corporation
5 #include <rte_malloc.h>
8 #include <rte_compressdev.h>
10 #include "comp_perf_options.h"
11 #include "comp_perf_test_verify.h"
12 #include "comp_perf_test_benchmark.h"
14 #define NUM_MAX_XFORMS 16
15 #define NUM_MAX_INFLIGHT_OPS 512
17 #define DIV_CEIL(a, b) ((a) / (b) + ((a) % (b) != 0))
19 /* Cleanup state machine */
20 static enum cleanup_st
{
31 param_range_check(uint16_t size
, const struct rte_param_log2_range
*range
)
33 unsigned int next_size
;
35 /* Check lower/upper bounds */
36 if (size
< range
->min
)
39 if (size
> range
->max
)
42 /* If range is actually only one value, size is correct */
43 if (range
->increment
== 0)
46 /* Check if value is one of the supported sizes */
47 for (next_size
= range
->min
; next_size
<= range
->max
;
48 next_size
+= range
->increment
)
49 if (size
== next_size
)
56 comp_perf_check_capabilities(struct comp_test_data
*test_data
)
58 const struct rte_compressdev_capabilities
*cap
;
60 cap
= rte_compressdev_capability_get(test_data
->cdev_id
,
61 RTE_COMP_ALGO_DEFLATE
);
65 "Compress device does not support DEFLATE\n");
69 uint64_t comp_flags
= cap
->comp_feature_flags
;
71 /* Huffman enconding */
72 if (test_data
->huffman_enc
== RTE_COMP_HUFFMAN_FIXED
&&
73 (comp_flags
& RTE_COMP_FF_HUFFMAN_FIXED
) == 0) {
75 "Compress device does not supported Fixed Huffman\n");
79 if (test_data
->huffman_enc
== RTE_COMP_HUFFMAN_DYNAMIC
&&
80 (comp_flags
& RTE_COMP_FF_HUFFMAN_DYNAMIC
) == 0) {
82 "Compress device does not supported Dynamic Huffman\n");
87 if (test_data
->window_sz
!= -1) {
88 if (param_range_check(test_data
->window_sz
, &cap
->window_size
)
91 "Compress device does not support "
92 "this window size\n");
96 /* Set window size to PMD maximum if none was specified */
97 test_data
->window_sz
= cap
->window_size
.max
;
99 /* Check if chained mbufs is supported */
100 if (test_data
->max_sgl_segs
> 1 &&
101 (comp_flags
& RTE_COMP_FF_OOP_SGL_IN_SGL_OUT
) == 0) {
102 RTE_LOG(INFO
, USER1
, "Compress device does not support "
103 "chained mbufs. Max SGL segments set to 1\n");
104 test_data
->max_sgl_segs
= 1;
107 /* Level 0 support */
108 if (test_data
->level
.min
== 0 &&
109 (comp_flags
& RTE_COMP_FF_NONCOMPRESSED_BLOCKS
) == 0) {
110 RTE_LOG(ERR
, USER1
, "Compress device does not support "
111 "level 0 (no compression)\n");
119 find_buf_size(uint32_t input_size
)
123 /* From performance point of view the buffer size should be a
124 * power of 2 but also should be enough to store incompressible data
127 /* We're looking for nearest power of 2 buffer size, which is greather
131 !input_size
? MIN_COMPRESSED_BUF_SIZE
: (input_size
<< 1);
133 for (i
= UINT16_MAX
+ 1; !(i
& size
); i
>>= 1)
136 return i
> ((UINT16_MAX
+ 1) >> 1)
137 ? (uint32_t)((float)input_size
* EXPANSE_RATIO
)
142 comp_perf_allocate_memory(struct comp_test_data
*test_data
)
145 test_data
->out_seg_sz
= find_buf_size(test_data
->seg_sz
);
146 /* Number of segments for input and output
147 * (compression and decompression)
149 uint32_t total_segs
= DIV_CEIL(test_data
->input_data_sz
,
151 test_data
->comp_buf_pool
= rte_pktmbuf_pool_create("comp_buf_pool",
154 test_data
->out_seg_sz
+ RTE_PKTMBUF_HEADROOM
,
156 if (test_data
->comp_buf_pool
== NULL
) {
157 RTE_LOG(ERR
, USER1
, "Mbuf mempool could not be created\n");
161 cleanup
= ST_MEMORY_ALLOC
;
162 test_data
->decomp_buf_pool
= rte_pktmbuf_pool_create("decomp_buf_pool",
164 0, 0, test_data
->seg_sz
+ RTE_PKTMBUF_HEADROOM
,
166 if (test_data
->decomp_buf_pool
== NULL
) {
167 RTE_LOG(ERR
, USER1
, "Mbuf mempool could not be created\n");
171 test_data
->total_bufs
= DIV_CEIL(total_segs
, test_data
->max_sgl_segs
);
173 test_data
->op_pool
= rte_comp_op_pool_create("op_pool",
174 test_data
->total_bufs
,
175 0, 0, rte_socket_id());
176 if (test_data
->op_pool
== NULL
) {
177 RTE_LOG(ERR
, USER1
, "Comp op mempool could not be created\n");
182 * Compressed data might be a bit larger than input data,
183 * if data cannot be compressed
185 test_data
->compressed_data
= rte_zmalloc_socket(NULL
,
186 test_data
->input_data_sz
* EXPANSE_RATIO
187 + MIN_COMPRESSED_BUF_SIZE
, 0,
189 if (test_data
->compressed_data
== NULL
) {
190 RTE_LOG(ERR
, USER1
, "Memory to hold the data from the input "
191 "file could not be allocated\n");
195 test_data
->decompressed_data
= rte_zmalloc_socket(NULL
,
196 test_data
->input_data_sz
, 0,
198 if (test_data
->decompressed_data
== NULL
) {
199 RTE_LOG(ERR
, USER1
, "Memory to hold the data from the input "
200 "file could not be allocated\n");
204 test_data
->comp_bufs
= rte_zmalloc_socket(NULL
,
205 test_data
->total_bufs
* sizeof(struct rte_mbuf
*),
207 if (test_data
->comp_bufs
== NULL
) {
208 RTE_LOG(ERR
, USER1
, "Memory to hold the compression mbufs"
209 " could not be allocated\n");
213 test_data
->decomp_bufs
= rte_zmalloc_socket(NULL
,
214 test_data
->total_bufs
* sizeof(struct rte_mbuf
*),
216 if (test_data
->decomp_bufs
== NULL
) {
217 RTE_LOG(ERR
, USER1
, "Memory to hold the decompression mbufs"
218 " could not be allocated\n");
225 comp_perf_dump_input_data(struct comp_test_data
*test_data
)
227 FILE *f
= fopen(test_data
->input_file
, "r");
231 RTE_LOG(ERR
, USER1
, "Input file could not be opened\n");
235 if (fseek(f
, 0, SEEK_END
) != 0) {
236 RTE_LOG(ERR
, USER1
, "Size of input could not be calculated\n");
239 size_t actual_file_sz
= ftell(f
);
240 /* If extended input data size has not been set,
241 * input data size = file size
244 if (test_data
->input_data_sz
== 0)
245 test_data
->input_data_sz
= actual_file_sz
;
247 if (fseek(f
, 0, SEEK_SET
) != 0) {
248 RTE_LOG(ERR
, USER1
, "Size of input could not be calculated\n");
252 test_data
->input_data
= rte_zmalloc_socket(NULL
,
253 test_data
->input_data_sz
, 0, rte_socket_id());
255 if (test_data
->input_data
== NULL
) {
256 RTE_LOG(ERR
, USER1
, "Memory to hold the data from the input "
257 "file could not be allocated\n");
261 size_t remaining_data
= test_data
->input_data_sz
;
262 uint8_t *data
= test_data
->input_data
;
264 while (remaining_data
> 0) {
265 size_t data_to_read
= RTE_MIN(remaining_data
, actual_file_sz
);
267 if (fread(data
, data_to_read
, 1, f
) != 1) {
268 RTE_LOG(ERR
, USER1
, "Input file could not be read\n");
271 if (fseek(f
, 0, SEEK_SET
) != 0) {
273 "Size of input could not be calculated\n");
276 remaining_data
-= data_to_read
;
277 data
+= data_to_read
;
280 if (test_data
->input_data_sz
> actual_file_sz
)
282 "%zu bytes read from file %s, extending the file %.2f times\n",
283 test_data
->input_data_sz
, test_data
->input_file
,
284 (double)test_data
->input_data_sz
/actual_file_sz
);
287 "%zu bytes read from file %s\n",
288 test_data
->input_data_sz
, test_data
->input_file
);
298 comp_perf_initialize_compressdev(struct comp_test_data
*test_data
)
300 uint8_t enabled_cdev_count
;
301 uint8_t enabled_cdevs
[RTE_COMPRESS_MAX_DEVS
];
303 enabled_cdev_count
= rte_compressdev_devices_get(test_data
->driver_name
,
304 enabled_cdevs
, RTE_COMPRESS_MAX_DEVS
);
305 if (enabled_cdev_count
== 0) {
306 RTE_LOG(ERR
, USER1
, "No compress devices type %s available\n",
307 test_data
->driver_name
);
311 if (enabled_cdev_count
> 1)
313 "Only the first compress device will be used\n");
315 test_data
->cdev_id
= enabled_cdevs
[0];
317 if (comp_perf_check_capabilities(test_data
) < 0)
320 /* Configure compressdev (one device, one queue pair) */
321 struct rte_compressdev_config config
= {
322 .socket_id
= rte_socket_id(),
324 .max_nb_priv_xforms
= NUM_MAX_XFORMS
,
328 if (rte_compressdev_configure(test_data
->cdev_id
, &config
) < 0) {
329 RTE_LOG(ERR
, USER1
, "Device configuration failed\n");
333 if (rte_compressdev_queue_pair_setup(test_data
->cdev_id
, 0,
334 NUM_MAX_INFLIGHT_OPS
, rte_socket_id()) < 0) {
335 RTE_LOG(ERR
, USER1
, "Queue pair setup failed\n");
339 if (rte_compressdev_start(test_data
->cdev_id
) < 0) {
340 RTE_LOG(ERR
, USER1
, "Device could not be started\n");
348 prepare_bufs(struct comp_test_data
*test_data
)
350 uint32_t remaining_data
= test_data
->input_data_sz
;
351 uint8_t *input_data_ptr
= test_data
->input_data
;
356 for (i
= 0; i
< test_data
->total_bufs
; i
++) {
357 /* Allocate data in input mbuf and copy data from input file */
358 test_data
->decomp_bufs
[i
] =
359 rte_pktmbuf_alloc(test_data
->decomp_buf_pool
);
360 if (test_data
->decomp_bufs
[i
] == NULL
) {
361 RTE_LOG(ERR
, USER1
, "Could not allocate mbuf\n");
365 cleanup
= ST_PREPARE_BUF
;
366 data_sz
= RTE_MIN(remaining_data
, test_data
->seg_sz
);
367 data_addr
= (uint8_t *) rte_pktmbuf_append(
368 test_data
->decomp_bufs
[i
], data_sz
);
369 if (data_addr
== NULL
) {
370 RTE_LOG(ERR
, USER1
, "Could not append data\n");
373 rte_memcpy(data_addr
, input_data_ptr
, data_sz
);
375 input_data_ptr
+= data_sz
;
376 remaining_data
-= data_sz
;
378 /* Already one segment in the mbuf */
379 uint16_t segs_per_mbuf
= 1;
381 /* Chain mbufs if needed for input mbufs */
382 while (segs_per_mbuf
< test_data
->max_sgl_segs
383 && remaining_data
> 0) {
384 struct rte_mbuf
*next_seg
=
385 rte_pktmbuf_alloc(test_data
->decomp_buf_pool
);
387 if (next_seg
== NULL
) {
389 "Could not allocate mbuf\n");
393 data_sz
= RTE_MIN(remaining_data
, test_data
->seg_sz
);
394 data_addr
= (uint8_t *)rte_pktmbuf_append(next_seg
,
397 if (data_addr
== NULL
) {
398 RTE_LOG(ERR
, USER1
, "Could not append data\n");
402 rte_memcpy(data_addr
, input_data_ptr
, data_sz
);
403 input_data_ptr
+= data_sz
;
404 remaining_data
-= data_sz
;
406 if (rte_pktmbuf_chain(test_data
->decomp_bufs
[i
],
408 RTE_LOG(ERR
, USER1
, "Could not chain mbufs\n");
414 /* Allocate data in output mbuf */
415 test_data
->comp_bufs
[i
] =
416 rte_pktmbuf_alloc(test_data
->comp_buf_pool
);
417 if (test_data
->comp_bufs
[i
] == NULL
) {
418 RTE_LOG(ERR
, USER1
, "Could not allocate mbuf\n");
421 data_addr
= (uint8_t *) rte_pktmbuf_append(
422 test_data
->comp_bufs
[i
],
423 test_data
->out_seg_sz
);
424 if (data_addr
== NULL
) {
425 RTE_LOG(ERR
, USER1
, "Could not append data\n");
429 /* Chain mbufs if needed for output mbufs */
430 for (j
= 1; j
< segs_per_mbuf
; j
++) {
431 struct rte_mbuf
*next_seg
=
432 rte_pktmbuf_alloc(test_data
->comp_buf_pool
);
434 if (next_seg
== NULL
) {
436 "Could not allocate mbuf\n");
440 data_addr
= (uint8_t *)rte_pktmbuf_append(next_seg
,
441 test_data
->out_seg_sz
);
443 if (data_addr
== NULL
) {
444 RTE_LOG(ERR
, USER1
, "Could not append data\n");
448 if (rte_pktmbuf_chain(test_data
->comp_bufs
[i
],
450 RTE_LOG(ERR
, USER1
, "Could not chain mbufs\n");
460 free_bufs(struct comp_test_data
*test_data
)
464 for (i
= 0; i
< test_data
->total_bufs
; i
++) {
465 rte_pktmbuf_free(test_data
->comp_bufs
[i
]);
466 rte_pktmbuf_free(test_data
->decomp_bufs
[i
]);
473 main(int argc
, char **argv
)
475 uint8_t level
, level_idx
= 0;
477 struct comp_test_data
*test_data
;
479 /* Initialise DPDK EAL */
480 ret
= rte_eal_init(argc
, argv
);
482 rte_exit(EXIT_FAILURE
, "Invalid EAL arguments!\n");
486 test_data
= rte_zmalloc_socket(NULL
, sizeof(struct comp_test_data
),
489 if (test_data
== NULL
)
490 rte_exit(EXIT_FAILURE
, "Cannot reserve memory in socket %d\n",
494 cleanup
= ST_TEST_DATA
;
495 comp_perf_options_default(test_data
);
497 if (comp_perf_options_parse(test_data
, argc
, argv
) < 0) {
499 "Parsing one or more user options failed\n");
504 if (comp_perf_options_check(test_data
) < 0) {
509 if (comp_perf_initialize_compressdev(test_data
) < 0) {
514 cleanup
= ST_COMPDEV
;
515 if (comp_perf_dump_input_data(test_data
) < 0) {
520 cleanup
= ST_INPUT_DATA
;
521 if (comp_perf_allocate_memory(test_data
) < 0) {
526 if (prepare_bufs(test_data
) < 0) {
531 if (test_data
->level
.inc
!= 0)
532 level
= test_data
->level
.min
;
534 level
= test_data
->level
.list
[0];
536 printf("Burst size = %u\n", test_data
->burst_sz
);
537 printf("File size = %zu\n", test_data
->input_data_sz
);
539 printf("%6s%12s%17s%19s%21s%15s%21s%23s%16s\n",
540 "Level", "Comp size", "Comp ratio [%]",
541 "Comp [Cycles/it]", "Comp [Cycles/Byte]", "Comp [Gbps]",
542 "Decomp [Cycles/it]", "Decomp [Cycles/Byte]", "Decomp [Gbps]");
544 cleanup
= ST_DURING_TEST
;
545 while (level
<= test_data
->level
.max
) {
548 * Run a first iteration, to verify compression and
549 * get the compression ratio for the level
551 if (cperf_verification(test_data
, level
) != EXIT_SUCCESS
)
555 * Run benchmarking test
557 if (cperf_benchmark(test_data
, level
) != EXIT_SUCCESS
)
560 printf("%6u%12zu%17.2f%19"PRIu64
"%21.2f"
561 "%15.2f%21"PRIu64
"%23.2f%16.2f\n",
562 level
, test_data
->comp_data_sz
, test_data
->ratio
,
563 test_data
->comp_tsc_duration
[level
],
564 test_data
->comp_tsc_byte
, test_data
->comp_gbps
,
565 test_data
->decomp_tsc_duration
[level
],
566 test_data
->decomp_tsc_byte
, test_data
->decomp_gbps
);
568 if (test_data
->level
.inc
!= 0)
569 level
+= test_data
->level
.inc
;
571 if (++level_idx
== test_data
->level
.count
)
573 level
= test_data
->level
.list
[level_idx
];
582 free_bufs(test_data
);
584 case ST_MEMORY_ALLOC
:
585 rte_free(test_data
->decomp_bufs
);
586 rte_free(test_data
->comp_bufs
);
587 rte_free(test_data
->decompressed_data
);
588 rte_free(test_data
->compressed_data
);
589 rte_mempool_free(test_data
->op_pool
);
590 rte_mempool_free(test_data
->decomp_buf_pool
);
591 rte_mempool_free(test_data
->comp_buf_pool
);
594 rte_free(test_data
->input_data
);
597 if (test_data
->cdev_id
!= -1)
598 rte_compressdev_stop(test_data
->cdev_id
);
605 i
= rte_eal_cleanup();
608 "Error from rte_eal_cleanup(), %d\n", i
);