Skip to content

Commit 4889093

Browse files
committed
unittest: add compression round-trip tests
Test compress_data() / decompress_data() with zero-filled, repeating pattern, pseudo-random, and single-byte pages across three LZ4 acceleration levels. Test compress_region() / decompress_region() with the same patterns at region sizes {16, 64, 256} pages and acceleration levels {1, 4, 32}, including an "all zeros except one non-zero page" case to exercise the zero pre-pass fast path and per-page zero detection inside the decompression result. Also test page_is_all_zero() edge cases. Signed-off-by: Radostin Stoyanov <rstoyanov@fedoraproject.org>
1 parent bf3b98f commit 4889093

1 file changed

Lines changed: 151 additions & 0 deletions

File tree

criu/unittest/unit.c

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <stdio.h>
22
#include <stdlib.h>
3+
#include <string.h>
34
#include <assert.h>
45
#include <unistd.h>
56
#include <fcntl.h>
@@ -9,6 +10,8 @@
910
#include "util.h"
1011
#include "criu-log.h"
1112
#include "bfd.h"
13+
#include "compression.h"
14+
#include "page.h"
1215

1316
int parse_statement(int i, char *line, char **configuration);
1417

@@ -92,6 +95,149 @@ static void test_bwrite(void)
9295
free(read_buf);
9396
}
9497

98+
#ifdef CONFIG_LZ4
99+
static void test_compress_roundtrip(const char *page, int acceleration)
100+
{
101+
char compressed[PAGE_COMPRESSED_SIZE_BOUND];
102+
char decompressed[PAGE_SIZE];
103+
int cs;
104+
105+
cs = compress_data(page, PAGE_SIZE, compressed,
106+
PAGE_COMPRESSED_SIZE_BOUND, acceleration);
107+
assert(cs > 0);
108+
assert(cs <= PAGE_COMPRESSED_SIZE_BOUND);
109+
assert(decompress_data(compressed, cs, PAGE_SIZE, decompressed) == 0);
110+
assert(memcmp(page, decompressed, PAGE_SIZE) == 0);
111+
}
112+
113+
static void test_compression(void)
114+
{
115+
char cbuf[PAGE_COMPRESSED_SIZE_BOUND];
116+
char page[PAGE_SIZE];
117+
int cs;
118+
int accels[] = { 1, 4, 100 };
119+
120+
/* Zero-page detection */
121+
memset(page, 0, PAGE_SIZE);
122+
assert(page_is_all_zero(page) == true);
123+
page[PAGE_SIZE - 1] = 1;
124+
assert(page_is_all_zero(page) == false);
125+
page[PAGE_SIZE - 1] = 0;
126+
page[0] = 0x42;
127+
assert(page_is_all_zero(page) == false);
128+
129+
130+
for (int a = 0; a < 3; a++) {
131+
int accel = accels[a];
132+
133+
/* Zero-filled page: should compress well */
134+
memset(cbuf, 0, sizeof(cbuf));
135+
memset(page, 0, PAGE_SIZE);
136+
cs = compress_data(page, PAGE_SIZE,
137+
cbuf, PAGE_COMPRESSED_SIZE_BOUND, accel);
138+
assert(cs > 0 && cs < PAGE_SIZE);
139+
test_compress_roundtrip(page, accel);
140+
141+
/* Repeating pattern */
142+
for (int i = 0; i < PAGE_SIZE; i++)
143+
page[i] = i & 0xff;
144+
test_compress_roundtrip(page, accel);
145+
146+
/* Pseudo-random data (incompressible) */
147+
srand(42);
148+
for (int i = 0; i < PAGE_SIZE; i++)
149+
page[i] = rand() & 0xff;
150+
test_compress_roundtrip(page, accel);
151+
152+
/* Single non-zero byte */
153+
memset(cbuf, 0, sizeof(cbuf));
154+
memset(page, 0, PAGE_SIZE);
155+
page[0] = 0x42;
156+
cs = compress_data(page, PAGE_SIZE,
157+
cbuf, PAGE_COMPRESSED_SIZE_BOUND, accel);
158+
assert(cs > 0 && cs < PAGE_SIZE);
159+
test_compress_roundtrip(page, accel);
160+
}
161+
}
162+
163+
static void test_region_roundtrip(const char *src, unsigned int n_pages,
164+
int acceleration)
165+
{
166+
size_t region_bytes = (size_t)n_pages * PAGE_SIZE;
167+
size_t cap = REGION_COMPRESSED_SIZE_BOUND(n_pages);
168+
char *cbuf = malloc(cap);
169+
char *dec = malloc(region_bytes);
170+
int cs;
171+
172+
assert(cbuf && dec);
173+
cs = compress_region(src, n_pages, cbuf, cap, acceleration);
174+
assert(cs >= 0);
175+
assert((size_t)cs <= region_bytes);
176+
assert(decompress_region(cbuf, cs, n_pages, dec) == 0);
177+
assert(memcmp(src, dec, region_bytes) == 0);
178+
179+
free(cbuf);
180+
free(dec);
181+
}
182+
183+
static void test_region_compression(void)
184+
{
185+
unsigned int sizes[] = { 16, 64, 256 };
186+
int accels[] = { 1, 4, 32 };
187+
unsigned int s, a;
188+
189+
for (s = 0; s < sizeof(sizes) / sizeof(sizes[0]); s++) {
190+
unsigned int n_pages = sizes[s];
191+
size_t region_bytes = (size_t)n_pages * PAGE_SIZE;
192+
char *src = malloc(region_bytes);
193+
size_t cap = REGION_COMPRESSED_SIZE_BOUND(n_pages);
194+
char *cbuf = malloc(cap);
195+
size_t i;
196+
int cs;
197+
198+
assert(src && cbuf);
199+
200+
for (a = 0; a < sizeof(accels) / sizeof(accels[0]); a++) {
201+
int accel = accels[a];
202+
203+
/* All-zero region: must short-circuit to 0 bytes. */
204+
memset(src, 0, region_bytes);
205+
cs = compress_region(src, n_pages, cbuf, cap, accel);
206+
assert(cs == 0);
207+
test_region_roundtrip(src, n_pages, accel);
208+
209+
/* Repeating pattern: should compress well. */
210+
for (i = 0; i < region_bytes; i++)
211+
src[i] = (char)(i & 0xff);
212+
cs = compress_region(src, n_pages, cbuf, cap, accel);
213+
assert(cs > 0);
214+
assert((size_t)cs < region_bytes);
215+
test_region_roundtrip(src, n_pages, accel);
216+
217+
/* Pseudo-random: store-raw fallback expected. */
218+
srand(42 + a);
219+
for (i = 0; i < region_bytes; i++)
220+
src[i] = (char)(rand() & 0xff);
221+
cs = compress_region(src, n_pages, cbuf, cap, accel);
222+
assert(cs > 0);
223+
assert((size_t)cs <= region_bytes);
224+
test_region_roundtrip(src, n_pages, accel);
225+
226+
/* Mostly zeros with one non-zero island. */
227+
memset(src, 0, region_bytes);
228+
memset(src + region_bytes / 2, 0xab, PAGE_SIZE);
229+
cs = compress_region(src, n_pages, cbuf, cap, accel);
230+
assert(cs > 0);
231+
assert((size_t)cs < region_bytes);
232+
test_region_roundtrip(src, n_pages, accel);
233+
}
234+
235+
free(src);
236+
free(cbuf);
237+
}
238+
}
239+
#endif
240+
95241
int main(int argc, char *argv[], char *envp[])
96242
{
97243
char **configuration;
@@ -230,6 +376,11 @@ int main(int argc, char *argv[], char *envp[])
230376
/* leaves punctuation in returned string as is */
231377
assert(!strcmp(get_relative_path("./a////.///./b//././c", "a"), "b//././c"));
232378

379+
#ifdef CONFIG_LZ4
380+
test_compression();
381+
test_region_compression();
382+
#endif
383+
233384
pr_msg("OK\n");
234385
return 0;
235386
}

0 commit comments

Comments
 (0)