1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2018 Intel Corporation
8 #include <rte_cycles.h>
9 #include <rte_malloc.h>
10 #include <rte_mempool.h>
12 #include <rte_compressdev.h>
14 #include "test_compressdev_test_buffer.h"
17 #define DEFAULT_WINDOW_SIZE 15
18 #define DEFAULT_MEM_LEVEL 8
19 #define MAX_DEQD_RETRIES 10
20 #define DEQUEUE_WAIT_TIME 10000
23 * 30% extra size for compressed data compared to original data,
24 * in case data size cannot be reduced and it is actually bigger
25 * due to the compress block headers
27 #define COMPRESS_BUF_SIZE_RATIO 1.3
30 #define NUM_MAX_XFORMS 1
31 #define NUM_MAX_INFLIGHT_OPS 128
35 huffman_type_strings[] = {
36 [RTE_COMP_HUFFMAN_DEFAULT] = "PMD default",
37 [RTE_COMP_HUFFMAN_FIXED] = "Fixed",
38 [RTE_COMP_HUFFMAN_DYNAMIC] = "Dynamic"
48 struct comp_testsuite_params {
49 struct rte_mempool *mbuf_pool;
50 struct rte_mempool *op_pool;
51 struct rte_comp_xform def_comp_xform;
52 struct rte_comp_xform def_decomp_xform;
55 static struct comp_testsuite_params testsuite_params = { 0 };
58 testsuite_teardown(void)
60 struct comp_testsuite_params *ts_params = &testsuite_params;
62 rte_mempool_free(ts_params->mbuf_pool);
63 rte_mempool_free(ts_params->op_pool);
69 struct comp_testsuite_params *ts_params = &testsuite_params;
72 if (rte_compressdev_count() == 0) {
73 RTE_LOG(ERR, USER1, "Need at least one compress device\n");
77 uint32_t max_buf_size = 0;
78 for (i = 0; i < RTE_DIM(compress_test_bufs); i++)
79 max_buf_size = RTE_MAX(max_buf_size,
80 strlen(compress_test_bufs[i]) + 1);
82 max_buf_size *= COMPRESS_BUF_SIZE_RATIO;
84 * Buffers to be used in compression and decompression.
85 * Since decompressed data might be larger than
86 * compressed data (due to block header),
87 * buffers should be big enough for both cases.
89 ts_params->mbuf_pool = rte_pktmbuf_pool_create("mbuf_pool",
92 max_buf_size + RTE_PKTMBUF_HEADROOM,
94 if (ts_params->mbuf_pool == NULL) {
95 RTE_LOG(ERR, USER1, "Large mbuf pool could not be created\n");
99 ts_params->op_pool = rte_comp_op_pool_create("op_pool", NUM_OPS,
100 0, 0, rte_socket_id());
101 if (ts_params->op_pool == NULL) {
102 RTE_LOG(ERR, USER1, "Operation pool could not be created\n");
106 /* Initializes default values for compress/decompress xforms */
107 ts_params->def_comp_xform.type = RTE_COMP_COMPRESS;
108 ts_params->def_comp_xform.compress.algo = RTE_COMP_ALGO_DEFLATE,
109 ts_params->def_comp_xform.compress.deflate.huffman =
110 RTE_COMP_HUFFMAN_DEFAULT;
111 ts_params->def_comp_xform.compress.level = RTE_COMP_LEVEL_PMD_DEFAULT;
112 ts_params->def_comp_xform.compress.chksum = RTE_COMP_CHECKSUM_NONE;
113 ts_params->def_comp_xform.compress.window_size = DEFAULT_WINDOW_SIZE;
115 ts_params->def_decomp_xform.type = RTE_COMP_DECOMPRESS;
116 ts_params->def_decomp_xform.decompress.algo = RTE_COMP_ALGO_DEFLATE,
117 ts_params->def_decomp_xform.decompress.chksum = RTE_COMP_CHECKSUM_NONE;
118 ts_params->def_decomp_xform.decompress.window_size = DEFAULT_WINDOW_SIZE;
123 testsuite_teardown();
129 generic_ut_setup(void)
131 /* Configure compressdev (one device, one queue pair) */
132 struct rte_compressdev_config config = {
133 .socket_id = rte_socket_id(),
135 .max_nb_priv_xforms = NUM_MAX_XFORMS,
139 if (rte_compressdev_configure(0, &config) < 0) {
140 RTE_LOG(ERR, USER1, "Device configuration failed\n");
144 if (rte_compressdev_queue_pair_setup(0, 0, NUM_MAX_INFLIGHT_OPS,
145 rte_socket_id()) < 0) {
146 RTE_LOG(ERR, USER1, "Queue pair setup failed\n");
150 if (rte_compressdev_start(0) < 0) {
151 RTE_LOG(ERR, USER1, "Device could not be started\n");
159 generic_ut_teardown(void)
161 rte_compressdev_stop(0);
162 if (rte_compressdev_close(0) < 0)
163 RTE_LOG(ERR, USER1, "Device could not be closed\n");
167 compare_buffers(const char *buffer1, uint32_t buffer1_len,
168 const char *buffer2, uint32_t buffer2_len)
170 if (buffer1_len != buffer2_len) {
171 RTE_LOG(ERR, USER1, "Buffer lengths are different\n");
175 if (memcmp(buffer1, buffer2, buffer1_len) != 0) {
176 RTE_LOG(ERR, USER1, "Buffers are different\n");
184 * Maps compressdev and Zlib flush flags
187 map_zlib_flush_flag(enum rte_comp_flush_flag flag)
190 case RTE_COMP_FLUSH_NONE:
192 case RTE_COMP_FLUSH_SYNC:
194 case RTE_COMP_FLUSH_FULL:
196 case RTE_COMP_FLUSH_FINAL:
199 * There should be only the values above,
200 * so this should never happen
208 compress_zlib(struct rte_comp_op *op,
209 const struct rte_comp_xform *xform, int mem_level)
213 int strategy, window_bits, comp_level;
216 /* initialize zlib stream */
217 stream.zalloc = Z_NULL;
218 stream.zfree = Z_NULL;
219 stream.opaque = Z_NULL;
221 if (xform->compress.deflate.huffman == RTE_COMP_HUFFMAN_FIXED)
224 strategy = Z_DEFAULT_STRATEGY;
227 * Window bits is the base two logarithm of the window size (in bytes).
228 * When doing raw DEFLATE, this number will be negative.
230 window_bits = -(xform->compress.window_size);
232 comp_level = xform->compress.level;
234 if (comp_level != RTE_COMP_LEVEL_NONE)
235 ret = deflateInit2(&stream, comp_level, Z_DEFLATED,
236 window_bits, mem_level, strategy);
238 ret = deflateInit(&stream, Z_NO_COMPRESSION);
241 printf("Zlib deflate could not be initialized\n");
245 /* Assuming stateless operation */
246 stream.avail_in = op->src.length;
247 stream.next_in = rte_pktmbuf_mtod(op->m_src, uint8_t *);
248 stream.avail_out = op->m_dst->data_len;
249 stream.next_out = rte_pktmbuf_mtod(op->m_dst, uint8_t *);
251 /* Stateless operation, all buffer will be compressed in one go */
252 zlib_flush = map_zlib_flush_flag(op->flush_flag);
253 ret = deflate(&stream, zlib_flush);
255 if (stream.avail_in != 0) {
256 RTE_LOG(ERR, USER1, "Buffer could not be read entirely\n");
260 if (ret != Z_STREAM_END)
263 op->consumed = op->src.length - stream.avail_in;
264 op->produced = op->m_dst->data_len - stream.avail_out;
265 op->status = RTE_COMP_OP_STATUS_SUCCESS;
267 deflateReset(&stream);
277 decompress_zlib(struct rte_comp_op *op,
278 const struct rte_comp_xform *xform)
283 int ret = TEST_FAILED;
285 /* initialize zlib stream */
286 stream.zalloc = Z_NULL;
287 stream.zfree = Z_NULL;
288 stream.opaque = Z_NULL;
291 * Window bits is the base two logarithm of the window size (in bytes).
292 * When doing raw DEFLATE, this number will be negative.
294 window_bits = -(xform->decompress.window_size);
296 ret = inflateInit2(&stream, window_bits);
299 printf("Zlib deflate could not be initialized\n");
303 /* Assuming stateless operation */
304 stream.avail_in = op->src.length;
305 stream.next_in = rte_pktmbuf_mtod(op->m_src, uint8_t *);
306 stream.avail_out = op->m_dst->data_len;
307 stream.next_out = rte_pktmbuf_mtod(op->m_dst, uint8_t *);
309 /* Stateless operation, all buffer will be compressed in one go */
310 zlib_flush = map_zlib_flush_flag(op->flush_flag);
311 ret = inflate(&stream, zlib_flush);
313 if (stream.avail_in != 0) {
314 RTE_LOG(ERR, USER1, "Buffer could not be read entirely\n");
318 if (ret != Z_STREAM_END)
321 op->consumed = op->src.length - stream.avail_in;
322 op->produced = op->m_dst->data_len - stream.avail_out;
323 op->status = RTE_COMP_OP_STATUS_SUCCESS;
325 inflateReset(&stream);
335 * Compresses and decompresses buffer with compressdev API and Zlib API
338 test_deflate_comp_decomp(const char *test_buffer,
339 struct rte_comp_xform *compress_xform,
340 struct rte_comp_xform *decompress_xform,
341 enum rte_comp_op_type state,
342 enum zlib_direction zlib_dir)
344 struct comp_testsuite_params *ts_params = &testsuite_params;
347 struct rte_mbuf *comp_buf = NULL;
348 struct rte_mbuf *uncomp_buf = NULL;
349 struct rte_comp_op *op = NULL;
350 struct rte_comp_op *op_processed = NULL;
351 void *priv_xform = NULL;
353 unsigned int deqd_retries = 0;
356 /* Prepare the source mbuf with the data */
357 uncomp_buf = rte_pktmbuf_alloc(ts_params->mbuf_pool);
358 if (uncomp_buf == NULL) {
360 "Source mbuf could not be allocated "
361 "from the mempool\n");
365 data_ptr = rte_pktmbuf_append(uncomp_buf, strlen(test_buffer) + 1);
366 snprintf(data_ptr, strlen(test_buffer) + 1, "%s", test_buffer);
368 /* Prepare the destination mbuf */
369 comp_buf = rte_pktmbuf_alloc(ts_params->mbuf_pool);
370 if (comp_buf == NULL) {
372 "Destination mbuf could not be allocated "
373 "from the mempool\n");
377 rte_pktmbuf_append(comp_buf,
378 strlen(test_buffer) * COMPRESS_BUF_SIZE_RATIO);
380 /* Build the compression operations */
381 op = rte_comp_op_alloc(ts_params->op_pool);
384 "Compress operation could not be allocated "
385 "from the mempool\n");
389 op->m_src = uncomp_buf;
390 op->m_dst = comp_buf;
392 op->src.length = rte_pktmbuf_pkt_len(uncomp_buf);
394 if (state == RTE_COMP_OP_STATELESS) {
395 op->flush_flag = RTE_COMP_FLUSH_FINAL;
398 "Stateful operations are not supported "
399 "in these tests yet\n");
402 op->input_chksum = 0;
404 /* Compress data (either with Zlib API or compressdev API */
405 if (zlib_dir == ZLIB_COMPRESS || zlib_dir == ZLIB_ALL) {
406 ret = compress_zlib(op,
407 (const struct rte_comp_xform *)&compress_xform,
414 /* Create compress xform private data */
415 ret = rte_compressdev_private_xform_create(0,
416 (const struct rte_comp_xform *)compress_xform,
420 "Compression private xform "
421 "could not be created\n");
425 /* Attach xform private data to operation */
426 op->private_xform = priv_xform;
428 /* Enqueue and dequeue all operations */
429 ret = rte_compressdev_enqueue_burst(0, 0, &op, 1);
432 "The operation could not be enqueued\n");
437 * If retrying a dequeue call, wait for 10 ms to allow
438 * enough time to the driver to process the operations
440 if (deqd_retries != 0) {
442 * Avoid infinite loop if not all the
443 * operations get out of the device
445 if (deqd_retries == MAX_DEQD_RETRIES) {
447 "Not all operations could be "
451 usleep(DEQUEUE_WAIT_TIME);
453 num_deqd = rte_compressdev_dequeue_burst(0, 0,
457 } while (num_deqd < 1);
461 /* Free compress private xform */
462 rte_compressdev_private_xform_free(0, priv_xform);
466 enum rte_comp_huffman huffman_type =
467 compress_xform->compress.deflate.huffman;
468 RTE_LOG(DEBUG, USER1, "Buffer compressed from %u to %u bytes "
469 "(level = %u, huffman = %s)\n",
470 op_processed->consumed, op_processed->produced,
471 compress_xform->compress.level,
472 huffman_type_strings[huffman_type]);
473 RTE_LOG(DEBUG, USER1, "Compression ratio = %.2f",
474 (float)op_processed->produced /
475 op_processed->consumed * 100);
479 * Check operation status and free source mbuf (destination mbuf and
480 * compress operation information is needed for the decompression stage)
482 if (op_processed->status != RTE_COMP_OP_STATUS_SUCCESS) {
484 "Some operations were not successful\n");
487 rte_pktmbuf_free(uncomp_buf);
490 /* Allocate buffer for decompressed data */
491 uncomp_buf = rte_pktmbuf_alloc(ts_params->mbuf_pool);
492 if (uncomp_buf == NULL) {
494 "Destination mbuf could not be allocated "
495 "from the mempool\n");
499 rte_pktmbuf_append(uncomp_buf, strlen(test_buffer) + 1);
501 /* Build the decompression operations */
502 op = rte_comp_op_alloc(ts_params->op_pool);
505 "Decompress operation could not be allocated "
506 "from the mempool\n");
510 /* Source buffer is the compressed data from the previous operation */
511 op->m_src = op_processed->m_dst;
512 op->m_dst = uncomp_buf;
515 * Set the length of the compressed data to the
516 * number of bytes that were produced in the previous stage
518 op->src.length = op_processed->produced;
520 if (state == RTE_COMP_OP_STATELESS) {
521 op->flush_flag = RTE_COMP_FLUSH_FINAL;
524 "Stateful operations are not supported "
525 "in these tests yet\n");
528 op->input_chksum = 0;
531 * Free the previous compress operation,
532 * as it is not needed anymore
534 rte_comp_op_free(op_processed);
537 /* Decompress data (either with Zlib API or compressdev API */
538 if (zlib_dir == ZLIB_DECOMPRESS || zlib_dir == ZLIB_ALL) {
539 ret = decompress_zlib(op,
540 (const struct rte_comp_xform *)&decompress_xform);
547 /* Create decompress xform private data */
548 ret = rte_compressdev_private_xform_create(0,
549 (const struct rte_comp_xform *)decompress_xform,
553 "Decompression private xform "
554 "could not be created\n");
558 /* Attach xform private data to operation */
559 op->private_xform = priv_xform;
561 /* Enqueue and dequeue all operations */
562 ret = rte_compressdev_enqueue_burst(0, 0, &op, 1);
565 "The operation could not be enqueued\n");
570 * If retrying a dequeue call, wait for 10 ms to allow
571 * enough time to the driver to process the operations
573 if (deqd_retries != 0) {
575 * Avoid infinite loop if not all the
576 * operations get out of the device
578 if (deqd_retries == MAX_DEQD_RETRIES) {
580 "Not all operations could be "
584 usleep(DEQUEUE_WAIT_TIME);
586 num_deqd = rte_compressdev_dequeue_burst(0, 0,
590 } while (num_deqd < 1);
593 RTE_LOG(DEBUG, USER1, "Buffer decompressed from %u to %u bytes\n",
594 op_processed->consumed, op_processed->produced);
597 * Check operation status and free source mbuf (destination mbuf and
598 * compress operation information is still needed)
600 if (op_processed->status != RTE_COMP_OP_STATUS_SUCCESS) {
602 "Some operations were not successful\n");
605 rte_pktmbuf_free(comp_buf);
609 * Compare the original stream with the decompressed stream
610 * (in size and the data)
612 if (compare_buffers(test_buffer, strlen(test_buffer) + 1,
613 rte_pktmbuf_mtod(op_processed->m_dst, const char *),
614 op_processed->produced) < 0)
621 rte_pktmbuf_free(uncomp_buf);
622 rte_pktmbuf_free(comp_buf);
623 rte_comp_op_free(op);
624 rte_comp_op_free(op_processed);
626 if (priv_xform != NULL)
627 rte_compressdev_private_xform_free(0, priv_xform);
633 test_compressdev_deflate_stateless_fixed(void)
635 struct comp_testsuite_params *ts_params = &testsuite_params;
636 const char *test_buffer;
638 struct rte_comp_xform compress_xform;
640 memcpy(&compress_xform, &ts_params->def_comp_xform,
641 sizeof(struct rte_comp_xform));
642 compress_xform.compress.deflate.huffman = RTE_COMP_HUFFMAN_FIXED;
644 for (i = 0; i < RTE_DIM(compress_test_bufs); i++) {
645 test_buffer = compress_test_bufs[i];
647 /* Compress with compressdev, decompress with Zlib */
648 if (test_deflate_comp_decomp(test_buffer,
650 &ts_params->def_decomp_xform,
651 RTE_COMP_OP_STATELESS,
652 ZLIB_DECOMPRESS) < 0)
655 /* Compress with Zlib, decompress with compressdev */
656 if (test_deflate_comp_decomp(test_buffer,
658 &ts_params->def_decomp_xform,
659 RTE_COMP_OP_STATELESS,
668 test_compressdev_deflate_stateless_dynamic(void)
670 struct comp_testsuite_params *ts_params = &testsuite_params;
671 const char *test_buffer;
673 struct rte_comp_xform compress_xform;
675 memcpy(&compress_xform, &ts_params->def_comp_xform,
676 sizeof(struct rte_comp_xform));
677 compress_xform.compress.deflate.huffman = RTE_COMP_HUFFMAN_DYNAMIC;
679 for (i = 0; i < RTE_DIM(compress_test_bufs); i++) {
680 test_buffer = compress_test_bufs[i];
682 /* Compress with compressdev, decompress with Zlib */
683 if (test_deflate_comp_decomp(test_buffer,
685 &ts_params->def_decomp_xform,
686 RTE_COMP_OP_STATELESS,
687 ZLIB_DECOMPRESS) < 0)
690 /* Compress with Zlib, decompress with compressdev */
691 if (test_deflate_comp_decomp(test_buffer,
693 &ts_params->def_decomp_xform,
694 RTE_COMP_OP_STATELESS,
702 static struct unit_test_suite compressdev_testsuite = {
703 .suite_name = "compressdev unit test suite",
704 .setup = testsuite_setup,
705 .teardown = testsuite_teardown,
707 TEST_CASE_ST(generic_ut_setup, generic_ut_teardown,
708 test_compressdev_deflate_stateless_fixed),
709 TEST_CASE_ST(generic_ut_setup, generic_ut_teardown,
710 test_compressdev_deflate_stateless_dynamic),
711 TEST_CASES_END() /**< NULL terminate unit test array */
716 test_compressdev(void)
718 return unit_test_suite_runner(&compressdev_testsuite);
721 REGISTER_TEST_COMMAND(compressdev_autotest, test_compressdev);