2 * Hierarchical bitmap unit-tests.
4 * Copyright (C) 2012 Red Hat Inc.
6 * Author: Paolo Bonzini <pbonzini@redhat.com>
8 * This work is licensed under the terms of the GNU GPL, version 2 or later.
9 * See the COPYING file in the top-level directory.
15 #include <sys/types.h>
16 #include "qemu/hbitmap.h"
18 #define LOG_BITS_PER_LONG (BITS_PER_LONG == 32 ? 5 : 6)
20 #define L1 BITS_PER_LONG
21 #define L2 (BITS_PER_LONG * L1)
22 #define L3 (BITS_PER_LONG * L2)
24 typedef struct TestHBitmapData
{
33 /* Check that the HBitmap and the shadow bitmap contain the same data,
34 * ignoring the same "first" bits.
36 static void hbitmap_test_check(TestHBitmapData
*data
,
45 hbitmap_iter_init(&hbi
, data
->hb
, first
);
49 next
= hbitmap_iter_next(&hbi
);
55 pos
= i
>> LOG_BITS_PER_LONG
;
56 bit
= i
& (BITS_PER_LONG
- 1);
58 g_assert_cmpint(data
->bits
[pos
] & (1UL << bit
), ==, 0);
61 if (next
== data
->size
) {
65 pos
= i
>> LOG_BITS_PER_LONG
;
66 bit
= i
& (BITS_PER_LONG
- 1);
69 g_assert_cmpint(data
->bits
[pos
] & (1UL << bit
), !=, 0);
73 g_assert_cmpint(count
<< data
->granularity
, ==, hbitmap_count(data
->hb
));
77 /* This is provided instead of a test setup function so that the sizes
78 are kept in the test functions (and not in main()) */
79 static void hbitmap_test_init(TestHBitmapData
*data
,
80 uint64_t size
, int granularity
)
83 data
->hb
= hbitmap_alloc(size
, granularity
);
85 n
= (size
+ BITS_PER_LONG
- 1) / BITS_PER_LONG
;
89 data
->bits
= g_new0(unsigned long, n
);
91 data
->granularity
= granularity
;
93 hbitmap_test_check(data
, 0);
97 static inline size_t hbitmap_test_array_size(size_t bits
)
99 size_t n
= (bits
+ BITS_PER_LONG
- 1) / BITS_PER_LONG
;
103 static void hbitmap_test_truncate_impl(TestHBitmapData
*data
,
108 data
->old_size
= data
->size
;
111 if (data
->size
== data
->old_size
) {
115 n
= hbitmap_test_array_size(size
);
116 m
= hbitmap_test_array_size(data
->old_size
);
117 data
->bits
= g_realloc(data
->bits
, sizeof(unsigned long) * n
);
119 memset(&data
->bits
[m
], 0x00, sizeof(unsigned long) * (n
- m
));
122 /* If we shrink to an uneven multiple of sizeof(unsigned long),
123 * scrub the leftover memory. */
124 if (data
->size
< data
->old_size
) {
125 m
= size
% (sizeof(unsigned long) * 8);
127 unsigned long mask
= (1ULL << m
) - 1;
128 data
->bits
[n
-1] &= mask
;
132 hbitmap_truncate(data
->hb
, size
);
135 static void hbitmap_test_teardown(TestHBitmapData
*data
,
139 hbitmap_free(data
->hb
);
148 /* Set a range in the HBitmap and in the shadow "simple" bitmap.
149 * The two bitmaps are then tested against each other.
151 static void hbitmap_test_set(TestHBitmapData
*data
,
152 uint64_t first
, uint64_t count
)
154 hbitmap_set(data
->hb
, first
, count
);
155 while (count
-- != 0) {
156 size_t pos
= first
>> LOG_BITS_PER_LONG
;
157 int bit
= first
& (BITS_PER_LONG
- 1);
160 data
->bits
[pos
] |= 1UL << bit
;
163 if (data
->granularity
== 0) {
164 hbitmap_test_check(data
, 0);
168 /* Reset a range in the HBitmap and in the shadow "simple" bitmap.
170 static void hbitmap_test_reset(TestHBitmapData
*data
,
171 uint64_t first
, uint64_t count
)
173 hbitmap_reset(data
->hb
, first
, count
);
174 while (count
-- != 0) {
175 size_t pos
= first
>> LOG_BITS_PER_LONG
;
176 int bit
= first
& (BITS_PER_LONG
- 1);
179 data
->bits
[pos
] &= ~(1UL << bit
);
182 if (data
->granularity
== 0) {
183 hbitmap_test_check(data
, 0);
187 static void hbitmap_test_check_get(TestHBitmapData
*data
)
192 for (i
= 0; i
< data
->size
; i
++) {
193 size_t pos
= i
>> LOG_BITS_PER_LONG
;
194 int bit
= i
& (BITS_PER_LONG
- 1);
195 unsigned long val
= data
->bits
[pos
] & (1UL << bit
);
196 count
+= hbitmap_get(data
->hb
, i
);
197 g_assert_cmpint(hbitmap_get(data
->hb
, i
), ==, val
!= 0);
199 g_assert_cmpint(count
, ==, hbitmap_count(data
->hb
));
202 static void test_hbitmap_zero(TestHBitmapData
*data
,
205 hbitmap_test_init(data
, 0, 0);
208 static void test_hbitmap_unaligned(TestHBitmapData
*data
,
211 hbitmap_test_init(data
, L3
+ 23, 0);
212 hbitmap_test_set(data
, 0, 1);
213 hbitmap_test_set(data
, L3
+ 22, 1);
216 static void test_hbitmap_iter_empty(TestHBitmapData
*data
,
219 hbitmap_test_init(data
, L1
, 0);
222 static void test_hbitmap_iter_partial(TestHBitmapData
*data
,
225 hbitmap_test_init(data
, L3
, 0);
226 hbitmap_test_set(data
, 0, L3
);
227 hbitmap_test_check(data
, 1);
228 hbitmap_test_check(data
, L1
- 1);
229 hbitmap_test_check(data
, L1
);
230 hbitmap_test_check(data
, L1
* 2 - 1);
231 hbitmap_test_check(data
, L2
- 1);
232 hbitmap_test_check(data
, L2
);
233 hbitmap_test_check(data
, L2
+ 1);
234 hbitmap_test_check(data
, L2
+ L1
);
235 hbitmap_test_check(data
, L2
+ L1
* 2 - 1);
236 hbitmap_test_check(data
, L2
* 2 - 1);
237 hbitmap_test_check(data
, L2
* 2);
238 hbitmap_test_check(data
, L2
* 2 + 1);
239 hbitmap_test_check(data
, L2
* 2 + L1
);
240 hbitmap_test_check(data
, L2
* 2 + L1
* 2 - 1);
241 hbitmap_test_check(data
, L3
/ 2);
244 static void test_hbitmap_set_all(TestHBitmapData
*data
,
247 hbitmap_test_init(data
, L3
, 0);
248 hbitmap_test_set(data
, 0, L3
);
251 static void test_hbitmap_get_all(TestHBitmapData
*data
,
254 hbitmap_test_init(data
, L3
, 0);
255 hbitmap_test_set(data
, 0, L3
);
256 hbitmap_test_check_get(data
);
259 static void test_hbitmap_get_some(TestHBitmapData
*data
,
262 hbitmap_test_init(data
, 2 * L2
, 0);
263 hbitmap_test_set(data
, 10, 1);
264 hbitmap_test_check_get(data
);
265 hbitmap_test_set(data
, L1
- 1, 1);
266 hbitmap_test_check_get(data
);
267 hbitmap_test_set(data
, L1
, 1);
268 hbitmap_test_check_get(data
);
269 hbitmap_test_set(data
, L2
- 1, 1);
270 hbitmap_test_check_get(data
);
271 hbitmap_test_set(data
, L2
, 1);
272 hbitmap_test_check_get(data
);
275 static void test_hbitmap_set_one(TestHBitmapData
*data
,
278 hbitmap_test_init(data
, 2 * L2
, 0);
279 hbitmap_test_set(data
, 10, 1);
280 hbitmap_test_set(data
, L1
- 1, 1);
281 hbitmap_test_set(data
, L1
, 1);
282 hbitmap_test_set(data
, L2
- 1, 1);
283 hbitmap_test_set(data
, L2
, 1);
286 static void test_hbitmap_set_two_elem(TestHBitmapData
*data
,
289 hbitmap_test_init(data
, 2 * L2
, 0);
290 hbitmap_test_set(data
, L1
- 1, 2);
291 hbitmap_test_set(data
, L1
* 2 - 1, 4);
292 hbitmap_test_set(data
, L1
* 4, L1
+ 1);
293 hbitmap_test_set(data
, L1
* 8 - 1, L1
+ 1);
294 hbitmap_test_set(data
, L2
- 1, 2);
295 hbitmap_test_set(data
, L2
+ L1
- 1, 8);
296 hbitmap_test_set(data
, L2
+ L1
* 4, L1
+ 1);
297 hbitmap_test_set(data
, L2
+ L1
* 8 - 1, L1
+ 1);
300 static void test_hbitmap_set(TestHBitmapData
*data
,
303 hbitmap_test_init(data
, L3
* 2, 0);
304 hbitmap_test_set(data
, L1
- 1, L1
+ 2);
305 hbitmap_test_set(data
, L1
* 3 - 1, L1
+ 2);
306 hbitmap_test_set(data
, L1
* 5, L1
* 2 + 1);
307 hbitmap_test_set(data
, L1
* 8 - 1, L1
* 2 + 1);
308 hbitmap_test_set(data
, L2
- 1, L1
+ 2);
309 hbitmap_test_set(data
, L2
+ L1
* 2 - 1, L1
+ 2);
310 hbitmap_test_set(data
, L2
+ L1
* 4, L1
* 2 + 1);
311 hbitmap_test_set(data
, L2
+ L1
* 7 - 1, L1
* 2 + 1);
312 hbitmap_test_set(data
, L2
* 2 - 1, L3
* 2 - L2
* 2);
315 static void test_hbitmap_set_twice(TestHBitmapData
*data
,
318 hbitmap_test_init(data
, L1
* 3, 0);
319 hbitmap_test_set(data
, 0, L1
* 3);
320 hbitmap_test_set(data
, L1
, 1);
323 static void test_hbitmap_set_overlap(TestHBitmapData
*data
,
326 hbitmap_test_init(data
, L3
* 2, 0);
327 hbitmap_test_set(data
, L1
- 1, L1
+ 2);
328 hbitmap_test_set(data
, L1
* 2 - 1, L1
* 2 + 2);
329 hbitmap_test_set(data
, 0, L1
* 3);
330 hbitmap_test_set(data
, L1
* 8 - 1, L2
);
331 hbitmap_test_set(data
, L2
, L1
);
332 hbitmap_test_set(data
, L2
- L1
- 1, L1
* 8 + 2);
333 hbitmap_test_set(data
, L2
, L3
- L2
+ 1);
334 hbitmap_test_set(data
, L3
- L1
, L1
* 3);
335 hbitmap_test_set(data
, L3
- 1, 3);
336 hbitmap_test_set(data
, L3
- 1, L2
);
339 static void test_hbitmap_reset_empty(TestHBitmapData
*data
,
342 hbitmap_test_init(data
, L3
, 0);
343 hbitmap_test_reset(data
, 0, L3
);
346 static void test_hbitmap_reset(TestHBitmapData
*data
,
349 hbitmap_test_init(data
, L3
* 2, 0);
350 hbitmap_test_set(data
, L1
- 1, L1
+ 2);
351 hbitmap_test_reset(data
, L1
* 2 - 1, L1
* 2 + 2);
352 hbitmap_test_set(data
, 0, L1
* 3);
353 hbitmap_test_reset(data
, L1
* 8 - 1, L2
);
354 hbitmap_test_set(data
, L2
, L1
);
355 hbitmap_test_reset(data
, L2
- L1
- 1, L1
* 8 + 2);
356 hbitmap_test_set(data
, L2
, L3
- L2
+ 1);
357 hbitmap_test_reset(data
, L3
- L1
, L1
* 3);
358 hbitmap_test_set(data
, L3
- 1, 3);
359 hbitmap_test_reset(data
, L3
- 1, L2
);
360 hbitmap_test_set(data
, 0, L3
* 2);
361 hbitmap_test_reset(data
, 0, L1
);
362 hbitmap_test_reset(data
, 0, L2
);
363 hbitmap_test_reset(data
, L3
, L3
);
364 hbitmap_test_set(data
, L3
/ 2, L3
);
367 static void test_hbitmap_granularity(TestHBitmapData
*data
,
370 /* Note that hbitmap_test_check has to be invoked manually in this test. */
371 hbitmap_test_init(data
, L1
, 1);
372 hbitmap_test_set(data
, 0, 1);
373 g_assert_cmpint(hbitmap_count(data
->hb
), ==, 2);
374 hbitmap_test_check(data
, 0);
375 hbitmap_test_set(data
, 2, 1);
376 g_assert_cmpint(hbitmap_count(data
->hb
), ==, 4);
377 hbitmap_test_check(data
, 0);
378 hbitmap_test_set(data
, 0, 3);
379 g_assert_cmpint(hbitmap_count(data
->hb
), ==, 4);
380 hbitmap_test_reset(data
, 0, 1);
381 g_assert_cmpint(hbitmap_count(data
->hb
), ==, 2);
384 static void test_hbitmap_iter_granularity(TestHBitmapData
*data
,
389 /* Note that hbitmap_test_check has to be invoked manually in this test. */
390 hbitmap_test_init(data
, 131072 << 7, 7);
391 hbitmap_iter_init(&hbi
, data
->hb
, 0);
392 g_assert_cmpint(hbitmap_iter_next(&hbi
), <, 0);
394 hbitmap_test_set(data
, ((L2
+ L1
+ 1) << 7) + 8, 8);
395 hbitmap_iter_init(&hbi
, data
->hb
, 0);
396 g_assert_cmpint(hbitmap_iter_next(&hbi
), ==, (L2
+ L1
+ 1) << 7);
397 g_assert_cmpint(hbitmap_iter_next(&hbi
), <, 0);
399 hbitmap_iter_init(&hbi
, data
->hb
, (L2
+ L1
+ 2) << 7);
400 g_assert_cmpint(hbitmap_iter_next(&hbi
), <, 0);
402 hbitmap_test_set(data
, (131072 << 7) - 8, 8);
403 hbitmap_iter_init(&hbi
, data
->hb
, 0);
404 g_assert_cmpint(hbitmap_iter_next(&hbi
), ==, (L2
+ L1
+ 1) << 7);
405 g_assert_cmpint(hbitmap_iter_next(&hbi
), ==, 131071 << 7);
406 g_assert_cmpint(hbitmap_iter_next(&hbi
), <, 0);
408 hbitmap_iter_init(&hbi
, data
->hb
, (L2
+ L1
+ 2) << 7);
409 g_assert_cmpint(hbitmap_iter_next(&hbi
), ==, 131071 << 7);
410 g_assert_cmpint(hbitmap_iter_next(&hbi
), <, 0);
413 static void hbitmap_test_set_boundary_bits(TestHBitmapData
*data
, ssize_t diff
)
415 size_t size
= data
->size
;
418 hbitmap_test_set(data
, 0, 1);
420 /* Last bit in new, shortened map */
421 hbitmap_test_set(data
, size
+ diff
- 1, 1);
423 /* First bit to be truncated away */
424 hbitmap_test_set(data
, size
+ diff
, 1);
427 hbitmap_test_set(data
, size
- 1, 1);
428 if (data
->granularity
== 0) {
429 hbitmap_test_check_get(data
);
433 static void hbitmap_test_check_boundary_bits(TestHBitmapData
*data
)
435 size_t size
= MIN(data
->size
, data
->old_size
);
437 if (data
->granularity
== 0) {
438 hbitmap_test_check_get(data
);
439 hbitmap_test_check(data
, 0);
441 /* If a granularity was set, note that every distinct
442 * (bit >> granularity) value that was set will increase
443 * the bit pop count by 2^granularity, not just 1.
445 * The hbitmap_test_check facility does not currently tolerate
446 * non-zero granularities, so test the boundaries and the population
449 g_assert(hbitmap_get(data
->hb
, 0));
450 g_assert(hbitmap_get(data
->hb
, size
- 1));
451 g_assert_cmpint(2 << data
->granularity
, ==, hbitmap_count(data
->hb
));
455 /* Generic truncate test. */
456 static void hbitmap_test_truncate(TestHBitmapData
*data
,
461 hbitmap_test_init(data
, size
, granularity
);
462 hbitmap_test_set_boundary_bits(data
, diff
);
463 hbitmap_test_truncate_impl(data
, size
+ diff
);
464 hbitmap_test_check_boundary_bits(data
);
467 static void test_hbitmap_truncate_nop(TestHBitmapData
*data
,
470 hbitmap_test_truncate(data
, L2
, 0, 0);
474 * Grow by an amount smaller than the granularity, without crossing
475 * a granularity alignment boundary. Effectively a NOP.
477 static void test_hbitmap_truncate_grow_negligible(TestHBitmapData
*data
,
480 size_t size
= L2
- 1;
484 hbitmap_test_truncate(data
, size
, diff
, granularity
);
488 * Shrink by an amount smaller than the granularity, without crossing
489 * a granularity alignment boundary. Effectively a NOP.
491 static void test_hbitmap_truncate_shrink_negligible(TestHBitmapData
*data
,
498 hbitmap_test_truncate(data
, size
, diff
, granularity
);
502 * Grow by an amount smaller than the granularity, but crossing over
503 * a granularity alignment boundary.
505 static void test_hbitmap_truncate_grow_tiny(TestHBitmapData
*data
,
508 size_t size
= L2
- 2;
512 hbitmap_test_truncate(data
, size
, diff
, granularity
);
516 * Shrink by an amount smaller than the granularity, but crossing over
517 * a granularity alignment boundary.
519 static void test_hbitmap_truncate_shrink_tiny(TestHBitmapData
*data
,
522 size_t size
= L2
- 1;
526 hbitmap_test_truncate(data
, size
, diff
, granularity
);
530 * Grow by an amount smaller than sizeof(long), and not crossing over
531 * a sizeof(long) alignment boundary.
533 static void test_hbitmap_truncate_grow_small(TestHBitmapData
*data
,
536 size_t size
= L2
+ 1;
537 size_t diff
= sizeof(long) / 2;
539 hbitmap_test_truncate(data
, size
, diff
, 0);
543 * Shrink by an amount smaller than sizeof(long), and not crossing over
544 * a sizeof(long) alignment boundary.
546 static void test_hbitmap_truncate_shrink_small(TestHBitmapData
*data
,
550 size_t diff
= sizeof(long) / 2;
552 hbitmap_test_truncate(data
, size
, -diff
, 0);
556 * Grow by an amount smaller than sizeof(long), while crossing over
557 * a sizeof(long) alignment boundary.
559 static void test_hbitmap_truncate_grow_medium(TestHBitmapData
*data
,
562 size_t size
= L2
- 1;
563 size_t diff
= sizeof(long) / 2;
565 hbitmap_test_truncate(data
, size
, diff
, 0);
569 * Shrink by an amount smaller than sizeof(long), while crossing over
570 * a sizeof(long) alignment boundary.
572 static void test_hbitmap_truncate_shrink_medium(TestHBitmapData
*data
,
575 size_t size
= L2
+ 1;
576 size_t diff
= sizeof(long) / 2;
578 hbitmap_test_truncate(data
, size
, -diff
, 0);
582 * Grow by an amount larger than sizeof(long).
584 static void test_hbitmap_truncate_grow_large(TestHBitmapData
*data
,
588 size_t diff
= 8 * sizeof(long);
590 hbitmap_test_truncate(data
, size
, diff
, 0);
594 * Shrink by an amount larger than sizeof(long).
596 static void test_hbitmap_truncate_shrink_large(TestHBitmapData
*data
,
600 size_t diff
= 8 * sizeof(long);
602 hbitmap_test_truncate(data
, size
, -diff
, 0);
605 static void hbitmap_test_add(const char *testpath
,
606 void (*test_func
)(TestHBitmapData
*data
, const void *user_data
))
608 g_test_add(testpath
, TestHBitmapData
, NULL
, NULL
, test_func
,
609 hbitmap_test_teardown
);
612 int main(int argc
, char **argv
)
614 g_test_init(&argc
, &argv
, NULL
);
615 hbitmap_test_add("/hbitmap/size/0", test_hbitmap_zero
);
616 hbitmap_test_add("/hbitmap/size/unaligned", test_hbitmap_unaligned
);
617 hbitmap_test_add("/hbitmap/iter/empty", test_hbitmap_iter_empty
);
618 hbitmap_test_add("/hbitmap/iter/partial", test_hbitmap_iter_partial
);
619 hbitmap_test_add("/hbitmap/iter/granularity", test_hbitmap_iter_granularity
);
620 hbitmap_test_add("/hbitmap/get/all", test_hbitmap_get_all
);
621 hbitmap_test_add("/hbitmap/get/some", test_hbitmap_get_some
);
622 hbitmap_test_add("/hbitmap/set/all", test_hbitmap_set_all
);
623 hbitmap_test_add("/hbitmap/set/one", test_hbitmap_set_one
);
624 hbitmap_test_add("/hbitmap/set/two-elem", test_hbitmap_set_two_elem
);
625 hbitmap_test_add("/hbitmap/set/general", test_hbitmap_set
);
626 hbitmap_test_add("/hbitmap/set/twice", test_hbitmap_set_twice
);
627 hbitmap_test_add("/hbitmap/set/overlap", test_hbitmap_set_overlap
);
628 hbitmap_test_add("/hbitmap/reset/empty", test_hbitmap_reset_empty
);
629 hbitmap_test_add("/hbitmap/reset/general", test_hbitmap_reset
);
630 hbitmap_test_add("/hbitmap/granularity", test_hbitmap_granularity
);
632 hbitmap_test_add("/hbitmap/truncate/nop", test_hbitmap_truncate_nop
);
633 hbitmap_test_add("/hbitmap/truncate/grow/negligible",
634 test_hbitmap_truncate_grow_negligible
);
635 hbitmap_test_add("/hbitmap/truncate/shrink/negligible",
636 test_hbitmap_truncate_shrink_negligible
);
637 hbitmap_test_add("/hbitmap/truncate/grow/tiny",
638 test_hbitmap_truncate_grow_tiny
);
639 hbitmap_test_add("/hbitmap/truncate/shrink/tiny",
640 test_hbitmap_truncate_shrink_tiny
);
641 hbitmap_test_add("/hbitmap/truncate/grow/small",
642 test_hbitmap_truncate_grow_small
);
643 hbitmap_test_add("/hbitmap/truncate/shrink/small",
644 test_hbitmap_truncate_shrink_small
);
645 hbitmap_test_add("/hbitmap/truncate/grow/medium",
646 test_hbitmap_truncate_grow_medium
);
647 hbitmap_test_add("/hbitmap/truncate/shrink/medium",
648 test_hbitmap_truncate_shrink_medium
);
649 hbitmap_test_add("/hbitmap/truncate/grow/large",
650 test_hbitmap_truncate_grow_large
);
651 hbitmap_test_add("/hbitmap/truncate/shrink/large",
652 test_hbitmap_truncate_shrink_large
);