From ac3077c3ea0d25a92888463ef88d8a8c00837afd Mon Sep 17 00:00:00 2001 From: Jim Harris Date: Wed, 2 Jan 2019 10:13:36 -0700 Subject: [PATCH] test/reduce: add compression algorithm This is a really dumb algorithm but is simple to understand for unit testing purposes. It counts the number of consecutive bytes with the same value, and then stores the number of bytes with that value, and the byte value itself. For example: 0xA1 0xA1 0xA2 0xA3 0xA3 0xA3 0xA3 0xA3 0xA3 would be compressed to: 0x02 0xA1 0x01 0xA2 0x06 0xA3 This will make it easy to generate specific data sequences that compress to specific sizes to validate the different compression paths through the reduce library. Signed-off-by: Jim Harris Change-Id: I0d48f98c080b9cdacb25433f53f44df7ada78c0a Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/449072 Tested-by: SPDK CI Jenkins Reviewed-by: Shuhei Matsumoto Reviewed-by: wuzhouhui Reviewed-by: Paul Luse Reviewed-by: Changpeng Liu --- test/unit/lib/reduce/reduce.c/reduce_ut.c | 125 +++++++++++++++++++++- 1 file changed, 124 insertions(+), 1 deletion(-) diff --git a/test/unit/lib/reduce/reduce.c/reduce_ut.c b/test/unit/lib/reduce/reduce.c/reduce_ut.c index c82e4e5d4..b7a283f55 100644 --- a/test/unit/lib/reduce/reduce.c/reduce_ut.c +++ b/test/unit/lib/reduce/reduce.c/reduce_ut.c @@ -1027,6 +1027,128 @@ overlapped(void) backing_dev_destroy(&backing_dev); } +static int +ut_compress(char *outbuf, uint32_t *compressed_len, char *inbuf, uint32_t inbuflen) +{ + uint32_t len = 0; + uint8_t count; + char last; + + while (true) { + if (inbuflen == 0) { + *compressed_len = len; + return 0; + } + + if (*compressed_len < (len + 2)) { + return -ENOSPC; + } + + last = *inbuf; + count = 1; + inbuflen--; + inbuf++; + + while (inbuflen > 0 && *inbuf == last && count < UINT8_MAX) { + count++; + inbuflen--; + inbuf++; + } + + outbuf[len] = count; + outbuf[len + 1] = last; + len += 2; + } +} + +static int +ut_decompress(uint8_t *outbuf, uint32_t *compressed_len, uint8_t *inbuf, uint32_t inbuflen) +{ + uint32_t len = 0; + + SPDK_CU_ASSERT_FATAL(inbuflen % 2 == 0); + + while (true) { + if (inbuflen == 0) { + *compressed_len = len; + return 0; + } + + if ((len + inbuf[0]) > *compressed_len) { + return -ENOSPC; + } + + memset(outbuf, inbuf[1], inbuf[0]); + outbuf += inbuf[0]; + len += inbuf[0]; + inbuflen -= 2; + inbuf += 2; + } +} + +#define BUFSIZE 4096 + +static void +compress_algorithm(void) +{ + uint8_t original_data[BUFSIZE]; + uint8_t compressed_data[BUFSIZE]; + uint8_t decompressed_data[BUFSIZE]; + uint32_t compressed_len, decompressed_len, i; + int rc; + + memset(original_data, 0xAA, BUFSIZE); + compressed_len = sizeof(compressed_data); + rc = ut_compress(compressed_data, &compressed_len, original_data, UINT8_MAX); + CU_ASSERT(rc == 0); + CU_ASSERT(compressed_len == 2); + CU_ASSERT(compressed_data[0] == UINT8_MAX); + CU_ASSERT(compressed_data[1] == 0xAA); + + decompressed_len = sizeof(decompressed_data); + rc = ut_decompress(decompressed_data, &decompressed_len, compressed_data, compressed_len); + CU_ASSERT(rc == 0); + CU_ASSERT(decompressed_len == UINT8_MAX); + CU_ASSERT(memcmp(original_data, decompressed_data, decompressed_len) == 0); + + compressed_len = sizeof(compressed_data); + rc = ut_compress(compressed_data, &compressed_len, original_data, UINT8_MAX + 1); + CU_ASSERT(rc == 0); + CU_ASSERT(compressed_len == 4); + CU_ASSERT(compressed_data[0] == UINT8_MAX); + CU_ASSERT(compressed_data[1] == 0xAA); + CU_ASSERT(compressed_data[2] == 1); + CU_ASSERT(compressed_data[3] == 0xAA); + + decompressed_len = sizeof(decompressed_data); + rc = ut_decompress(decompressed_data, &decompressed_len, compressed_data, compressed_len); + CU_ASSERT(rc == 0); + CU_ASSERT(decompressed_len == UINT8_MAX + 1); + CU_ASSERT(memcmp(original_data, decompressed_data, decompressed_len) == 0); + + for (i = 0; i < sizeof(original_data); i++) { + original_data[i] = i & 0xFF; + } + compressed_len = sizeof(compressed_data); + rc = ut_compress(compressed_data, &compressed_len, original_data, 2048); + CU_ASSERT(rc == 0); + CU_ASSERT(compressed_len == 4096); + CU_ASSERT(compressed_data[0] == 1); + CU_ASSERT(compressed_data[1] == 0); + CU_ASSERT(compressed_data[4094] == 1); + CU_ASSERT(compressed_data[4095] == 0xFF); + + decompressed_len = sizeof(decompressed_data); + rc = ut_decompress(decompressed_data, &decompressed_len, compressed_data, compressed_len); + CU_ASSERT(rc == 0); + CU_ASSERT(decompressed_len == 2048); + CU_ASSERT(memcmp(original_data, decompressed_data, decompressed_len) == 0); + + compressed_len = sizeof(compressed_data); + rc = ut_compress(compressed_data, &compressed_len, original_data, 2049); + CU_ASSERT(rc == -ENOSPC); +} + int main(int argc, char **argv) { @@ -1054,7 +1176,8 @@ main(int argc, char **argv) CU_add_test(suite, "read_write", read_write) == NULL || CU_add_test(suite, "destroy", destroy) == NULL || CU_add_test(suite, "defer_bdev_io", defer_bdev_io) == NULL || - CU_add_test(suite, "overlapped", overlapped) == NULL + CU_add_test(suite, "overlapped", overlapped) == NULL || + CU_add_test(suite, "compress_algorithm", compress_algorithm) == NULL ) { CU_cleanup_registry(); return CU_get_error();