2 * Xor Based Zero Run Length Encoding unit tests.
4 * Copyright 2013 Red Hat, Inc. and/or its affiliates
7 * Orit Wasserman <owasserm@redhat.com>
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
13 #include "qemu/osdep.h"
14 #include "qemu/cutils.h"
15 #include "../migration/xbzrle.h"
17 #if defined(CONFIG_AVX512BW_OPT)
18 #define XBZRLE_PAGE_SIZE 4096
19 static bool is_cpu_support_avx512bw
;
20 #include "qemu/cpuid.h"
21 static void __attribute__((constructor
)) init_cpu_flag(void)
23 unsigned max
= __get_cpuid_max(0, NULL
);
25 is_cpu_support_avx512bw
= false;
27 __cpuid(1, a
, b
, c
, d
);
28 /* We must check that AVX is not just available, but usable. */
29 if ((c
& bit_OSXSAVE
) && (c
& bit_AVX
) && max
>= 7) {
31 __asm("xgetbv" : "=a"(bv
), "=d"(d
) : "c"(0));
32 __cpuid_count(7, 0, a
, b
, c
, d
);
34 * XCR0[7:5] = 111b (OPMASK state, upper 256-bit of ZMM0-ZMM15
35 * and ZMM16-ZMM31 state are enabled by OS)
36 * XCR0[2:1] = 11b (XMM state and YMM state are enabled by OS)
38 if ((bv
& 0xe6) == 0xe6 && (b
& bit_AVX512BW
)) {
39 is_cpu_support_avx512bw
= true;
52 /* Function prototypes
53 int xbzrle_encode_buffer_avx512(uint8_t *old_buf, uint8_t *new_buf, int slen,
54 uint8_t *dst, int dlen);
56 static void encode_decode_zero(struct ResTime
*res
)
58 uint8_t *buffer
= g_malloc0(XBZRLE_PAGE_SIZE
);
59 uint8_t *compressed
= g_malloc0(XBZRLE_PAGE_SIZE
);
60 uint8_t *buffer512
= g_malloc0(XBZRLE_PAGE_SIZE
);
61 uint8_t *compressed512
= g_malloc0(XBZRLE_PAGE_SIZE
);
63 int dlen
= 0, dlen512
= 0;
64 int diff_len
= g_test_rand_int_range(0, XBZRLE_PAGE_SIZE
- 1006);
66 for (i
= diff_len
; i
> 0; i
--) {
68 buffer512
[1000 + i
] = i
;
71 buffer
[1000 + diff_len
+ 3] = 103;
72 buffer
[1000 + diff_len
+ 5] = 105;
74 buffer512
[1000 + diff_len
+ 3] = 103;
75 buffer512
[1000 + diff_len
+ 5] = 105;
77 /* encode zero page */
78 time_t t_start
, t_end
, t_start512
, t_end512
;
80 dlen
= xbzrle_encode_buffer(buffer
, buffer
, XBZRLE_PAGE_SIZE
, compressed
,
83 float time_val
= difftime(t_end
, t_start
);
87 dlen512
= xbzrle_encode_buffer_avx512(buffer512
, buffer512
, XBZRLE_PAGE_SIZE
,
88 compressed512
, XBZRLE_PAGE_SIZE
);
90 float time_val512
= difftime(t_end512
, t_start512
);
91 g_assert(dlen512
== 0);
93 res
->t_raw
= time_val
;
94 res
->t_512
= time_val512
;
99 g_free(compressed512
);
103 static void test_encode_decode_zero_avx512(void)
106 float time_raw
= 0.0, time_512
= 0.0;
108 for (i
= 0; i
< 10000; i
++) {
109 encode_decode_zero(&res
);
110 time_raw
+= res
.t_raw
;
111 time_512
+= res
.t_512
;
113 printf("Zero test:\n");
114 printf("Raw xbzrle_encode time is %f ms\n", time_raw
);
115 printf("512 xbzrle_encode time is %f ms\n", time_512
);
118 static void encode_decode_unchanged(struct ResTime
*res
)
120 uint8_t *compressed
= g_malloc0(XBZRLE_PAGE_SIZE
);
121 uint8_t *test
= g_malloc0(XBZRLE_PAGE_SIZE
);
122 uint8_t *compressed512
= g_malloc0(XBZRLE_PAGE_SIZE
);
123 uint8_t *test512
= g_malloc0(XBZRLE_PAGE_SIZE
);
125 int dlen
= 0, dlen512
= 0;
126 int diff_len
= g_test_rand_int_range(0, XBZRLE_PAGE_SIZE
- 1006);
128 for (i
= diff_len
; i
> 0; i
--) {
129 test
[1000 + i
] = i
+ 4;
130 test512
[1000 + i
] = i
+ 4;
133 test
[1000 + diff_len
+ 3] = 107;
134 test
[1000 + diff_len
+ 5] = 109;
136 test512
[1000 + diff_len
+ 3] = 107;
137 test512
[1000 + diff_len
+ 5] = 109;
139 /* test unchanged buffer */
140 time_t t_start
, t_end
, t_start512
, t_end512
;
142 dlen
= xbzrle_encode_buffer(test
, test
, XBZRLE_PAGE_SIZE
, compressed
,
145 float time_val
= difftime(t_end
, t_start
);
148 t_start512
= clock();
149 dlen512
= xbzrle_encode_buffer_avx512(test512
, test512
, XBZRLE_PAGE_SIZE
,
150 compressed512
, XBZRLE_PAGE_SIZE
);
152 float time_val512
= difftime(t_end512
, t_start512
);
153 g_assert(dlen512
== 0);
155 res
->t_raw
= time_val
;
156 res
->t_512
= time_val512
;
161 g_free(compressed512
);
165 static void test_encode_decode_unchanged_avx512(void)
168 float time_raw
= 0.0, time_512
= 0.0;
170 for (i
= 0; i
< 10000; i
++) {
171 encode_decode_unchanged(&res
);
172 time_raw
+= res
.t_raw
;
173 time_512
+= res
.t_512
;
175 printf("Unchanged test:\n");
176 printf("Raw xbzrle_encode time is %f ms\n", time_raw
);
177 printf("512 xbzrle_encode time is %f ms\n", time_512
);
180 static void encode_decode_1_byte(struct ResTime
*res
)
182 uint8_t *buffer
= g_malloc0(XBZRLE_PAGE_SIZE
);
183 uint8_t *test
= g_malloc0(XBZRLE_PAGE_SIZE
);
184 uint8_t *compressed
= g_malloc(XBZRLE_PAGE_SIZE
);
185 uint8_t *buffer512
= g_malloc0(XBZRLE_PAGE_SIZE
);
186 uint8_t *test512
= g_malloc0(XBZRLE_PAGE_SIZE
);
187 uint8_t *compressed512
= g_malloc(XBZRLE_PAGE_SIZE
);
188 int dlen
= 0, rc
= 0, dlen512
= 0, rc512
= 0;
192 test
[XBZRLE_PAGE_SIZE
- 1] = 1;
193 test512
[XBZRLE_PAGE_SIZE
- 1] = 1;
195 time_t t_start
, t_end
, t_start512
, t_end512
;
197 dlen
= xbzrle_encode_buffer(buffer
, test
, XBZRLE_PAGE_SIZE
, compressed
,
200 float time_val
= difftime(t_end
, t_start
);
201 g_assert(dlen
== (uleb128_encode_small(&buf
[0], 4095) + 2));
203 rc
= xbzrle_decode_buffer(compressed
, dlen
, buffer
, XBZRLE_PAGE_SIZE
);
204 g_assert(rc
== XBZRLE_PAGE_SIZE
);
205 g_assert(memcmp(test
, buffer
, XBZRLE_PAGE_SIZE
) == 0);
207 t_start512
= clock();
208 dlen512
= xbzrle_encode_buffer_avx512(buffer512
, test512
, XBZRLE_PAGE_SIZE
,
209 compressed512
, XBZRLE_PAGE_SIZE
);
211 float time_val512
= difftime(t_end512
, t_start512
);
212 g_assert(dlen512
== (uleb128_encode_small(&buf512
[0], 4095) + 2));
214 rc512
= xbzrle_decode_buffer(compressed512
, dlen512
, buffer512
,
216 g_assert(rc512
== XBZRLE_PAGE_SIZE
);
217 g_assert(memcmp(test512
, buffer512
, XBZRLE_PAGE_SIZE
) == 0);
219 res
->t_raw
= time_val
;
220 res
->t_512
= time_val512
;
226 g_free(compressed512
);
231 static void test_encode_decode_1_byte_avx512(void)
234 float time_raw
= 0.0, time_512
= 0.0;
236 for (i
= 0; i
< 10000; i
++) {
237 encode_decode_1_byte(&res
);
238 time_raw
+= res
.t_raw
;
239 time_512
+= res
.t_512
;
241 printf("1 byte test:\n");
242 printf("Raw xbzrle_encode time is %f ms\n", time_raw
);
243 printf("512 xbzrle_encode time is %f ms\n", time_512
);
246 static void encode_decode_overflow(struct ResTime
*res
)
248 uint8_t *compressed
= g_malloc0(XBZRLE_PAGE_SIZE
);
249 uint8_t *test
= g_malloc0(XBZRLE_PAGE_SIZE
);
250 uint8_t *buffer
= g_malloc0(XBZRLE_PAGE_SIZE
);
251 uint8_t *compressed512
= g_malloc0(XBZRLE_PAGE_SIZE
);
252 uint8_t *test512
= g_malloc0(XBZRLE_PAGE_SIZE
);
253 uint8_t *buffer512
= g_malloc0(XBZRLE_PAGE_SIZE
);
254 int i
= 0, rc
= 0, rc512
= 0;
256 for (i
= 0; i
< XBZRLE_PAGE_SIZE
/ 2 - 1; i
++) {
261 /* encode overflow */
262 time_t t_start
, t_end
, t_start512
, t_end512
;
264 rc
= xbzrle_encode_buffer(buffer
, test
, XBZRLE_PAGE_SIZE
, compressed
,
267 float time_val
= difftime(t_end
, t_start
);
270 t_start512
= clock();
271 rc512
= xbzrle_encode_buffer_avx512(buffer512
, test512
, XBZRLE_PAGE_SIZE
,
272 compressed512
, XBZRLE_PAGE_SIZE
);
274 float time_val512
= difftime(t_end512
, t_start512
);
275 g_assert(rc512
== -1);
277 res
->t_raw
= time_val
;
278 res
->t_512
= time_val512
;
284 g_free(compressed512
);
289 static void test_encode_decode_overflow_avx512(void)
292 float time_raw
= 0.0, time_512
= 0.0;
294 for (i
= 0; i
< 10000; i
++) {
295 encode_decode_overflow(&res
);
296 time_raw
+= res
.t_raw
;
297 time_512
+= res
.t_512
;
299 printf("Overflow test:\n");
300 printf("Raw xbzrle_encode time is %f ms\n", time_raw
);
301 printf("512 xbzrle_encode time is %f ms\n", time_512
);
304 static void encode_decode_range_avx512(struct ResTime
*res
)
306 uint8_t *buffer
= g_malloc0(XBZRLE_PAGE_SIZE
);
307 uint8_t *compressed
= g_malloc(XBZRLE_PAGE_SIZE
);
308 uint8_t *test
= g_malloc0(XBZRLE_PAGE_SIZE
);
309 uint8_t *buffer512
= g_malloc0(XBZRLE_PAGE_SIZE
);
310 uint8_t *compressed512
= g_malloc(XBZRLE_PAGE_SIZE
);
311 uint8_t *test512
= g_malloc0(XBZRLE_PAGE_SIZE
);
312 int i
= 0, rc
= 0, rc512
= 0;
313 int dlen
= 0, dlen512
= 0;
315 int diff_len
= g_test_rand_int_range(0, XBZRLE_PAGE_SIZE
- 1006);
317 for (i
= diff_len
; i
> 0; i
--) {
318 buffer
[1000 + i
] = i
;
319 test
[1000 + i
] = i
+ 4;
320 buffer512
[1000 + i
] = i
;
321 test512
[1000 + i
] = i
+ 4;
324 buffer
[1000 + diff_len
+ 3] = 103;
325 test
[1000 + diff_len
+ 3] = 107;
327 buffer
[1000 + diff_len
+ 5] = 105;
328 test
[1000 + diff_len
+ 5] = 109;
330 buffer512
[1000 + diff_len
+ 3] = 103;
331 test512
[1000 + diff_len
+ 3] = 107;
333 buffer512
[1000 + diff_len
+ 5] = 105;
334 test512
[1000 + diff_len
+ 5] = 109;
336 /* test encode/decode */
337 time_t t_start
, t_end
, t_start512
, t_end512
;
339 dlen
= xbzrle_encode_buffer(test
, buffer
, XBZRLE_PAGE_SIZE
, compressed
,
342 float time_val
= difftime(t_end
, t_start
);
343 rc
= xbzrle_decode_buffer(compressed
, dlen
, test
, XBZRLE_PAGE_SIZE
);
344 g_assert(rc
< XBZRLE_PAGE_SIZE
);
345 g_assert(memcmp(test
, buffer
, XBZRLE_PAGE_SIZE
) == 0);
347 t_start512
= clock();
348 dlen512
= xbzrle_encode_buffer_avx512(test512
, buffer512
, XBZRLE_PAGE_SIZE
,
349 compressed512
, XBZRLE_PAGE_SIZE
);
351 float time_val512
= difftime(t_end512
, t_start512
);
352 rc512
= xbzrle_decode_buffer(compressed512
, dlen512
, test512
, XBZRLE_PAGE_SIZE
);
353 g_assert(rc512
< XBZRLE_PAGE_SIZE
);
354 g_assert(memcmp(test512
, buffer512
, XBZRLE_PAGE_SIZE
) == 0);
356 res
->t_raw
= time_val
;
357 res
->t_512
= time_val512
;
363 g_free(compressed512
);
368 static void test_encode_decode_avx512(void)
371 float time_raw
= 0.0, time_512
= 0.0;
373 for (i
= 0; i
< 10000; i
++) {
374 encode_decode_range_avx512(&res
);
375 time_raw
+= res
.t_raw
;
376 time_512
+= res
.t_512
;
378 printf("Encode decode test:\n");
379 printf("Raw xbzrle_encode time is %f ms\n", time_raw
);
380 printf("512 xbzrle_encode time is %f ms\n", time_512
);
383 static void encode_decode_random(struct ResTime
*res
)
385 uint8_t *buffer
= g_malloc0(XBZRLE_PAGE_SIZE
);
386 uint8_t *compressed
= g_malloc(XBZRLE_PAGE_SIZE
);
387 uint8_t *test
= g_malloc0(XBZRLE_PAGE_SIZE
);
388 uint8_t *buffer512
= g_malloc0(XBZRLE_PAGE_SIZE
);
389 uint8_t *compressed512
= g_malloc(XBZRLE_PAGE_SIZE
);
390 uint8_t *test512
= g_malloc0(XBZRLE_PAGE_SIZE
);
391 int i
= 0, rc
= 0, rc512
= 0;
392 int dlen
= 0, dlen512
= 0;
394 int diff_len
= g_test_rand_int_range(0, XBZRLE_PAGE_SIZE
- 1);
395 /* store the index of diff */
396 int dirty_index
[diff_len
];
397 for (int j
= 0; j
< diff_len
; j
++) {
398 dirty_index
[j
] = g_test_rand_int_range(0, XBZRLE_PAGE_SIZE
- 1);
400 for (i
= diff_len
- 1; i
>= 0; i
--) {
401 buffer
[dirty_index
[i
]] = i
;
402 test
[dirty_index
[i
]] = i
+ 4;
403 buffer512
[dirty_index
[i
]] = i
;
404 test512
[dirty_index
[i
]] = i
+ 4;
407 time_t t_start
, t_end
, t_start512
, t_end512
;
409 dlen
= xbzrle_encode_buffer(test
, buffer
, XBZRLE_PAGE_SIZE
, compressed
,
412 float time_val
= difftime(t_end
, t_start
);
413 rc
= xbzrle_decode_buffer(compressed
, dlen
, test
, XBZRLE_PAGE_SIZE
);
414 g_assert(rc
< XBZRLE_PAGE_SIZE
);
416 t_start512
= clock();
417 dlen512
= xbzrle_encode_buffer_avx512(test512
, buffer512
, XBZRLE_PAGE_SIZE
,
418 compressed512
, XBZRLE_PAGE_SIZE
);
420 float time_val512
= difftime(t_end512
, t_start512
);
421 rc512
= xbzrle_decode_buffer(compressed512
, dlen512
, test512
, XBZRLE_PAGE_SIZE
);
422 g_assert(rc512
< XBZRLE_PAGE_SIZE
);
424 res
->t_raw
= time_val
;
425 res
->t_512
= time_val512
;
431 g_free(compressed512
);
436 static void test_encode_decode_random_avx512(void)
439 float time_raw
= 0.0, time_512
= 0.0;
441 for (i
= 0; i
< 10000; i
++) {
442 encode_decode_random(&res
);
443 time_raw
+= res
.t_raw
;
444 time_512
+= res
.t_512
;
446 printf("Random test:\n");
447 printf("Raw xbzrle_encode time is %f ms\n", time_raw
);
448 printf("512 xbzrle_encode time is %f ms\n", time_512
);
452 int main(int argc
, char **argv
)
454 g_test_init(&argc
, &argv
, NULL
);
456 #if defined(CONFIG_AVX512BW_OPT)
457 if (likely(is_cpu_support_avx512bw
)) {
458 g_test_add_func("/xbzrle/encode_decode_zero", test_encode_decode_zero_avx512
);
459 g_test_add_func("/xbzrle/encode_decode_unchanged",
460 test_encode_decode_unchanged_avx512
);
461 g_test_add_func("/xbzrle/encode_decode_1_byte", test_encode_decode_1_byte_avx512
);
462 g_test_add_func("/xbzrle/encode_decode_overflow",
463 test_encode_decode_overflow_avx512
);
464 g_test_add_func("/xbzrle/encode_decode", test_encode_decode_avx512
);
465 g_test_add_func("/xbzrle/encode_decode_random", test_encode_decode_random_avx512
);