test-hbitmap.c (37130B)
1/* 2 * Hierarchical bitmap unit-tests. 3 * 4 * Copyright (C) 2012 Red Hat Inc. 5 * 6 * Author: Paolo Bonzini <pbonzini@redhat.com> 7 * 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. 10 */ 11 12#include "qemu/osdep.h" 13#include "qemu/hbitmap.h" 14#include "qemu/bitmap.h" 15#include "block/block.h" 16 17#define LOG_BITS_PER_LONG (BITS_PER_LONG == 32 ? 5 : 6) 18 19#define L1 BITS_PER_LONG 20#define L2 (BITS_PER_LONG * L1) 21#define L3 (BITS_PER_LONG * L2) 22 23typedef struct TestHBitmapData { 24 HBitmap *hb; 25 unsigned long *bits; 26 size_t size; 27 size_t old_size; 28 int granularity; 29} TestHBitmapData; 30 31 32/* Check that the HBitmap and the shadow bitmap contain the same data, 33 * ignoring the same "first" bits. 34 */ 35static void hbitmap_test_check(TestHBitmapData *data, 36 uint64_t first) 37{ 38 uint64_t count = 0; 39 size_t pos; 40 int bit; 41 HBitmapIter hbi; 42 int64_t i, next; 43 44 hbitmap_iter_init(&hbi, data->hb, first); 45 46 i = first; 47 for (;;) { 48 next = hbitmap_iter_next(&hbi); 49 if (next < 0) { 50 next = data->size; 51 } 52 53 while (i < next) { 54 pos = i >> LOG_BITS_PER_LONG; 55 bit = i & (BITS_PER_LONG - 1); 56 i++; 57 g_assert_cmpint(data->bits[pos] & (1UL << bit), ==, 0); 58 } 59 60 if (next == data->size) { 61 break; 62 } 63 64 pos = i >> LOG_BITS_PER_LONG; 65 bit = i & (BITS_PER_LONG - 1); 66 i++; 67 count++; 68 g_assert_cmpint(data->bits[pos] & (1UL << bit), !=, 0); 69 } 70 71 if (first == 0) { 72 g_assert_cmpint(count << data->granularity, ==, hbitmap_count(data->hb)); 73 } 74} 75 76/* This is provided instead of a test setup function so that the sizes 77 are kept in the test functions (and not in main()) */ 78static void hbitmap_test_init(TestHBitmapData *data, 79 uint64_t size, int granularity) 80{ 81 size_t n; 82 data->hb = hbitmap_alloc(size, granularity); 83 84 n = DIV_ROUND_UP(size, BITS_PER_LONG); 85 if (n == 0) { 86 n = 1; 87 } 88 data->bits = g_new0(unsigned long, n); 89 data->size = size; 90 data->granularity = granularity; 91 if (size) { 92 hbitmap_test_check(data, 0); 93 } 94} 95 96static inline size_t hbitmap_test_array_size(size_t bits) 97{ 98 size_t n = DIV_ROUND_UP(bits, BITS_PER_LONG); 99 return n ? n : 1; 100} 101 102static void hbitmap_test_truncate_impl(TestHBitmapData *data, 103 size_t size) 104{ 105 size_t n; 106 size_t m; 107 data->old_size = data->size; 108 data->size = size; 109 110 if (data->size == data->old_size) { 111 return; 112 } 113 114 n = hbitmap_test_array_size(size); 115 m = hbitmap_test_array_size(data->old_size); 116 data->bits = g_realloc(data->bits, sizeof(unsigned long) * n); 117 if (n > m) { 118 memset(&data->bits[m], 0x00, sizeof(unsigned long) * (n - m)); 119 } 120 121 /* If we shrink to an uneven multiple of sizeof(unsigned long), 122 * scrub the leftover memory. */ 123 if (data->size < data->old_size) { 124 m = size % (sizeof(unsigned long) * 8); 125 if (m) { 126 unsigned long mask = (1ULL << m) - 1; 127 data->bits[n-1] &= mask; 128 } 129 } 130 131 hbitmap_truncate(data->hb, size); 132} 133 134static void hbitmap_test_teardown(TestHBitmapData *data, 135 const void *unused) 136{ 137 if (data->hb) { 138 hbitmap_free(data->hb); 139 data->hb = NULL; 140 } 141 g_free(data->bits); 142 data->bits = NULL; 143} 144 145/* Set a range in the HBitmap and in the shadow "simple" bitmap. 146 * The two bitmaps are then tested against each other. 147 */ 148static void hbitmap_test_set(TestHBitmapData *data, 149 uint64_t first, uint64_t count) 150{ 151 hbitmap_set(data->hb, first, count); 152 while (count-- != 0) { 153 size_t pos = first >> LOG_BITS_PER_LONG; 154 int bit = first & (BITS_PER_LONG - 1); 155 first++; 156 157 data->bits[pos] |= 1UL << bit; 158 } 159 160 if (data->granularity == 0) { 161 hbitmap_test_check(data, 0); 162 } 163} 164 165/* Reset a range in the HBitmap and in the shadow "simple" bitmap. 166 */ 167static void hbitmap_test_reset(TestHBitmapData *data, 168 uint64_t first, uint64_t count) 169{ 170 hbitmap_reset(data->hb, first, count); 171 while (count-- != 0) { 172 size_t pos = first >> LOG_BITS_PER_LONG; 173 int bit = first & (BITS_PER_LONG - 1); 174 first++; 175 176 data->bits[pos] &= ~(1UL << bit); 177 } 178 179 if (data->granularity == 0) { 180 hbitmap_test_check(data, 0); 181 } 182} 183 184static void hbitmap_test_reset_all(TestHBitmapData *data) 185{ 186 size_t n; 187 188 hbitmap_reset_all(data->hb); 189 190 n = DIV_ROUND_UP(data->size, BITS_PER_LONG); 191 if (n == 0) { 192 n = 1; 193 } 194 memset(data->bits, 0, n * sizeof(unsigned long)); 195 196 if (data->granularity == 0) { 197 hbitmap_test_check(data, 0); 198 } 199} 200 201static void hbitmap_test_check_get(TestHBitmapData *data) 202{ 203 uint64_t count = 0; 204 uint64_t i; 205 206 for (i = 0; i < data->size; i++) { 207 size_t pos = i >> LOG_BITS_PER_LONG; 208 int bit = i & (BITS_PER_LONG - 1); 209 unsigned long val = data->bits[pos] & (1UL << bit); 210 count += hbitmap_get(data->hb, i); 211 g_assert_cmpint(hbitmap_get(data->hb, i), ==, val != 0); 212 } 213 g_assert_cmpint(count, ==, hbitmap_count(data->hb)); 214} 215 216static void test_hbitmap_zero(TestHBitmapData *data, 217 const void *unused) 218{ 219 hbitmap_test_init(data, 0, 0); 220} 221 222static void test_hbitmap_unaligned(TestHBitmapData *data, 223 const void *unused) 224{ 225 hbitmap_test_init(data, L3 + 23, 0); 226 hbitmap_test_set(data, 0, 1); 227 hbitmap_test_set(data, L3 + 22, 1); 228} 229 230static void test_hbitmap_iter_empty(TestHBitmapData *data, 231 const void *unused) 232{ 233 hbitmap_test_init(data, L1, 0); 234} 235 236static void test_hbitmap_iter_partial(TestHBitmapData *data, 237 const void *unused) 238{ 239 hbitmap_test_init(data, L3, 0); 240 hbitmap_test_set(data, 0, L3); 241 hbitmap_test_check(data, 1); 242 hbitmap_test_check(data, L1 - 1); 243 hbitmap_test_check(data, L1); 244 hbitmap_test_check(data, L1 * 2 - 1); 245 hbitmap_test_check(data, L2 - 1); 246 hbitmap_test_check(data, L2); 247 hbitmap_test_check(data, L2 + 1); 248 hbitmap_test_check(data, L2 + L1); 249 hbitmap_test_check(data, L2 + L1 * 2 - 1); 250 hbitmap_test_check(data, L2 * 2 - 1); 251 hbitmap_test_check(data, L2 * 2); 252 hbitmap_test_check(data, L2 * 2 + 1); 253 hbitmap_test_check(data, L2 * 2 + L1); 254 hbitmap_test_check(data, L2 * 2 + L1 * 2 - 1); 255 hbitmap_test_check(data, L3 / 2); 256} 257 258static void test_hbitmap_set_all(TestHBitmapData *data, 259 const void *unused) 260{ 261 hbitmap_test_init(data, L3, 0); 262 hbitmap_test_set(data, 0, L3); 263} 264 265static void test_hbitmap_get_all(TestHBitmapData *data, 266 const void *unused) 267{ 268 hbitmap_test_init(data, L3, 0); 269 hbitmap_test_set(data, 0, L3); 270 hbitmap_test_check_get(data); 271} 272 273static void test_hbitmap_get_some(TestHBitmapData *data, 274 const void *unused) 275{ 276 hbitmap_test_init(data, 2 * L2, 0); 277 hbitmap_test_set(data, 10, 1); 278 hbitmap_test_check_get(data); 279 hbitmap_test_set(data, L1 - 1, 1); 280 hbitmap_test_check_get(data); 281 hbitmap_test_set(data, L1, 1); 282 hbitmap_test_check_get(data); 283 hbitmap_test_set(data, L2 - 1, 1); 284 hbitmap_test_check_get(data); 285 hbitmap_test_set(data, L2, 1); 286 hbitmap_test_check_get(data); 287} 288 289static void test_hbitmap_set_one(TestHBitmapData *data, 290 const void *unused) 291{ 292 hbitmap_test_init(data, 2 * L2, 0); 293 hbitmap_test_set(data, 10, 1); 294 hbitmap_test_set(data, L1 - 1, 1); 295 hbitmap_test_set(data, L1, 1); 296 hbitmap_test_set(data, L2 - 1, 1); 297 hbitmap_test_set(data, L2, 1); 298} 299 300static void test_hbitmap_set_two_elem(TestHBitmapData *data, 301 const void *unused) 302{ 303 hbitmap_test_init(data, 2 * L2, 0); 304 hbitmap_test_set(data, L1 - 1, 2); 305 hbitmap_test_set(data, L1 * 2 - 1, 4); 306 hbitmap_test_set(data, L1 * 4, L1 + 1); 307 hbitmap_test_set(data, L1 * 8 - 1, L1 + 1); 308 hbitmap_test_set(data, L2 - 1, 2); 309 hbitmap_test_set(data, L2 + L1 - 1, 8); 310 hbitmap_test_set(data, L2 + L1 * 4, L1 + 1); 311 hbitmap_test_set(data, L2 + L1 * 8 - 1, L1 + 1); 312} 313 314static void test_hbitmap_set(TestHBitmapData *data, 315 const void *unused) 316{ 317 hbitmap_test_init(data, L3 * 2, 0); 318 hbitmap_test_set(data, L1 - 1, L1 + 2); 319 hbitmap_test_set(data, L1 * 3 - 1, L1 + 2); 320 hbitmap_test_set(data, L1 * 5, L1 * 2 + 1); 321 hbitmap_test_set(data, L1 * 8 - 1, L1 * 2 + 1); 322 hbitmap_test_set(data, L2 - 1, L1 + 2); 323 hbitmap_test_set(data, L2 + L1 * 2 - 1, L1 + 2); 324 hbitmap_test_set(data, L2 + L1 * 4, L1 * 2 + 1); 325 hbitmap_test_set(data, L2 + L1 * 7 - 1, L1 * 2 + 1); 326 hbitmap_test_set(data, L2 * 2 - 1, L3 * 2 - L2 * 2); 327} 328 329static void test_hbitmap_set_twice(TestHBitmapData *data, 330 const void *unused) 331{ 332 hbitmap_test_init(data, L1 * 3, 0); 333 hbitmap_test_set(data, 0, L1 * 3); 334 hbitmap_test_set(data, L1, 1); 335} 336 337static void test_hbitmap_set_overlap(TestHBitmapData *data, 338 const void *unused) 339{ 340 hbitmap_test_init(data, L3 * 2, 0); 341 hbitmap_test_set(data, L1 - 1, L1 + 2); 342 hbitmap_test_set(data, L1 * 2 - 1, L1 * 2 + 2); 343 hbitmap_test_set(data, 0, L1 * 3); 344 hbitmap_test_set(data, L1 * 8 - 1, L2); 345 hbitmap_test_set(data, L2, L1); 346 hbitmap_test_set(data, L2 - L1 - 1, L1 * 8 + 2); 347 hbitmap_test_set(data, L2, L3 - L2 + 1); 348 hbitmap_test_set(data, L3 - L1, L1 * 3); 349 hbitmap_test_set(data, L3 - 1, 3); 350 hbitmap_test_set(data, L3 - 1, L2); 351} 352 353static void test_hbitmap_reset_empty(TestHBitmapData *data, 354 const void *unused) 355{ 356 hbitmap_test_init(data, L3, 0); 357 hbitmap_test_reset(data, 0, L3); 358} 359 360static void test_hbitmap_reset(TestHBitmapData *data, 361 const void *unused) 362{ 363 hbitmap_test_init(data, L3 * 2, 0); 364 hbitmap_test_set(data, L1 - 1, L1 + 2); 365 hbitmap_test_reset(data, L1 * 2 - 1, L1 * 2 + 2); 366 hbitmap_test_set(data, 0, L1 * 3); 367 hbitmap_test_reset(data, L1 * 8 - 1, L2); 368 hbitmap_test_set(data, L2, L1); 369 hbitmap_test_reset(data, L2 - L1 - 1, L1 * 8 + 2); 370 hbitmap_test_set(data, L2, L3 - L2 + 1); 371 hbitmap_test_reset(data, L3 - L1, L1 * 3); 372 hbitmap_test_set(data, L3 - 1, 3); 373 hbitmap_test_reset(data, L3 - 1, L2); 374 hbitmap_test_set(data, 0, L3 * 2); 375 hbitmap_test_reset(data, 0, L1); 376 hbitmap_test_reset(data, 0, L2); 377 hbitmap_test_reset(data, L3, L3); 378 hbitmap_test_set(data, L3 / 2, L3); 379} 380 381static void test_hbitmap_reset_all(TestHBitmapData *data, 382 const void *unused) 383{ 384 hbitmap_test_init(data, L3 * 2, 0); 385 hbitmap_test_set(data, L1 - 1, L1 + 2); 386 hbitmap_test_reset_all(data); 387 hbitmap_test_set(data, 0, L1 * 3); 388 hbitmap_test_reset_all(data); 389 hbitmap_test_set(data, L2, L1); 390 hbitmap_test_reset_all(data); 391 hbitmap_test_set(data, L2, L3 - L2 + 1); 392 hbitmap_test_reset_all(data); 393 hbitmap_test_set(data, L3 - 1, 3); 394 hbitmap_test_reset_all(data); 395 hbitmap_test_set(data, 0, L3 * 2); 396 hbitmap_test_reset_all(data); 397 hbitmap_test_set(data, L3 / 2, L3); 398 hbitmap_test_reset_all(data); 399} 400 401static void test_hbitmap_granularity(TestHBitmapData *data, 402 const void *unused) 403{ 404 /* Note that hbitmap_test_check has to be invoked manually in this test. */ 405 hbitmap_test_init(data, L1, 1); 406 hbitmap_test_set(data, 0, 1); 407 g_assert_cmpint(hbitmap_count(data->hb), ==, 2); 408 hbitmap_test_check(data, 0); 409 hbitmap_test_set(data, 2, 1); 410 g_assert_cmpint(hbitmap_count(data->hb), ==, 4); 411 hbitmap_test_check(data, 0); 412 hbitmap_test_set(data, 0, 3); 413 g_assert_cmpint(hbitmap_count(data->hb), ==, 4); 414 hbitmap_test_reset(data, 0, 2); 415 g_assert_cmpint(hbitmap_count(data->hb), ==, 2); 416} 417 418static void test_hbitmap_iter_granularity(TestHBitmapData *data, 419 const void *unused) 420{ 421 HBitmapIter hbi; 422 423 /* Note that hbitmap_test_check has to be invoked manually in this test. */ 424 hbitmap_test_init(data, 131072 << 7, 7); 425 hbitmap_iter_init(&hbi, data->hb, 0); 426 g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0); 427 428 hbitmap_test_set(data, ((L2 + L1 + 1) << 7) + 8, 8); 429 hbitmap_iter_init(&hbi, data->hb, 0); 430 g_assert_cmpint(hbitmap_iter_next(&hbi), ==, (L2 + L1 + 1) << 7); 431 g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0); 432 433 hbitmap_iter_init(&hbi, data->hb, (L2 + L1 + 2) << 7); 434 g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0); 435 436 hbitmap_test_set(data, (131072 << 7) - 8, 8); 437 hbitmap_iter_init(&hbi, data->hb, 0); 438 g_assert_cmpint(hbitmap_iter_next(&hbi), ==, (L2 + L1 + 1) << 7); 439 g_assert_cmpint(hbitmap_iter_next(&hbi), ==, 131071 << 7); 440 g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0); 441 442 hbitmap_iter_init(&hbi, data->hb, (L2 + L1 + 2) << 7); 443 g_assert_cmpint(hbitmap_iter_next(&hbi), ==, 131071 << 7); 444 g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0); 445} 446 447static void hbitmap_test_set_boundary_bits(TestHBitmapData *data, ssize_t diff) 448{ 449 size_t size = data->size; 450 451 /* First bit */ 452 hbitmap_test_set(data, 0, 1); 453 if (diff < 0) { 454 /* Last bit in new, shortened map */ 455 hbitmap_test_set(data, size + diff - 1, 1); 456 457 /* First bit to be truncated away */ 458 hbitmap_test_set(data, size + diff, 1); 459 } 460 /* Last bit */ 461 hbitmap_test_set(data, size - 1, 1); 462 if (data->granularity == 0) { 463 hbitmap_test_check_get(data); 464 } 465} 466 467static void hbitmap_test_check_boundary_bits(TestHBitmapData *data) 468{ 469 size_t size = MIN(data->size, data->old_size); 470 471 if (data->granularity == 0) { 472 hbitmap_test_check_get(data); 473 hbitmap_test_check(data, 0); 474 } else { 475 /* If a granularity was set, note that every distinct 476 * (bit >> granularity) value that was set will increase 477 * the bit pop count by 2^granularity, not just 1. 478 * 479 * The hbitmap_test_check facility does not currently tolerate 480 * non-zero granularities, so test the boundaries and the population 481 * count manually. 482 */ 483 g_assert(hbitmap_get(data->hb, 0)); 484 g_assert(hbitmap_get(data->hb, size - 1)); 485 g_assert_cmpint(2 << data->granularity, ==, hbitmap_count(data->hb)); 486 } 487} 488 489/* Generic truncate test. */ 490static void hbitmap_test_truncate(TestHBitmapData *data, 491 size_t size, 492 ssize_t diff, 493 int granularity) 494{ 495 hbitmap_test_init(data, size, granularity); 496 hbitmap_test_set_boundary_bits(data, diff); 497 hbitmap_test_truncate_impl(data, size + diff); 498 hbitmap_test_check_boundary_bits(data); 499} 500 501static void test_hbitmap_truncate_nop(TestHBitmapData *data, 502 const void *unused) 503{ 504 hbitmap_test_truncate(data, L2, 0, 0); 505} 506 507/** 508 * Grow by an amount smaller than the granularity, without crossing 509 * a granularity alignment boundary. Effectively a NOP. 510 */ 511static void test_hbitmap_truncate_grow_negligible(TestHBitmapData *data, 512 const void *unused) 513{ 514 size_t size = L2 - 1; 515 size_t diff = 1; 516 int granularity = 1; 517 518 hbitmap_test_truncate(data, size, diff, granularity); 519} 520 521/** 522 * Shrink by an amount smaller than the granularity, without crossing 523 * a granularity alignment boundary. Effectively a NOP. 524 */ 525static void test_hbitmap_truncate_shrink_negligible(TestHBitmapData *data, 526 const void *unused) 527{ 528 size_t size = L2; 529 ssize_t diff = -1; 530 int granularity = 1; 531 532 hbitmap_test_truncate(data, size, diff, granularity); 533} 534 535/** 536 * Grow by an amount smaller than the granularity, but crossing over 537 * a granularity alignment boundary. 538 */ 539static void test_hbitmap_truncate_grow_tiny(TestHBitmapData *data, 540 const void *unused) 541{ 542 size_t size = L2 - 2; 543 ssize_t diff = 1; 544 int granularity = 1; 545 546 hbitmap_test_truncate(data, size, diff, granularity); 547} 548 549/** 550 * Shrink by an amount smaller than the granularity, but crossing over 551 * a granularity alignment boundary. 552 */ 553static void test_hbitmap_truncate_shrink_tiny(TestHBitmapData *data, 554 const void *unused) 555{ 556 size_t size = L2 - 1; 557 ssize_t diff = -1; 558 int granularity = 1; 559 560 hbitmap_test_truncate(data, size, diff, granularity); 561} 562 563/** 564 * Grow by an amount smaller than sizeof(long), and not crossing over 565 * a sizeof(long) alignment boundary. 566 */ 567static void test_hbitmap_truncate_grow_small(TestHBitmapData *data, 568 const void *unused) 569{ 570 size_t size = L2 + 1; 571 size_t diff = sizeof(long) / 2; 572 573 hbitmap_test_truncate(data, size, diff, 0); 574} 575 576/** 577 * Shrink by an amount smaller than sizeof(long), and not crossing over 578 * a sizeof(long) alignment boundary. 579 */ 580static void test_hbitmap_truncate_shrink_small(TestHBitmapData *data, 581 const void *unused) 582{ 583 size_t size = L2; 584 size_t diff = sizeof(long) / 2; 585 586 hbitmap_test_truncate(data, size, -diff, 0); 587} 588 589/** 590 * Grow by an amount smaller than sizeof(long), while crossing over 591 * a sizeof(long) alignment boundary. 592 */ 593static void test_hbitmap_truncate_grow_medium(TestHBitmapData *data, 594 const void *unused) 595{ 596 size_t size = L2 - 1; 597 size_t diff = sizeof(long) / 2; 598 599 hbitmap_test_truncate(data, size, diff, 0); 600} 601 602/** 603 * Shrink by an amount smaller than sizeof(long), while crossing over 604 * a sizeof(long) alignment boundary. 605 */ 606static void test_hbitmap_truncate_shrink_medium(TestHBitmapData *data, 607 const void *unused) 608{ 609 size_t size = L2 + 1; 610 size_t diff = sizeof(long) / 2; 611 612 hbitmap_test_truncate(data, size, -diff, 0); 613} 614 615/** 616 * Grow by an amount larger than sizeof(long). 617 */ 618static void test_hbitmap_truncate_grow_large(TestHBitmapData *data, 619 const void *unused) 620{ 621 size_t size = L2; 622 size_t diff = 8 * sizeof(long); 623 624 hbitmap_test_truncate(data, size, diff, 0); 625} 626 627/** 628 * Shrink by an amount larger than sizeof(long). 629 */ 630static void test_hbitmap_truncate_shrink_large(TestHBitmapData *data, 631 const void *unused) 632{ 633 size_t size = L2; 634 size_t diff = 8 * sizeof(long); 635 636 hbitmap_test_truncate(data, size, -diff, 0); 637} 638 639static void test_hbitmap_serialize_align(TestHBitmapData *data, 640 const void *unused) 641{ 642 int r; 643 644 hbitmap_test_init(data, L3 * 2, 3); 645 g_assert(hbitmap_is_serializable(data->hb)); 646 647 r = hbitmap_serialization_align(data->hb); 648 g_assert_cmpint(r, ==, 64 << 3); 649} 650 651static void hbitmap_test_serialize_range(TestHBitmapData *data, 652 uint8_t *buf, size_t buf_size, 653 uint64_t pos, uint64_t count) 654{ 655 size_t i; 656 unsigned long *el = (unsigned long *)buf; 657 658 assert(hbitmap_granularity(data->hb) == 0); 659 hbitmap_reset_all(data->hb); 660 memset(buf, 0, buf_size); 661 if (count) { 662 hbitmap_set(data->hb, pos, count); 663 } 664 665 g_assert(hbitmap_is_serializable(data->hb)); 666 hbitmap_serialize_part(data->hb, buf, 0, data->size); 667 668 /* Serialized buffer is inherently LE, convert it back manually to test */ 669 for (i = 0; i < buf_size / sizeof(unsigned long); i++) { 670 el[i] = (BITS_PER_LONG == 32 ? le32_to_cpu(el[i]) : le64_to_cpu(el[i])); 671 } 672 673 for (i = 0; i < data->size; i++) { 674 int is_set = test_bit(i, (unsigned long *)buf); 675 if (i >= pos && i < pos + count) { 676 g_assert(is_set); 677 } else { 678 g_assert(!is_set); 679 } 680 } 681 682 /* Re-serialize for deserialization testing */ 683 memset(buf, 0, buf_size); 684 hbitmap_serialize_part(data->hb, buf, 0, data->size); 685 hbitmap_reset_all(data->hb); 686 687 g_assert(hbitmap_is_serializable(data->hb)); 688 hbitmap_deserialize_part(data->hb, buf, 0, data->size, true); 689 690 for (i = 0; i < data->size; i++) { 691 int is_set = hbitmap_get(data->hb, i); 692 if (i >= pos && i < pos + count) { 693 g_assert(is_set); 694 } else { 695 g_assert(!is_set); 696 } 697 } 698} 699 700static void test_hbitmap_serialize_basic(TestHBitmapData *data, 701 const void *unused) 702{ 703 int i, j; 704 size_t buf_size; 705 uint8_t *buf; 706 uint64_t positions[] = { 0, 1, L1 - 1, L1, L2 - 1, L2, L2 + 1, L3 - 1 }; 707 int num_positions = ARRAY_SIZE(positions); 708 709 hbitmap_test_init(data, L3, 0); 710 g_assert(hbitmap_is_serializable(data->hb)); 711 buf_size = hbitmap_serialization_size(data->hb, 0, data->size); 712 buf = g_malloc0(buf_size); 713 714 for (i = 0; i < num_positions; i++) { 715 for (j = 0; j < num_positions; j++) { 716 hbitmap_test_serialize_range(data, buf, buf_size, 717 positions[i], 718 MIN(positions[j], L3 - positions[i])); 719 } 720 } 721 722 g_free(buf); 723} 724 725static void test_hbitmap_serialize_part(TestHBitmapData *data, 726 const void *unused) 727{ 728 int i, j, k; 729 size_t buf_size; 730 uint8_t *buf; 731 uint64_t positions[] = { 0, 1, L1 - 1, L1, L2 - 1, L2, L2 + 1, L3 - 1 }; 732 int num_positions = ARRAY_SIZE(positions); 733 734 hbitmap_test_init(data, L3, 0); 735 buf_size = L2; 736 buf = g_malloc0(buf_size); 737 738 for (i = 0; i < num_positions; i++) { 739 hbitmap_set(data->hb, positions[i], 1); 740 } 741 742 g_assert(hbitmap_is_serializable(data->hb)); 743 744 for (i = 0; i < data->size; i += buf_size) { 745 unsigned long *el = (unsigned long *)buf; 746 hbitmap_serialize_part(data->hb, buf, i, buf_size); 747 for (j = 0; j < buf_size / sizeof(unsigned long); j++) { 748 el[j] = (BITS_PER_LONG == 32 ? le32_to_cpu(el[j]) : le64_to_cpu(el[j])); 749 } 750 751 for (j = 0; j < buf_size; j++) { 752 bool should_set = false; 753 for (k = 0; k < num_positions; k++) { 754 if (positions[k] == j + i) { 755 should_set = true; 756 break; 757 } 758 } 759 g_assert_cmpint(should_set, ==, test_bit(j, (unsigned long *)buf)); 760 } 761 } 762 763 g_free(buf); 764} 765 766static void test_hbitmap_serialize_zeroes(TestHBitmapData *data, 767 const void *unused) 768{ 769 int i; 770 HBitmapIter iter; 771 int64_t next; 772 uint64_t min_l1 = MAX(L1, 64); 773 uint64_t positions[] = { 0, min_l1, L2, L3 - min_l1}; 774 int num_positions = ARRAY_SIZE(positions); 775 776 hbitmap_test_init(data, L3, 0); 777 778 for (i = 0; i < num_positions; i++) { 779 hbitmap_set(data->hb, positions[i], L1); 780 } 781 782 g_assert(hbitmap_is_serializable(data->hb)); 783 784 for (i = 0; i < num_positions; i++) { 785 hbitmap_deserialize_zeroes(data->hb, positions[i], min_l1, true); 786 hbitmap_iter_init(&iter, data->hb, 0); 787 next = hbitmap_iter_next(&iter); 788 if (i == num_positions - 1) { 789 g_assert_cmpint(next, ==, -1); 790 } else { 791 g_assert_cmpint(next, ==, positions[i + 1]); 792 } 793 } 794} 795 796static void hbitmap_test_add(const char *testpath, 797 void (*test_func)(TestHBitmapData *data, const void *user_data)) 798{ 799 g_test_add(testpath, TestHBitmapData, NULL, NULL, test_func, 800 hbitmap_test_teardown); 801} 802 803static void test_hbitmap_iter_and_reset(TestHBitmapData *data, 804 const void *unused) 805{ 806 HBitmapIter hbi; 807 808 hbitmap_test_init(data, L1 * 2, 0); 809 hbitmap_set(data->hb, 0, data->size); 810 811 hbitmap_iter_init(&hbi, data->hb, BITS_PER_LONG - 1); 812 813 hbitmap_iter_next(&hbi); 814 815 hbitmap_reset_all(data->hb); 816 hbitmap_iter_next(&hbi); 817} 818 819static void test_hbitmap_next_x_check_range(TestHBitmapData *data, 820 int64_t start, 821 int64_t count) 822{ 823 int64_t next_zero = hbitmap_next_zero(data->hb, start, count); 824 int64_t next_dirty = hbitmap_next_dirty(data->hb, start, count); 825 int64_t next; 826 int64_t end = start >= data->size || data->size - start < count ? 827 data->size : start + count; 828 bool first_bit = hbitmap_get(data->hb, start); 829 830 for (next = start; 831 next < end && hbitmap_get(data->hb, next) == first_bit; 832 next++) 833 { 834 ; 835 } 836 837 if (next == end) { 838 next = -1; 839 } 840 841 g_assert_cmpint(next_dirty, ==, first_bit ? start : next); 842 g_assert_cmpint(next_zero, ==, first_bit ? next : start); 843} 844 845static void test_hbitmap_next_x_check(TestHBitmapData *data, int64_t start) 846{ 847 test_hbitmap_next_x_check_range(data, start, INT64_MAX); 848} 849 850static void test_hbitmap_next_x_do(TestHBitmapData *data, int granularity) 851{ 852 hbitmap_test_init(data, L3, granularity); 853 test_hbitmap_next_x_check(data, 0); 854 test_hbitmap_next_x_check(data, L3 - 1); 855 test_hbitmap_next_x_check_range(data, 0, 1); 856 test_hbitmap_next_x_check_range(data, L3 - 1, 1); 857 858 hbitmap_set(data->hb, L2, 1); 859 test_hbitmap_next_x_check(data, 0); 860 test_hbitmap_next_x_check(data, L2 - 1); 861 test_hbitmap_next_x_check(data, L2); 862 test_hbitmap_next_x_check(data, L2 + 1); 863 test_hbitmap_next_x_check_range(data, 0, 1); 864 test_hbitmap_next_x_check_range(data, 0, L2); 865 test_hbitmap_next_x_check_range(data, L2 - 1, 1); 866 test_hbitmap_next_x_check_range(data, L2 - 1, 2); 867 test_hbitmap_next_x_check_range(data, L2, 1); 868 test_hbitmap_next_x_check_range(data, L2 + 1, 1); 869 870 hbitmap_set(data->hb, L2 + 5, L1); 871 test_hbitmap_next_x_check(data, 0); 872 test_hbitmap_next_x_check(data, L2 - L1); 873 test_hbitmap_next_x_check(data, L2 + 1); 874 test_hbitmap_next_x_check(data, L2 + 2); 875 test_hbitmap_next_x_check(data, L2 + 5); 876 test_hbitmap_next_x_check(data, L2 + L1 - 1); 877 test_hbitmap_next_x_check(data, L2 + L1); 878 test_hbitmap_next_x_check(data, L2 + L1 + 1); 879 test_hbitmap_next_x_check_range(data, L2 - 2, L1); 880 test_hbitmap_next_x_check_range(data, L2, 4); 881 test_hbitmap_next_x_check_range(data, L2, 6); 882 test_hbitmap_next_x_check_range(data, L2 + 1, 3); 883 test_hbitmap_next_x_check_range(data, L2 + 4, L1); 884 test_hbitmap_next_x_check_range(data, L2 + 5, L1); 885 test_hbitmap_next_x_check_range(data, L2 + 5 + L1 - 1, 1); 886 test_hbitmap_next_x_check_range(data, L2 + 5 + L1, 1); 887 test_hbitmap_next_x_check_range(data, L2 + 5 + L1 + 1, 1); 888 889 hbitmap_set(data->hb, L2 * 2, L3 - L2 * 2); 890 test_hbitmap_next_x_check(data, L2 * 2 - L1); 891 test_hbitmap_next_x_check(data, L2 * 2 - 2); 892 test_hbitmap_next_x_check(data, L2 * 2 - 1); 893 test_hbitmap_next_x_check(data, L2 * 2); 894 test_hbitmap_next_x_check(data, L2 * 2 + 1); 895 test_hbitmap_next_x_check(data, L2 * 2 + L1); 896 test_hbitmap_next_x_check(data, L3 - 1); 897 test_hbitmap_next_x_check_range(data, L2 * 2 - L1, L1 + 1); 898 test_hbitmap_next_x_check_range(data, L2 * 2, L2); 899 900 hbitmap_set(data->hb, 0, L3); 901 test_hbitmap_next_x_check(data, 0); 902} 903 904static void test_hbitmap_next_x_0(TestHBitmapData *data, const void *unused) 905{ 906 test_hbitmap_next_x_do(data, 0); 907} 908 909static void test_hbitmap_next_x_4(TestHBitmapData *data, const void *unused) 910{ 911 test_hbitmap_next_x_do(data, 4); 912} 913 914static void test_hbitmap_next_x_after_truncate(TestHBitmapData *data, 915 const void *unused) 916{ 917 hbitmap_test_init(data, L1, 0); 918 hbitmap_test_truncate_impl(data, L1 * 2); 919 hbitmap_set(data->hb, 0, L1); 920 test_hbitmap_next_x_check(data, 0); 921} 922 923static void test_hbitmap_next_dirty_area_check_limited(TestHBitmapData *data, 924 int64_t offset, 925 int64_t count, 926 int64_t max_dirty) 927{ 928 int64_t off1, off2; 929 int64_t len1 = 0, len2; 930 bool ret1, ret2; 931 int64_t end; 932 933 ret1 = hbitmap_next_dirty_area(data->hb, 934 offset, count == INT64_MAX ? INT64_MAX : offset + count, max_dirty, 935 &off1, &len1); 936 937 end = offset > data->size || data->size - offset < count ? data->size : 938 offset + count; 939 940 for (off2 = offset; off2 < end && !hbitmap_get(data->hb, off2); off2++) { 941 ; 942 } 943 944 for (len2 = 1; (off2 + len2 < end && len2 < max_dirty && 945 hbitmap_get(data->hb, off2 + len2)); len2++) 946 { 947 ; 948 } 949 950 ret2 = off2 < end; 951 g_assert_cmpint(ret1, ==, ret2); 952 953 if (ret2) { 954 g_assert_cmpint(off1, ==, off2); 955 g_assert_cmpint(len1, ==, len2); 956 } 957} 958 959static void test_hbitmap_next_dirty_area_check(TestHBitmapData *data, 960 int64_t offset, int64_t count) 961{ 962 test_hbitmap_next_dirty_area_check_limited(data, offset, count, INT64_MAX); 963} 964 965static void test_hbitmap_next_dirty_area_do(TestHBitmapData *data, 966 int granularity) 967{ 968 hbitmap_test_init(data, L3, granularity); 969 test_hbitmap_next_dirty_area_check(data, 0, INT64_MAX); 970 test_hbitmap_next_dirty_area_check(data, 0, 1); 971 test_hbitmap_next_dirty_area_check(data, L3 - 1, 1); 972 test_hbitmap_next_dirty_area_check_limited(data, 0, INT64_MAX, 1); 973 974 hbitmap_set(data->hb, L2, 1); 975 test_hbitmap_next_dirty_area_check(data, 0, 1); 976 test_hbitmap_next_dirty_area_check(data, 0, L2); 977 test_hbitmap_next_dirty_area_check(data, 0, INT64_MAX); 978 test_hbitmap_next_dirty_area_check(data, L2 - 1, INT64_MAX); 979 test_hbitmap_next_dirty_area_check(data, L2 - 1, 1); 980 test_hbitmap_next_dirty_area_check(data, L2 - 1, 2); 981 test_hbitmap_next_dirty_area_check(data, L2 - 1, 3); 982 test_hbitmap_next_dirty_area_check(data, L2, INT64_MAX); 983 test_hbitmap_next_dirty_area_check(data, L2, 1); 984 test_hbitmap_next_dirty_area_check(data, L2 + 1, 1); 985 test_hbitmap_next_dirty_area_check_limited(data, 0, INT64_MAX, 1); 986 test_hbitmap_next_dirty_area_check_limited(data, L2 - 1, 2, 1); 987 988 hbitmap_set(data->hb, L2 + 5, L1); 989 test_hbitmap_next_dirty_area_check(data, 0, INT64_MAX); 990 test_hbitmap_next_dirty_area_check(data, L2 - 2, 8); 991 test_hbitmap_next_dirty_area_check(data, L2 + 1, 5); 992 test_hbitmap_next_dirty_area_check(data, L2 + 1, 3); 993 test_hbitmap_next_dirty_area_check(data, L2 + 4, L1); 994 test_hbitmap_next_dirty_area_check(data, L2 + 5, L1); 995 test_hbitmap_next_dirty_area_check(data, L2 + 7, L1); 996 test_hbitmap_next_dirty_area_check(data, L2 + L1, L1); 997 test_hbitmap_next_dirty_area_check(data, L2, 0); 998 test_hbitmap_next_dirty_area_check(data, L2 + 1, 0); 999 test_hbitmap_next_dirty_area_check_limited(data, L2 + 3, INT64_MAX, 3); 1000 test_hbitmap_next_dirty_area_check_limited(data, L2 + 3, 7, 10); 1001 1002 hbitmap_set(data->hb, L2 * 2, L3 - L2 * 2); 1003 test_hbitmap_next_dirty_area_check(data, 0, INT64_MAX); 1004 test_hbitmap_next_dirty_area_check(data, L2, INT64_MAX); 1005 test_hbitmap_next_dirty_area_check(data, L2 + 1, INT64_MAX); 1006 test_hbitmap_next_dirty_area_check(data, L2 + 5 + L1 - 1, INT64_MAX); 1007 test_hbitmap_next_dirty_area_check(data, L2 + 5 + L1, 5); 1008 test_hbitmap_next_dirty_area_check(data, L2 * 2 - L1, L1 + 1); 1009 test_hbitmap_next_dirty_area_check(data, L2 * 2, L2); 1010 test_hbitmap_next_dirty_area_check_limited(data, L2 * 2 + 1, INT64_MAX, 5); 1011 test_hbitmap_next_dirty_area_check_limited(data, L2 * 2 + 1, 10, 5); 1012 test_hbitmap_next_dirty_area_check_limited(data, L2 * 2 + 1, 2, 5); 1013 1014 hbitmap_set(data->hb, 0, L3); 1015 test_hbitmap_next_dirty_area_check(data, 0, INT64_MAX); 1016} 1017 1018static void test_hbitmap_next_dirty_area_0(TestHBitmapData *data, 1019 const void *unused) 1020{ 1021 test_hbitmap_next_dirty_area_do(data, 0); 1022} 1023 1024static void test_hbitmap_next_dirty_area_1(TestHBitmapData *data, 1025 const void *unused) 1026{ 1027 test_hbitmap_next_dirty_area_do(data, 1); 1028} 1029 1030static void test_hbitmap_next_dirty_area_4(TestHBitmapData *data, 1031 const void *unused) 1032{ 1033 test_hbitmap_next_dirty_area_do(data, 4); 1034} 1035 1036static void test_hbitmap_next_dirty_area_after_truncate(TestHBitmapData *data, 1037 const void *unused) 1038{ 1039 hbitmap_test_init(data, L1, 0); 1040 hbitmap_test_truncate_impl(data, L1 * 2); 1041 hbitmap_set(data->hb, L1 + 1, 1); 1042 test_hbitmap_next_dirty_area_check(data, 0, INT64_MAX); 1043} 1044 1045int main(int argc, char **argv) 1046{ 1047 g_test_init(&argc, &argv, NULL); 1048 hbitmap_test_add("/hbitmap/size/0", test_hbitmap_zero); 1049 hbitmap_test_add("/hbitmap/size/unaligned", test_hbitmap_unaligned); 1050 hbitmap_test_add("/hbitmap/iter/empty", test_hbitmap_iter_empty); 1051 hbitmap_test_add("/hbitmap/iter/partial", test_hbitmap_iter_partial); 1052 hbitmap_test_add("/hbitmap/iter/granularity", test_hbitmap_iter_granularity); 1053 hbitmap_test_add("/hbitmap/get/all", test_hbitmap_get_all); 1054 hbitmap_test_add("/hbitmap/get/some", test_hbitmap_get_some); 1055 hbitmap_test_add("/hbitmap/set/all", test_hbitmap_set_all); 1056 hbitmap_test_add("/hbitmap/set/one", test_hbitmap_set_one); 1057 hbitmap_test_add("/hbitmap/set/two-elem", test_hbitmap_set_two_elem); 1058 hbitmap_test_add("/hbitmap/set/general", test_hbitmap_set); 1059 hbitmap_test_add("/hbitmap/set/twice", test_hbitmap_set_twice); 1060 hbitmap_test_add("/hbitmap/set/overlap", test_hbitmap_set_overlap); 1061 hbitmap_test_add("/hbitmap/reset/empty", test_hbitmap_reset_empty); 1062 hbitmap_test_add("/hbitmap/reset/general", test_hbitmap_reset); 1063 hbitmap_test_add("/hbitmap/reset/all", test_hbitmap_reset_all); 1064 hbitmap_test_add("/hbitmap/granularity", test_hbitmap_granularity); 1065 1066 hbitmap_test_add("/hbitmap/truncate/nop", test_hbitmap_truncate_nop); 1067 hbitmap_test_add("/hbitmap/truncate/grow/negligible", 1068 test_hbitmap_truncate_grow_negligible); 1069 hbitmap_test_add("/hbitmap/truncate/shrink/negligible", 1070 test_hbitmap_truncate_shrink_negligible); 1071 hbitmap_test_add("/hbitmap/truncate/grow/tiny", 1072 test_hbitmap_truncate_grow_tiny); 1073 hbitmap_test_add("/hbitmap/truncate/shrink/tiny", 1074 test_hbitmap_truncate_shrink_tiny); 1075 hbitmap_test_add("/hbitmap/truncate/grow/small", 1076 test_hbitmap_truncate_grow_small); 1077 hbitmap_test_add("/hbitmap/truncate/shrink/small", 1078 test_hbitmap_truncate_shrink_small); 1079 hbitmap_test_add("/hbitmap/truncate/grow/medium", 1080 test_hbitmap_truncate_grow_medium); 1081 hbitmap_test_add("/hbitmap/truncate/shrink/medium", 1082 test_hbitmap_truncate_shrink_medium); 1083 hbitmap_test_add("/hbitmap/truncate/grow/large", 1084 test_hbitmap_truncate_grow_large); 1085 hbitmap_test_add("/hbitmap/truncate/shrink/large", 1086 test_hbitmap_truncate_shrink_large); 1087 1088 hbitmap_test_add("/hbitmap/serialize/align", 1089 test_hbitmap_serialize_align); 1090 hbitmap_test_add("/hbitmap/serialize/basic", 1091 test_hbitmap_serialize_basic); 1092 hbitmap_test_add("/hbitmap/serialize/part", 1093 test_hbitmap_serialize_part); 1094 hbitmap_test_add("/hbitmap/serialize/zeroes", 1095 test_hbitmap_serialize_zeroes); 1096 1097 hbitmap_test_add("/hbitmap/iter/iter_and_reset", 1098 test_hbitmap_iter_and_reset); 1099 1100 hbitmap_test_add("/hbitmap/next_zero/next_x_0", 1101 test_hbitmap_next_x_0); 1102 hbitmap_test_add("/hbitmap/next_zero/next_x_4", 1103 test_hbitmap_next_x_4); 1104 hbitmap_test_add("/hbitmap/next_zero/next_x_after_truncate", 1105 test_hbitmap_next_x_after_truncate); 1106 1107 hbitmap_test_add("/hbitmap/next_dirty_area/next_dirty_area_0", 1108 test_hbitmap_next_dirty_area_0); 1109 hbitmap_test_add("/hbitmap/next_dirty_area/next_dirty_area_1", 1110 test_hbitmap_next_dirty_area_1); 1111 hbitmap_test_add("/hbitmap/next_dirty_area/next_dirty_area_4", 1112 test_hbitmap_next_dirty_area_4); 1113 hbitmap_test_add("/hbitmap/next_dirty_area/next_dirty_area_after_truncate", 1114 test_hbitmap_next_dirty_area_after_truncate); 1115 1116 g_test_run(); 1117 1118 return 0; 1119}