|
1 | 1 | #include <stdio.h> |
2 | 2 | #include <stdlib.h> |
| 3 | +#include <string.h> |
3 | 4 | #include <assert.h> |
4 | 5 | #include <unistd.h> |
5 | 6 | #include <fcntl.h> |
|
9 | 10 | #include "util.h" |
10 | 11 | #include "criu-log.h" |
11 | 12 | #include "bfd.h" |
| 13 | +#include "compression.h" |
| 14 | +#include "page.h" |
12 | 15 |
|
13 | 16 | int parse_statement(int i, char *line, char **configuration); |
14 | 17 |
|
@@ -92,6 +95,149 @@ static void test_bwrite(void) |
92 | 95 | free(read_buf); |
93 | 96 | } |
94 | 97 |
|
| 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(page, 0, PAGE_SIZE); |
| 154 | + page[0] = 0x42; |
| 155 | + cs = compress_data(page, PAGE_SIZE, |
| 156 | + (char[PAGE_COMPRESSED_SIZE_BOUND]){0}, |
| 157 | + 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 | + |
95 | 241 | int main(int argc, char *argv[], char *envp[]) |
96 | 242 | { |
97 | 243 | char **configuration; |
@@ -230,6 +376,11 @@ int main(int argc, char *argv[], char *envp[]) |
230 | 376 | /* leaves punctuation in returned string as is */ |
231 | 377 | assert(!strcmp(get_relative_path("./a////.///./b//././c", "a"), "b//././c")); |
232 | 378 |
|
| 379 | +#ifdef CONFIG_LZ4 |
| 380 | + test_compression(); |
| 381 | + test_region_compression(); |
| 382 | +#endif |
| 383 | + |
233 | 384 | pr_msg("OK\n"); |
234 | 385 | return 0; |
235 | 386 | } |
0 commit comments