1*7bdf38e5Schristos #include "test/jemalloc_test.h" 2*7bdf38e5Schristos 3*7bdf38e5Schristos #include "jemalloc/internal/fb.h" 4*7bdf38e5Schristos #include "test/nbits.h" 5*7bdf38e5Schristos 6*7bdf38e5Schristos static void 7*7bdf38e5Schristos do_test_init(size_t nbits) { 8*7bdf38e5Schristos size_t sz = FB_NGROUPS(nbits) * sizeof(fb_group_t); 9*7bdf38e5Schristos fb_group_t *fb = malloc(sz); 10*7bdf38e5Schristos /* Junk fb's contents. */ 11*7bdf38e5Schristos memset(fb, 99, sz); 12*7bdf38e5Schristos fb_init(fb, nbits); 13*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 14*7bdf38e5Schristos expect_false(fb_get(fb, nbits, i), 15*7bdf38e5Schristos "bitmap should start empty"); 16*7bdf38e5Schristos } 17*7bdf38e5Schristos free(fb); 18*7bdf38e5Schristos } 19*7bdf38e5Schristos 20*7bdf38e5Schristos TEST_BEGIN(test_fb_init) { 21*7bdf38e5Schristos #define NB(nbits) \ 22*7bdf38e5Schristos do_test_init(nbits); 23*7bdf38e5Schristos NBITS_TAB 24*7bdf38e5Schristos #undef NB 25*7bdf38e5Schristos } 26*7bdf38e5Schristos TEST_END 27*7bdf38e5Schristos 28*7bdf38e5Schristos static void 29*7bdf38e5Schristos do_test_get_set_unset(size_t nbits) { 30*7bdf38e5Schristos size_t sz = FB_NGROUPS(nbits) * sizeof(fb_group_t); 31*7bdf38e5Schristos fb_group_t *fb = malloc(sz); 32*7bdf38e5Schristos fb_init(fb, nbits); 33*7bdf38e5Schristos /* Set the bits divisible by 3. */ 34*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 35*7bdf38e5Schristos if (i % 3 == 0) { 36*7bdf38e5Schristos fb_set(fb, nbits, i); 37*7bdf38e5Schristos } 38*7bdf38e5Schristos } 39*7bdf38e5Schristos /* Check them. */ 40*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 41*7bdf38e5Schristos expect_b_eq(i % 3 == 0, fb_get(fb, nbits, i), 42*7bdf38e5Schristos "Unexpected bit at position %zu", i); 43*7bdf38e5Schristos } 44*7bdf38e5Schristos /* Unset those divisible by 5. */ 45*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 46*7bdf38e5Schristos if (i % 5 == 0) { 47*7bdf38e5Schristos fb_unset(fb, nbits, i); 48*7bdf38e5Schristos } 49*7bdf38e5Schristos } 50*7bdf38e5Schristos /* Check them. */ 51*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 52*7bdf38e5Schristos expect_b_eq(i % 3 == 0 && i % 5 != 0, fb_get(fb, nbits, i), 53*7bdf38e5Schristos "Unexpected bit at position %zu", i); 54*7bdf38e5Schristos } 55*7bdf38e5Schristos free(fb); 56*7bdf38e5Schristos } 57*7bdf38e5Schristos 58*7bdf38e5Schristos TEST_BEGIN(test_get_set_unset) { 59*7bdf38e5Schristos #define NB(nbits) \ 60*7bdf38e5Schristos do_test_get_set_unset(nbits); 61*7bdf38e5Schristos NBITS_TAB 62*7bdf38e5Schristos #undef NB 63*7bdf38e5Schristos } 64*7bdf38e5Schristos TEST_END 65*7bdf38e5Schristos 66*7bdf38e5Schristos static ssize_t 67*7bdf38e5Schristos find_3_5_compute(ssize_t i, size_t nbits, bool bit, bool forward) { 68*7bdf38e5Schristos for(; i < (ssize_t)nbits && i >= 0; i += (forward ? 1 : -1)) { 69*7bdf38e5Schristos bool expected_bit = i % 3 == 0 || i % 5 == 0; 70*7bdf38e5Schristos if (expected_bit == bit) { 71*7bdf38e5Schristos return i; 72*7bdf38e5Schristos } 73*7bdf38e5Schristos } 74*7bdf38e5Schristos return forward ? (ssize_t)nbits : (ssize_t)-1; 75*7bdf38e5Schristos } 76*7bdf38e5Schristos 77*7bdf38e5Schristos static void 78*7bdf38e5Schristos do_test_search_simple(size_t nbits) { 79*7bdf38e5Schristos size_t sz = FB_NGROUPS(nbits) * sizeof(fb_group_t); 80*7bdf38e5Schristos fb_group_t *fb = malloc(sz); 81*7bdf38e5Schristos fb_init(fb, nbits); 82*7bdf38e5Schristos 83*7bdf38e5Schristos /* We pick multiples of 3 or 5. */ 84*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 85*7bdf38e5Schristos if (i % 3 == 0) { 86*7bdf38e5Schristos fb_set(fb, nbits, i); 87*7bdf38e5Schristos } 88*7bdf38e5Schristos /* This tests double-setting a little, too. */ 89*7bdf38e5Schristos if (i % 5 == 0) { 90*7bdf38e5Schristos fb_set(fb, nbits, i); 91*7bdf38e5Schristos } 92*7bdf38e5Schristos } 93*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 94*7bdf38e5Schristos size_t ffs_compute = find_3_5_compute(i, nbits, true, true); 95*7bdf38e5Schristos size_t ffs_search = fb_ffs(fb, nbits, i); 96*7bdf38e5Schristos expect_zu_eq(ffs_compute, ffs_search, "ffs mismatch at %zu", i); 97*7bdf38e5Schristos 98*7bdf38e5Schristos ssize_t fls_compute = find_3_5_compute(i, nbits, true, false); 99*7bdf38e5Schristos size_t fls_search = fb_fls(fb, nbits, i); 100*7bdf38e5Schristos expect_zu_eq(fls_compute, fls_search, "fls mismatch at %zu", i); 101*7bdf38e5Schristos 102*7bdf38e5Schristos size_t ffu_compute = find_3_5_compute(i, nbits, false, true); 103*7bdf38e5Schristos size_t ffu_search = fb_ffu(fb, nbits, i); 104*7bdf38e5Schristos expect_zu_eq(ffu_compute, ffu_search, "ffu mismatch at %zu", i); 105*7bdf38e5Schristos 106*7bdf38e5Schristos size_t flu_compute = find_3_5_compute(i, nbits, false, false); 107*7bdf38e5Schristos size_t flu_search = fb_flu(fb, nbits, i); 108*7bdf38e5Schristos expect_zu_eq(flu_compute, flu_search, "flu mismatch at %zu", i); 109*7bdf38e5Schristos } 110*7bdf38e5Schristos 111*7bdf38e5Schristos free(fb); 112*7bdf38e5Schristos } 113*7bdf38e5Schristos 114*7bdf38e5Schristos TEST_BEGIN(test_search_simple) { 115*7bdf38e5Schristos #define NB(nbits) \ 116*7bdf38e5Schristos do_test_search_simple(nbits); 117*7bdf38e5Schristos NBITS_TAB 118*7bdf38e5Schristos #undef NB 119*7bdf38e5Schristos } 120*7bdf38e5Schristos TEST_END 121*7bdf38e5Schristos 122*7bdf38e5Schristos static void 123*7bdf38e5Schristos expect_exhaustive_results(fb_group_t *mostly_full, fb_group_t *mostly_empty, 124*7bdf38e5Schristos size_t nbits, size_t special_bit, size_t position) { 125*7bdf38e5Schristos if (position < special_bit) { 126*7bdf38e5Schristos expect_zu_eq(special_bit, fb_ffs(mostly_empty, nbits, position), 127*7bdf38e5Schristos "mismatch at %zu, %zu", position, special_bit); 128*7bdf38e5Schristos expect_zd_eq(-1, fb_fls(mostly_empty, nbits, position), 129*7bdf38e5Schristos "mismatch at %zu, %zu", position, special_bit); 130*7bdf38e5Schristos expect_zu_eq(position, fb_ffu(mostly_empty, nbits, position), 131*7bdf38e5Schristos "mismatch at %zu, %zu", position, special_bit); 132*7bdf38e5Schristos expect_zd_eq(position, fb_flu(mostly_empty, nbits, position), 133*7bdf38e5Schristos "mismatch at %zu, %zu", position, special_bit); 134*7bdf38e5Schristos 135*7bdf38e5Schristos expect_zu_eq(position, fb_ffs(mostly_full, nbits, position), 136*7bdf38e5Schristos "mismatch at %zu, %zu", position, special_bit); 137*7bdf38e5Schristos expect_zd_eq(position, fb_fls(mostly_full, nbits, position), 138*7bdf38e5Schristos "mismatch at %zu, %zu", position, special_bit); 139*7bdf38e5Schristos expect_zu_eq(special_bit, fb_ffu(mostly_full, nbits, position), 140*7bdf38e5Schristos "mismatch at %zu, %zu", position, special_bit); 141*7bdf38e5Schristos expect_zd_eq(-1, fb_flu(mostly_full, nbits, position), 142*7bdf38e5Schristos "mismatch at %zu, %zu", position, special_bit); 143*7bdf38e5Schristos } else if (position == special_bit) { 144*7bdf38e5Schristos expect_zu_eq(special_bit, fb_ffs(mostly_empty, nbits, position), 145*7bdf38e5Schristos "mismatch at %zu, %zu", position, special_bit); 146*7bdf38e5Schristos expect_zd_eq(special_bit, fb_fls(mostly_empty, nbits, position), 147*7bdf38e5Schristos "mismatch at %zu, %zu", position, special_bit); 148*7bdf38e5Schristos expect_zu_eq(position + 1, fb_ffu(mostly_empty, nbits, position), 149*7bdf38e5Schristos "mismatch at %zu, %zu", position, special_bit); 150*7bdf38e5Schristos expect_zd_eq(position - 1, fb_flu(mostly_empty, nbits, 151*7bdf38e5Schristos position), "mismatch at %zu, %zu", position, special_bit); 152*7bdf38e5Schristos 153*7bdf38e5Schristos expect_zu_eq(position + 1, fb_ffs(mostly_full, nbits, position), 154*7bdf38e5Schristos "mismatch at %zu, %zu", position, special_bit); 155*7bdf38e5Schristos expect_zd_eq(position - 1, fb_fls(mostly_full, nbits, 156*7bdf38e5Schristos position), "mismatch at %zu, %zu", position, special_bit); 157*7bdf38e5Schristos expect_zu_eq(position, fb_ffu(mostly_full, nbits, position), 158*7bdf38e5Schristos "mismatch at %zu, %zu", position, special_bit); 159*7bdf38e5Schristos expect_zd_eq(position, fb_flu(mostly_full, nbits, position), 160*7bdf38e5Schristos "mismatch at %zu, %zu", position, special_bit); 161*7bdf38e5Schristos } else { 162*7bdf38e5Schristos /* position > special_bit. */ 163*7bdf38e5Schristos expect_zu_eq(nbits, fb_ffs(mostly_empty, nbits, position), 164*7bdf38e5Schristos "mismatch at %zu, %zu", position, special_bit); 165*7bdf38e5Schristos expect_zd_eq(special_bit, fb_fls(mostly_empty, nbits, 166*7bdf38e5Schristos position), "mismatch at %zu, %zu", position, special_bit); 167*7bdf38e5Schristos expect_zu_eq(position, fb_ffu(mostly_empty, nbits, position), 168*7bdf38e5Schristos "mismatch at %zu, %zu", position, special_bit); 169*7bdf38e5Schristos expect_zd_eq(position, fb_flu(mostly_empty, nbits, position), 170*7bdf38e5Schristos "mismatch at %zu, %zu", position, special_bit); 171*7bdf38e5Schristos 172*7bdf38e5Schristos expect_zu_eq(position, fb_ffs(mostly_full, nbits, position), 173*7bdf38e5Schristos "mismatch at %zu, %zu", position, special_bit); 174*7bdf38e5Schristos expect_zd_eq(position, fb_fls(mostly_full, nbits, position), 175*7bdf38e5Schristos "mismatch at %zu, %zu", position, special_bit); 176*7bdf38e5Schristos expect_zu_eq(nbits, fb_ffu(mostly_full, nbits, position), 177*7bdf38e5Schristos "mismatch at %zu, %zu", position, special_bit); 178*7bdf38e5Schristos expect_zd_eq(special_bit, fb_flu(mostly_full, nbits, position), 179*7bdf38e5Schristos "mismatch at %zu, %zu", position, special_bit); 180*7bdf38e5Schristos } 181*7bdf38e5Schristos } 182*7bdf38e5Schristos 183*7bdf38e5Schristos static void 184*7bdf38e5Schristos do_test_search_exhaustive(size_t nbits) { 185*7bdf38e5Schristos /* This test is quadratic; let's not get too big. */ 186*7bdf38e5Schristos if (nbits > 1000) { 187*7bdf38e5Schristos return; 188*7bdf38e5Schristos } 189*7bdf38e5Schristos size_t sz = FB_NGROUPS(nbits) * sizeof(fb_group_t); 190*7bdf38e5Schristos fb_group_t *empty = malloc(sz); 191*7bdf38e5Schristos fb_init(empty, nbits); 192*7bdf38e5Schristos fb_group_t *full = malloc(sz); 193*7bdf38e5Schristos fb_init(full, nbits); 194*7bdf38e5Schristos fb_set_range(full, nbits, 0, nbits); 195*7bdf38e5Schristos 196*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 197*7bdf38e5Schristos fb_set(empty, nbits, i); 198*7bdf38e5Schristos fb_unset(full, nbits, i); 199*7bdf38e5Schristos 200*7bdf38e5Schristos for (size_t j = 0; j < nbits; j++) { 201*7bdf38e5Schristos expect_exhaustive_results(full, empty, nbits, i, j); 202*7bdf38e5Schristos } 203*7bdf38e5Schristos fb_unset(empty, nbits, i); 204*7bdf38e5Schristos fb_set(full, nbits, i); 205*7bdf38e5Schristos } 206*7bdf38e5Schristos 207*7bdf38e5Schristos free(empty); 208*7bdf38e5Schristos free(full); 209*7bdf38e5Schristos } 210*7bdf38e5Schristos 211*7bdf38e5Schristos TEST_BEGIN(test_search_exhaustive) { 212*7bdf38e5Schristos #define NB(nbits) \ 213*7bdf38e5Schristos do_test_search_exhaustive(nbits); 214*7bdf38e5Schristos NBITS_TAB 215*7bdf38e5Schristos #undef NB 216*7bdf38e5Schristos } 217*7bdf38e5Schristos TEST_END 218*7bdf38e5Schristos 219*7bdf38e5Schristos TEST_BEGIN(test_range_simple) { 220*7bdf38e5Schristos /* 221*7bdf38e5Schristos * Just pick a constant big enough to have nontrivial middle sizes, and 222*7bdf38e5Schristos * big enough that usages of things like weirdnum (below) near the 223*7bdf38e5Schristos * beginning fit comfortably into the beginning of the bitmap. 224*7bdf38e5Schristos */ 225*7bdf38e5Schristos size_t nbits = 64 * 10; 226*7bdf38e5Schristos size_t ngroups = FB_NGROUPS(nbits); 227*7bdf38e5Schristos fb_group_t *fb = malloc(sizeof(fb_group_t) * ngroups); 228*7bdf38e5Schristos fb_init(fb, nbits); 229*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 230*7bdf38e5Schristos if (i % 2 == 0) { 231*7bdf38e5Schristos fb_set_range(fb, nbits, i, 1); 232*7bdf38e5Schristos } 233*7bdf38e5Schristos } 234*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 235*7bdf38e5Schristos expect_b_eq(i % 2 == 0, fb_get(fb, nbits, i), 236*7bdf38e5Schristos "mismatch at position %zu", i); 237*7bdf38e5Schristos } 238*7bdf38e5Schristos fb_set_range(fb, nbits, 0, nbits / 2); 239*7bdf38e5Schristos fb_unset_range(fb, nbits, nbits / 2, nbits / 2); 240*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 241*7bdf38e5Schristos expect_b_eq(i < nbits / 2, fb_get(fb, nbits, i), 242*7bdf38e5Schristos "mismatch at position %zu", i); 243*7bdf38e5Schristos } 244*7bdf38e5Schristos 245*7bdf38e5Schristos static const size_t weirdnum = 7; 246*7bdf38e5Schristos fb_set_range(fb, nbits, 0, nbits); 247*7bdf38e5Schristos fb_unset_range(fb, nbits, weirdnum, FB_GROUP_BITS + weirdnum); 248*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 249*7bdf38e5Schristos expect_b_eq(7 <= i && i <= 2 * weirdnum + FB_GROUP_BITS - 1, 250*7bdf38e5Schristos !fb_get(fb, nbits, i), "mismatch at position %zu", i); 251*7bdf38e5Schristos } 252*7bdf38e5Schristos free(fb); 253*7bdf38e5Schristos } 254*7bdf38e5Schristos TEST_END 255*7bdf38e5Schristos 256*7bdf38e5Schristos static void 257*7bdf38e5Schristos do_test_empty_full_exhaustive(size_t nbits) { 258*7bdf38e5Schristos size_t sz = FB_NGROUPS(nbits) * sizeof(fb_group_t); 259*7bdf38e5Schristos fb_group_t *empty = malloc(sz); 260*7bdf38e5Schristos fb_init(empty, nbits); 261*7bdf38e5Schristos fb_group_t *full = malloc(sz); 262*7bdf38e5Schristos fb_init(full, nbits); 263*7bdf38e5Schristos fb_set_range(full, nbits, 0, nbits); 264*7bdf38e5Schristos 265*7bdf38e5Schristos expect_true(fb_full(full, nbits), ""); 266*7bdf38e5Schristos expect_false(fb_empty(full, nbits), ""); 267*7bdf38e5Schristos expect_false(fb_full(empty, nbits), ""); 268*7bdf38e5Schristos expect_true(fb_empty(empty, nbits), ""); 269*7bdf38e5Schristos 270*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 271*7bdf38e5Schristos fb_set(empty, nbits, i); 272*7bdf38e5Schristos fb_unset(full, nbits, i); 273*7bdf38e5Schristos 274*7bdf38e5Schristos expect_false(fb_empty(empty, nbits), "error at bit %zu", i); 275*7bdf38e5Schristos if (nbits != 1) { 276*7bdf38e5Schristos expect_false(fb_full(empty, nbits), 277*7bdf38e5Schristos "error at bit %zu", i); 278*7bdf38e5Schristos expect_false(fb_empty(full, nbits), 279*7bdf38e5Schristos "error at bit %zu", i); 280*7bdf38e5Schristos } else { 281*7bdf38e5Schristos expect_true(fb_full(empty, nbits), 282*7bdf38e5Schristos "error at bit %zu", i); 283*7bdf38e5Schristos expect_true(fb_empty(full, nbits), 284*7bdf38e5Schristos "error at bit %zu", i); 285*7bdf38e5Schristos } 286*7bdf38e5Schristos expect_false(fb_full(full, nbits), "error at bit %zu", i); 287*7bdf38e5Schristos 288*7bdf38e5Schristos fb_unset(empty, nbits, i); 289*7bdf38e5Schristos fb_set(full, nbits, i); 290*7bdf38e5Schristos } 291*7bdf38e5Schristos 292*7bdf38e5Schristos free(empty); 293*7bdf38e5Schristos free(full); 294*7bdf38e5Schristos } 295*7bdf38e5Schristos 296*7bdf38e5Schristos TEST_BEGIN(test_empty_full) { 297*7bdf38e5Schristos #define NB(nbits) \ 298*7bdf38e5Schristos do_test_empty_full_exhaustive(nbits); 299*7bdf38e5Schristos NBITS_TAB 300*7bdf38e5Schristos #undef NB 301*7bdf38e5Schristos } 302*7bdf38e5Schristos TEST_END 303*7bdf38e5Schristos 304*7bdf38e5Schristos /* 305*7bdf38e5Schristos * This tests both iter_range and the longest range functionality, which is 306*7bdf38e5Schristos * built closely on top of it. 307*7bdf38e5Schristos */ 308*7bdf38e5Schristos TEST_BEGIN(test_iter_range_simple) { 309*7bdf38e5Schristos size_t set_limit = 30; 310*7bdf38e5Schristos size_t nbits = 100; 311*7bdf38e5Schristos fb_group_t fb[FB_NGROUPS(100)]; 312*7bdf38e5Schristos 313*7bdf38e5Schristos fb_init(fb, nbits); 314*7bdf38e5Schristos 315*7bdf38e5Schristos /* 316*7bdf38e5Schristos * Failing to initialize these can lead to build failures with -Wall; 317*7bdf38e5Schristos * the compiler can't prove that they're set. 318*7bdf38e5Schristos */ 319*7bdf38e5Schristos size_t begin = (size_t)-1; 320*7bdf38e5Schristos size_t len = (size_t)-1; 321*7bdf38e5Schristos bool result; 322*7bdf38e5Schristos 323*7bdf38e5Schristos /* A set of checks with only the first set_limit bits *set*. */ 324*7bdf38e5Schristos fb_set_range(fb, nbits, 0, set_limit); 325*7bdf38e5Schristos expect_zu_eq(set_limit, fb_srange_longest(fb, nbits), 326*7bdf38e5Schristos "Incorrect longest set range"); 327*7bdf38e5Schristos expect_zu_eq(nbits - set_limit, fb_urange_longest(fb, nbits), 328*7bdf38e5Schristos "Incorrect longest unset range"); 329*7bdf38e5Schristos for (size_t i = 0; i < set_limit; i++) { 330*7bdf38e5Schristos result = fb_srange_iter(fb, nbits, i, &begin, &len); 331*7bdf38e5Schristos expect_true(result, "Should have found a range at %zu", i); 332*7bdf38e5Schristos expect_zu_eq(i, begin, "Incorrect begin at %zu", i); 333*7bdf38e5Schristos expect_zu_eq(set_limit - i, len, "Incorrect len at %zu", i); 334*7bdf38e5Schristos 335*7bdf38e5Schristos result = fb_urange_iter(fb, nbits, i, &begin, &len); 336*7bdf38e5Schristos expect_true(result, "Should have found a range at %zu", i); 337*7bdf38e5Schristos expect_zu_eq(set_limit, begin, "Incorrect begin at %zu", i); 338*7bdf38e5Schristos expect_zu_eq(nbits - set_limit, len, "Incorrect len at %zu", i); 339*7bdf38e5Schristos 340*7bdf38e5Schristos result = fb_srange_riter(fb, nbits, i, &begin, &len); 341*7bdf38e5Schristos expect_true(result, "Should have found a range at %zu", i); 342*7bdf38e5Schristos expect_zu_eq(0, begin, "Incorrect begin at %zu", i); 343*7bdf38e5Schristos expect_zu_eq(i + 1, len, "Incorrect len at %zu", i); 344*7bdf38e5Schristos 345*7bdf38e5Schristos result = fb_urange_riter(fb, nbits, i, &begin, &len); 346*7bdf38e5Schristos expect_false(result, "Should not have found a range at %zu", i); 347*7bdf38e5Schristos } 348*7bdf38e5Schristos for (size_t i = set_limit; i < nbits; i++) { 349*7bdf38e5Schristos result = fb_srange_iter(fb, nbits, i, &begin, &len); 350*7bdf38e5Schristos expect_false(result, "Should not have found a range at %zu", i); 351*7bdf38e5Schristos 352*7bdf38e5Schristos result = fb_urange_iter(fb, nbits, i, &begin, &len); 353*7bdf38e5Schristos expect_true(result, "Should have found a range at %zu", i); 354*7bdf38e5Schristos expect_zu_eq(i, begin, "Incorrect begin at %zu", i); 355*7bdf38e5Schristos expect_zu_eq(nbits - i, len, "Incorrect len at %zu", i); 356*7bdf38e5Schristos 357*7bdf38e5Schristos result = fb_srange_riter(fb, nbits, i, &begin, &len); 358*7bdf38e5Schristos expect_true(result, "Should have found a range at %zu", i); 359*7bdf38e5Schristos expect_zu_eq(0, begin, "Incorrect begin at %zu", i); 360*7bdf38e5Schristos expect_zu_eq(set_limit, len, "Incorrect len at %zu", i); 361*7bdf38e5Schristos 362*7bdf38e5Schristos result = fb_urange_riter(fb, nbits, i, &begin, &len); 363*7bdf38e5Schristos expect_true(result, "Should have found a range at %zu", i); 364*7bdf38e5Schristos expect_zu_eq(set_limit, begin, "Incorrect begin at %zu", i); 365*7bdf38e5Schristos expect_zu_eq(i - set_limit + 1, len, "Incorrect len at %zu", i); 366*7bdf38e5Schristos } 367*7bdf38e5Schristos 368*7bdf38e5Schristos /* A set of checks with only the first set_limit bits *unset*. */ 369*7bdf38e5Schristos fb_unset_range(fb, nbits, 0, set_limit); 370*7bdf38e5Schristos fb_set_range(fb, nbits, set_limit, nbits - set_limit); 371*7bdf38e5Schristos expect_zu_eq(nbits - set_limit, fb_srange_longest(fb, nbits), 372*7bdf38e5Schristos "Incorrect longest set range"); 373*7bdf38e5Schristos expect_zu_eq(set_limit, fb_urange_longest(fb, nbits), 374*7bdf38e5Schristos "Incorrect longest unset range"); 375*7bdf38e5Schristos for (size_t i = 0; i < set_limit; i++) { 376*7bdf38e5Schristos result = fb_srange_iter(fb, nbits, i, &begin, &len); 377*7bdf38e5Schristos expect_true(result, "Should have found a range at %zu", i); 378*7bdf38e5Schristos expect_zu_eq(set_limit, begin, "Incorrect begin at %zu", i); 379*7bdf38e5Schristos expect_zu_eq(nbits - set_limit, len, "Incorrect len at %zu", i); 380*7bdf38e5Schristos 381*7bdf38e5Schristos result = fb_urange_iter(fb, nbits, i, &begin, &len); 382*7bdf38e5Schristos expect_true(result, "Should have found a range at %zu", i); 383*7bdf38e5Schristos expect_zu_eq(i, begin, "Incorrect begin at %zu", i); 384*7bdf38e5Schristos expect_zu_eq(set_limit - i, len, "Incorrect len at %zu", i); 385*7bdf38e5Schristos 386*7bdf38e5Schristos result = fb_srange_riter(fb, nbits, i, &begin, &len); 387*7bdf38e5Schristos expect_false(result, "Should not have found a range at %zu", i); 388*7bdf38e5Schristos 389*7bdf38e5Schristos result = fb_urange_riter(fb, nbits, i, &begin, &len); 390*7bdf38e5Schristos expect_true(result, "Should not have found a range at %zu", i); 391*7bdf38e5Schristos expect_zu_eq(0, begin, "Incorrect begin at %zu", i); 392*7bdf38e5Schristos expect_zu_eq(i + 1, len, "Incorrect len at %zu", i); 393*7bdf38e5Schristos } 394*7bdf38e5Schristos for (size_t i = set_limit; i < nbits; i++) { 395*7bdf38e5Schristos result = fb_srange_iter(fb, nbits, i, &begin, &len); 396*7bdf38e5Schristos expect_true(result, "Should have found a range at %zu", i); 397*7bdf38e5Schristos expect_zu_eq(i, begin, "Incorrect begin at %zu", i); 398*7bdf38e5Schristos expect_zu_eq(nbits - i, len, "Incorrect len at %zu", i); 399*7bdf38e5Schristos 400*7bdf38e5Schristos result = fb_urange_iter(fb, nbits, i, &begin, &len); 401*7bdf38e5Schristos expect_false(result, "Should not have found a range at %zu", i); 402*7bdf38e5Schristos 403*7bdf38e5Schristos result = fb_srange_riter(fb, nbits, i, &begin, &len); 404*7bdf38e5Schristos expect_true(result, "Should have found a range at %zu", i); 405*7bdf38e5Schristos expect_zu_eq(set_limit, begin, "Incorrect begin at %zu", i); 406*7bdf38e5Schristos expect_zu_eq(i - set_limit + 1, len, "Incorrect len at %zu", i); 407*7bdf38e5Schristos 408*7bdf38e5Schristos result = fb_urange_riter(fb, nbits, i, &begin, &len); 409*7bdf38e5Schristos expect_true(result, "Should have found a range at %zu", i); 410*7bdf38e5Schristos expect_zu_eq(0, begin, "Incorrect begin at %zu", i); 411*7bdf38e5Schristos expect_zu_eq(set_limit, len, "Incorrect len at %zu", i); 412*7bdf38e5Schristos } 413*7bdf38e5Schristos 414*7bdf38e5Schristos } 415*7bdf38e5Schristos TEST_END 416*7bdf38e5Schristos 417*7bdf38e5Schristos /* 418*7bdf38e5Schristos * Doing this bit-by-bit is too slow for a real implementation, but for testing 419*7bdf38e5Schristos * code, it's easy to get right. In the exhaustive tests, we'll compare the 420*7bdf38e5Schristos * (fast but tricky) real implementation against the (slow but simple) testing 421*7bdf38e5Schristos * one. 422*7bdf38e5Schristos */ 423*7bdf38e5Schristos static bool 424*7bdf38e5Schristos fb_iter_simple(fb_group_t *fb, size_t nbits, size_t start, size_t *r_begin, 425*7bdf38e5Schristos size_t *r_len, bool val, bool forward) { 426*7bdf38e5Schristos ssize_t stride = (forward ? (ssize_t)1 : (ssize_t)-1); 427*7bdf38e5Schristos ssize_t range_begin = (ssize_t)start; 428*7bdf38e5Schristos for (; range_begin != (ssize_t)nbits && range_begin != -1; 429*7bdf38e5Schristos range_begin += stride) { 430*7bdf38e5Schristos if (fb_get(fb, nbits, range_begin) == val) { 431*7bdf38e5Schristos ssize_t range_end = range_begin; 432*7bdf38e5Schristos for (; range_end != (ssize_t)nbits && range_end != -1; 433*7bdf38e5Schristos range_end += stride) { 434*7bdf38e5Schristos if (fb_get(fb, nbits, range_end) != val) { 435*7bdf38e5Schristos break; 436*7bdf38e5Schristos } 437*7bdf38e5Schristos } 438*7bdf38e5Schristos if (forward) { 439*7bdf38e5Schristos *r_begin = range_begin; 440*7bdf38e5Schristos *r_len = range_end - range_begin; 441*7bdf38e5Schristos } else { 442*7bdf38e5Schristos *r_begin = range_end + 1; 443*7bdf38e5Schristos *r_len = range_begin - range_end; 444*7bdf38e5Schristos } 445*7bdf38e5Schristos return true; 446*7bdf38e5Schristos } 447*7bdf38e5Schristos } 448*7bdf38e5Schristos return false; 449*7bdf38e5Schristos } 450*7bdf38e5Schristos 451*7bdf38e5Schristos /* Similar, but for finding longest ranges. */ 452*7bdf38e5Schristos static size_t 453*7bdf38e5Schristos fb_range_longest_simple(fb_group_t *fb, size_t nbits, bool val) { 454*7bdf38e5Schristos size_t longest_so_far = 0; 455*7bdf38e5Schristos for (size_t begin = 0; begin < nbits; begin++) { 456*7bdf38e5Schristos if (fb_get(fb, nbits, begin) != val) { 457*7bdf38e5Schristos continue; 458*7bdf38e5Schristos } 459*7bdf38e5Schristos size_t end = begin + 1; 460*7bdf38e5Schristos for (; end < nbits; end++) { 461*7bdf38e5Schristos if (fb_get(fb, nbits, end) != val) { 462*7bdf38e5Schristos break; 463*7bdf38e5Schristos } 464*7bdf38e5Schristos } 465*7bdf38e5Schristos if (end - begin > longest_so_far) { 466*7bdf38e5Schristos longest_so_far = end - begin; 467*7bdf38e5Schristos } 468*7bdf38e5Schristos } 469*7bdf38e5Schristos return longest_so_far; 470*7bdf38e5Schristos } 471*7bdf38e5Schristos 472*7bdf38e5Schristos static void 473*7bdf38e5Schristos expect_iter_results_at(fb_group_t *fb, size_t nbits, size_t pos, 474*7bdf38e5Schristos bool val, bool forward) { 475*7bdf38e5Schristos bool iter_res; 476*7bdf38e5Schristos size_t iter_begin JEMALLOC_CC_SILENCE_INIT(0); 477*7bdf38e5Schristos size_t iter_len JEMALLOC_CC_SILENCE_INIT(0); 478*7bdf38e5Schristos if (val) { 479*7bdf38e5Schristos if (forward) { 480*7bdf38e5Schristos iter_res = fb_srange_iter(fb, nbits, pos, 481*7bdf38e5Schristos &iter_begin, &iter_len); 482*7bdf38e5Schristos } else { 483*7bdf38e5Schristos iter_res = fb_srange_riter(fb, nbits, pos, 484*7bdf38e5Schristos &iter_begin, &iter_len); 485*7bdf38e5Schristos } 486*7bdf38e5Schristos } else { 487*7bdf38e5Schristos if (forward) { 488*7bdf38e5Schristos iter_res = fb_urange_iter(fb, nbits, pos, 489*7bdf38e5Schristos &iter_begin, &iter_len); 490*7bdf38e5Schristos } else { 491*7bdf38e5Schristos iter_res = fb_urange_riter(fb, nbits, pos, 492*7bdf38e5Schristos &iter_begin, &iter_len); 493*7bdf38e5Schristos } 494*7bdf38e5Schristos } 495*7bdf38e5Schristos 496*7bdf38e5Schristos bool simple_iter_res; 497*7bdf38e5Schristos /* 498*7bdf38e5Schristos * These are dead stores, but the compiler can't always figure that out 499*7bdf38e5Schristos * statically, and warns on the uninitialized variable. 500*7bdf38e5Schristos */ 501*7bdf38e5Schristos size_t simple_iter_begin = 0; 502*7bdf38e5Schristos size_t simple_iter_len = 0; 503*7bdf38e5Schristos simple_iter_res = fb_iter_simple(fb, nbits, pos, &simple_iter_begin, 504*7bdf38e5Schristos &simple_iter_len, val, forward); 505*7bdf38e5Schristos 506*7bdf38e5Schristos expect_b_eq(iter_res, simple_iter_res, "Result mismatch at %zu", pos); 507*7bdf38e5Schristos if (iter_res && simple_iter_res) { 508*7bdf38e5Schristos assert_zu_eq(iter_begin, simple_iter_begin, 509*7bdf38e5Schristos "Begin mismatch at %zu", pos); 510*7bdf38e5Schristos expect_zu_eq(iter_len, simple_iter_len, 511*7bdf38e5Schristos "Length mismatch at %zu", pos); 512*7bdf38e5Schristos } 513*7bdf38e5Schristos } 514*7bdf38e5Schristos 515*7bdf38e5Schristos static void 516*7bdf38e5Schristos expect_iter_results(fb_group_t *fb, size_t nbits) { 517*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 518*7bdf38e5Schristos expect_iter_results_at(fb, nbits, i, false, false); 519*7bdf38e5Schristos expect_iter_results_at(fb, nbits, i, false, true); 520*7bdf38e5Schristos expect_iter_results_at(fb, nbits, i, true, false); 521*7bdf38e5Schristos expect_iter_results_at(fb, nbits, i, true, true); 522*7bdf38e5Schristos } 523*7bdf38e5Schristos expect_zu_eq(fb_range_longest_simple(fb, nbits, true), 524*7bdf38e5Schristos fb_srange_longest(fb, nbits), "Longest range mismatch"); 525*7bdf38e5Schristos expect_zu_eq(fb_range_longest_simple(fb, nbits, false), 526*7bdf38e5Schristos fb_urange_longest(fb, nbits), "Longest range mismatch"); 527*7bdf38e5Schristos } 528*7bdf38e5Schristos 529*7bdf38e5Schristos static void 530*7bdf38e5Schristos set_pattern_3(fb_group_t *fb, size_t nbits, bool zero_val) { 531*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 532*7bdf38e5Schristos if ((i % 6 < 3 && zero_val) || (i % 6 >= 3 && !zero_val)) { 533*7bdf38e5Schristos fb_set(fb, nbits, i); 534*7bdf38e5Schristos } else { 535*7bdf38e5Schristos fb_unset(fb, nbits, i); 536*7bdf38e5Schristos } 537*7bdf38e5Schristos } 538*7bdf38e5Schristos } 539*7bdf38e5Schristos 540*7bdf38e5Schristos static void 541*7bdf38e5Schristos do_test_iter_range_exhaustive(size_t nbits) { 542*7bdf38e5Schristos /* This test is also pretty slow. */ 543*7bdf38e5Schristos if (nbits > 1000) { 544*7bdf38e5Schristos return; 545*7bdf38e5Schristos } 546*7bdf38e5Schristos size_t sz = FB_NGROUPS(nbits) * sizeof(fb_group_t); 547*7bdf38e5Schristos fb_group_t *fb = malloc(sz); 548*7bdf38e5Schristos fb_init(fb, nbits); 549*7bdf38e5Schristos 550*7bdf38e5Schristos set_pattern_3(fb, nbits, /* zero_val */ true); 551*7bdf38e5Schristos expect_iter_results(fb, nbits); 552*7bdf38e5Schristos 553*7bdf38e5Schristos set_pattern_3(fb, nbits, /* zero_val */ false); 554*7bdf38e5Schristos expect_iter_results(fb, nbits); 555*7bdf38e5Schristos 556*7bdf38e5Schristos fb_set_range(fb, nbits, 0, nbits); 557*7bdf38e5Schristos fb_unset_range(fb, nbits, 0, nbits / 2 == 0 ? 1 : nbits / 2); 558*7bdf38e5Schristos expect_iter_results(fb, nbits); 559*7bdf38e5Schristos 560*7bdf38e5Schristos fb_unset_range(fb, nbits, 0, nbits); 561*7bdf38e5Schristos fb_set_range(fb, nbits, 0, nbits / 2 == 0 ? 1: nbits / 2); 562*7bdf38e5Schristos expect_iter_results(fb, nbits); 563*7bdf38e5Schristos 564*7bdf38e5Schristos free(fb); 565*7bdf38e5Schristos } 566*7bdf38e5Schristos 567*7bdf38e5Schristos /* 568*7bdf38e5Schristos * Like test_iter_range_simple, this tests both iteration and longest-range 569*7bdf38e5Schristos * computation. 570*7bdf38e5Schristos */ 571*7bdf38e5Schristos TEST_BEGIN(test_iter_range_exhaustive) { 572*7bdf38e5Schristos #define NB(nbits) \ 573*7bdf38e5Schristos do_test_iter_range_exhaustive(nbits); 574*7bdf38e5Schristos NBITS_TAB 575*7bdf38e5Schristos #undef NB 576*7bdf38e5Schristos } 577*7bdf38e5Schristos TEST_END 578*7bdf38e5Schristos 579*7bdf38e5Schristos /* 580*7bdf38e5Schristos * If all set bits in the bitmap are contiguous, in [set_start, set_end), 581*7bdf38e5Schristos * returns the number of set bits in [scount_start, scount_end). 582*7bdf38e5Schristos */ 583*7bdf38e5Schristos static size_t 584*7bdf38e5Schristos scount_contiguous(size_t set_start, size_t set_end, size_t scount_start, 585*7bdf38e5Schristos size_t scount_end) { 586*7bdf38e5Schristos /* No overlap. */ 587*7bdf38e5Schristos if (set_end <= scount_start || scount_end <= set_start) { 588*7bdf38e5Schristos return 0; 589*7bdf38e5Schristos } 590*7bdf38e5Schristos /* set range contains scount range */ 591*7bdf38e5Schristos if (set_start <= scount_start && set_end >= scount_end) { 592*7bdf38e5Schristos return scount_end - scount_start; 593*7bdf38e5Schristos } 594*7bdf38e5Schristos /* scount range contains set range. */ 595*7bdf38e5Schristos if (scount_start <= set_start && scount_end >= set_end) { 596*7bdf38e5Schristos return set_end - set_start; 597*7bdf38e5Schristos } 598*7bdf38e5Schristos /* Partial overlap, with set range starting first. */ 599*7bdf38e5Schristos if (set_start < scount_start && set_end < scount_end) { 600*7bdf38e5Schristos return set_end - scount_start; 601*7bdf38e5Schristos } 602*7bdf38e5Schristos /* Partial overlap, with scount range starting first. */ 603*7bdf38e5Schristos if (scount_start < set_start && scount_end < set_end) { 604*7bdf38e5Schristos return scount_end - set_start; 605*7bdf38e5Schristos } 606*7bdf38e5Schristos /* 607*7bdf38e5Schristos * Trigger an assert failure; the above list should have been 608*7bdf38e5Schristos * exhaustive. 609*7bdf38e5Schristos */ 610*7bdf38e5Schristos unreachable(); 611*7bdf38e5Schristos } 612*7bdf38e5Schristos 613*7bdf38e5Schristos static size_t 614*7bdf38e5Schristos ucount_contiguous(size_t set_start, size_t set_end, size_t ucount_start, 615*7bdf38e5Schristos size_t ucount_end) { 616*7bdf38e5Schristos /* No overlap. */ 617*7bdf38e5Schristos if (set_end <= ucount_start || ucount_end <= set_start) { 618*7bdf38e5Schristos return ucount_end - ucount_start; 619*7bdf38e5Schristos } 620*7bdf38e5Schristos /* set range contains ucount range */ 621*7bdf38e5Schristos if (set_start <= ucount_start && set_end >= ucount_end) { 622*7bdf38e5Schristos return 0; 623*7bdf38e5Schristos } 624*7bdf38e5Schristos /* ucount range contains set range. */ 625*7bdf38e5Schristos if (ucount_start <= set_start && ucount_end >= set_end) { 626*7bdf38e5Schristos return (ucount_end - ucount_start) - (set_end - set_start); 627*7bdf38e5Schristos } 628*7bdf38e5Schristos /* Partial overlap, with set range starting first. */ 629*7bdf38e5Schristos if (set_start < ucount_start && set_end < ucount_end) { 630*7bdf38e5Schristos return ucount_end - set_end; 631*7bdf38e5Schristos } 632*7bdf38e5Schristos /* Partial overlap, with ucount range starting first. */ 633*7bdf38e5Schristos if (ucount_start < set_start && ucount_end < set_end) { 634*7bdf38e5Schristos return set_start - ucount_start; 635*7bdf38e5Schristos } 636*7bdf38e5Schristos /* 637*7bdf38e5Schristos * Trigger an assert failure; the above list should have been 638*7bdf38e5Schristos * exhaustive. 639*7bdf38e5Schristos */ 640*7bdf38e5Schristos unreachable(); 641*7bdf38e5Schristos } 642*7bdf38e5Schristos 643*7bdf38e5Schristos static void 644*7bdf38e5Schristos expect_count_match_contiguous(fb_group_t *fb, size_t nbits, size_t set_start, 645*7bdf38e5Schristos size_t set_end) { 646*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 647*7bdf38e5Schristos for (size_t j = i + 1; j <= nbits; j++) { 648*7bdf38e5Schristos size_t cnt = j - i; 649*7bdf38e5Schristos size_t scount_expected = scount_contiguous(set_start, 650*7bdf38e5Schristos set_end, i, j); 651*7bdf38e5Schristos size_t scount_computed = fb_scount(fb, nbits, i, cnt); 652*7bdf38e5Schristos expect_zu_eq(scount_expected, scount_computed, 653*7bdf38e5Schristos "fb_scount error with nbits=%zu, start=%zu, " 654*7bdf38e5Schristos "cnt=%zu, with bits set in [%zu, %zu)", 655*7bdf38e5Schristos nbits, i, cnt, set_start, set_end); 656*7bdf38e5Schristos 657*7bdf38e5Schristos size_t ucount_expected = ucount_contiguous(set_start, 658*7bdf38e5Schristos set_end, i, j); 659*7bdf38e5Schristos size_t ucount_computed = fb_ucount(fb, nbits, i, cnt); 660*7bdf38e5Schristos assert_zu_eq(ucount_expected, ucount_computed, 661*7bdf38e5Schristos "fb_ucount error with nbits=%zu, start=%zu, " 662*7bdf38e5Schristos "cnt=%zu, with bits set in [%zu, %zu)", 663*7bdf38e5Schristos nbits, i, cnt, set_start, set_end); 664*7bdf38e5Schristos 665*7bdf38e5Schristos } 666*7bdf38e5Schristos } 667*7bdf38e5Schristos } 668*7bdf38e5Schristos 669*7bdf38e5Schristos static void 670*7bdf38e5Schristos do_test_count_contiguous(size_t nbits) { 671*7bdf38e5Schristos size_t sz = FB_NGROUPS(nbits) * sizeof(fb_group_t); 672*7bdf38e5Schristos fb_group_t *fb = malloc(sz); 673*7bdf38e5Schristos 674*7bdf38e5Schristos fb_init(fb, nbits); 675*7bdf38e5Schristos 676*7bdf38e5Schristos expect_count_match_contiguous(fb, nbits, 0, 0); 677*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 678*7bdf38e5Schristos fb_set(fb, nbits, i); 679*7bdf38e5Schristos expect_count_match_contiguous(fb, nbits, 0, i + 1); 680*7bdf38e5Schristos } 681*7bdf38e5Schristos 682*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 683*7bdf38e5Schristos fb_unset(fb, nbits, i); 684*7bdf38e5Schristos expect_count_match_contiguous(fb, nbits, i + 1, nbits); 685*7bdf38e5Schristos } 686*7bdf38e5Schristos 687*7bdf38e5Schristos free(fb); 688*7bdf38e5Schristos } 689*7bdf38e5Schristos 690*7bdf38e5Schristos TEST_BEGIN(test_count_contiguous_simple) { 691*7bdf38e5Schristos enum {nbits = 300}; 692*7bdf38e5Schristos fb_group_t fb[FB_NGROUPS(nbits)]; 693*7bdf38e5Schristos fb_init(fb, nbits); 694*7bdf38e5Schristos /* Just an arbitrary number. */ 695*7bdf38e5Schristos size_t start = 23; 696*7bdf38e5Schristos 697*7bdf38e5Schristos fb_set_range(fb, nbits, start, 30 - start); 698*7bdf38e5Schristos expect_count_match_contiguous(fb, nbits, start, 30); 699*7bdf38e5Schristos 700*7bdf38e5Schristos fb_set_range(fb, nbits, start, 40 - start); 701*7bdf38e5Schristos expect_count_match_contiguous(fb, nbits, start, 40); 702*7bdf38e5Schristos 703*7bdf38e5Schristos fb_set_range(fb, nbits, start, 70 - start); 704*7bdf38e5Schristos expect_count_match_contiguous(fb, nbits, start, 70); 705*7bdf38e5Schristos 706*7bdf38e5Schristos fb_set_range(fb, nbits, start, 120 - start); 707*7bdf38e5Schristos expect_count_match_contiguous(fb, nbits, start, 120); 708*7bdf38e5Schristos 709*7bdf38e5Schristos fb_set_range(fb, nbits, start, 150 - start); 710*7bdf38e5Schristos expect_count_match_contiguous(fb, nbits, start, 150); 711*7bdf38e5Schristos 712*7bdf38e5Schristos fb_set_range(fb, nbits, start, 200 - start); 713*7bdf38e5Schristos expect_count_match_contiguous(fb, nbits, start, 200); 714*7bdf38e5Schristos 715*7bdf38e5Schristos fb_set_range(fb, nbits, start, 290 - start); 716*7bdf38e5Schristos expect_count_match_contiguous(fb, nbits, start, 290); 717*7bdf38e5Schristos } 718*7bdf38e5Schristos TEST_END 719*7bdf38e5Schristos 720*7bdf38e5Schristos TEST_BEGIN(test_count_contiguous) { 721*7bdf38e5Schristos #define NB(nbits) \ 722*7bdf38e5Schristos /* This test is *particularly* slow in debug builds. */ \ 723*7bdf38e5Schristos if ((!config_debug && nbits < 300) || nbits < 150) { \ 724*7bdf38e5Schristos do_test_count_contiguous(nbits); \ 725*7bdf38e5Schristos } 726*7bdf38e5Schristos NBITS_TAB 727*7bdf38e5Schristos #undef NB 728*7bdf38e5Schristos } 729*7bdf38e5Schristos TEST_END 730*7bdf38e5Schristos 731*7bdf38e5Schristos static void 732*7bdf38e5Schristos expect_count_match_alternating(fb_group_t *fb_even, fb_group_t *fb_odd, 733*7bdf38e5Schristos size_t nbits) { 734*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 735*7bdf38e5Schristos for (size_t j = i + 1; j <= nbits; j++) { 736*7bdf38e5Schristos size_t cnt = j - i; 737*7bdf38e5Schristos size_t odd_scount = cnt / 2 738*7bdf38e5Schristos + (size_t)(cnt % 2 == 1 && i % 2 == 1); 739*7bdf38e5Schristos size_t odd_scount_computed = fb_scount(fb_odd, nbits, 740*7bdf38e5Schristos i, j - i); 741*7bdf38e5Schristos assert_zu_eq(odd_scount, odd_scount_computed, 742*7bdf38e5Schristos "fb_scount error with nbits=%zu, start=%zu, " 743*7bdf38e5Schristos "cnt=%zu, with alternating bits set.", 744*7bdf38e5Schristos nbits, i, j - i); 745*7bdf38e5Schristos 746*7bdf38e5Schristos size_t odd_ucount = cnt / 2 747*7bdf38e5Schristos + (size_t)(cnt % 2 == 1 && i % 2 == 0); 748*7bdf38e5Schristos size_t odd_ucount_computed = fb_ucount(fb_odd, nbits, 749*7bdf38e5Schristos i, j - i); 750*7bdf38e5Schristos assert_zu_eq(odd_ucount, odd_ucount_computed, 751*7bdf38e5Schristos "fb_ucount error with nbits=%zu, start=%zu, " 752*7bdf38e5Schristos "cnt=%zu, with alternating bits set.", 753*7bdf38e5Schristos nbits, i, j - i); 754*7bdf38e5Schristos 755*7bdf38e5Schristos size_t even_scount = cnt / 2 756*7bdf38e5Schristos + (size_t)(cnt % 2 == 1 && i % 2 == 0); 757*7bdf38e5Schristos size_t even_scount_computed = fb_scount(fb_even, nbits, 758*7bdf38e5Schristos i, j - i); 759*7bdf38e5Schristos assert_zu_eq(even_scount, even_scount_computed, 760*7bdf38e5Schristos "fb_scount error with nbits=%zu, start=%zu, " 761*7bdf38e5Schristos "cnt=%zu, with alternating bits set.", 762*7bdf38e5Schristos nbits, i, j - i); 763*7bdf38e5Schristos 764*7bdf38e5Schristos size_t even_ucount = cnt / 2 765*7bdf38e5Schristos + (size_t)(cnt % 2 == 1 && i % 2 == 1); 766*7bdf38e5Schristos size_t even_ucount_computed = fb_ucount(fb_even, nbits, 767*7bdf38e5Schristos i, j - i); 768*7bdf38e5Schristos assert_zu_eq(even_ucount, even_ucount_computed, 769*7bdf38e5Schristos "fb_ucount error with nbits=%zu, start=%zu, " 770*7bdf38e5Schristos "cnt=%zu, with alternating bits set.", 771*7bdf38e5Schristos nbits, i, j - i); 772*7bdf38e5Schristos } 773*7bdf38e5Schristos } 774*7bdf38e5Schristos } 775*7bdf38e5Schristos 776*7bdf38e5Schristos static void 777*7bdf38e5Schristos do_test_count_alternating(size_t nbits) { 778*7bdf38e5Schristos if (nbits > 1000) { 779*7bdf38e5Schristos return; 780*7bdf38e5Schristos } 781*7bdf38e5Schristos size_t sz = FB_NGROUPS(nbits) * sizeof(fb_group_t); 782*7bdf38e5Schristos fb_group_t *fb_even = malloc(sz); 783*7bdf38e5Schristos fb_group_t *fb_odd = malloc(sz); 784*7bdf38e5Schristos 785*7bdf38e5Schristos fb_init(fb_even, nbits); 786*7bdf38e5Schristos fb_init(fb_odd, nbits); 787*7bdf38e5Schristos 788*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 789*7bdf38e5Schristos if (i % 2 == 0) { 790*7bdf38e5Schristos fb_set(fb_even, nbits, i); 791*7bdf38e5Schristos } else { 792*7bdf38e5Schristos fb_set(fb_odd, nbits, i); 793*7bdf38e5Schristos } 794*7bdf38e5Schristos } 795*7bdf38e5Schristos 796*7bdf38e5Schristos expect_count_match_alternating(fb_even, fb_odd, nbits); 797*7bdf38e5Schristos 798*7bdf38e5Schristos free(fb_even); 799*7bdf38e5Schristos free(fb_odd); 800*7bdf38e5Schristos } 801*7bdf38e5Schristos 802*7bdf38e5Schristos TEST_BEGIN(test_count_alternating) { 803*7bdf38e5Schristos #define NB(nbits) \ 804*7bdf38e5Schristos do_test_count_alternating(nbits); 805*7bdf38e5Schristos NBITS_TAB 806*7bdf38e5Schristos #undef NB 807*7bdf38e5Schristos } 808*7bdf38e5Schristos TEST_END 809*7bdf38e5Schristos 810*7bdf38e5Schristos static void 811*7bdf38e5Schristos do_test_bit_op(size_t nbits, bool (*op)(bool a, bool b), 812*7bdf38e5Schristos void (*fb_op)(fb_group_t *dst, fb_group_t *src1, fb_group_t *src2, size_t nbits)) { 813*7bdf38e5Schristos size_t sz = FB_NGROUPS(nbits) * sizeof(fb_group_t); 814*7bdf38e5Schristos fb_group_t *fb1 = malloc(sz); 815*7bdf38e5Schristos fb_group_t *fb2 = malloc(sz); 816*7bdf38e5Schristos fb_group_t *fb_result = malloc(sz); 817*7bdf38e5Schristos fb_init(fb1, nbits); 818*7bdf38e5Schristos fb_init(fb2, nbits); 819*7bdf38e5Schristos fb_init(fb_result, nbits); 820*7bdf38e5Schristos 821*7bdf38e5Schristos /* Just two random numbers. */ 822*7bdf38e5Schristos const uint64_t prng_init1 = (uint64_t)0X4E9A9DE6A35691CDULL; 823*7bdf38e5Schristos const uint64_t prng_init2 = (uint64_t)0X7856E396B063C36EULL; 824*7bdf38e5Schristos 825*7bdf38e5Schristos uint64_t prng1 = prng_init1; 826*7bdf38e5Schristos uint64_t prng2 = prng_init2; 827*7bdf38e5Schristos 828*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 829*7bdf38e5Schristos bool bit1 = ((prng1 & (1ULL << (i % 64))) != 0); 830*7bdf38e5Schristos bool bit2 = ((prng2 & (1ULL << (i % 64))) != 0); 831*7bdf38e5Schristos 832*7bdf38e5Schristos if (bit1) { 833*7bdf38e5Schristos fb_set(fb1, nbits, i); 834*7bdf38e5Schristos } 835*7bdf38e5Schristos if (bit2) { 836*7bdf38e5Schristos fb_set(fb2, nbits, i); 837*7bdf38e5Schristos } 838*7bdf38e5Schristos 839*7bdf38e5Schristos if (i % 64 == 0) { 840*7bdf38e5Schristos prng1 = prng_state_next_u64(prng1); 841*7bdf38e5Schristos prng2 = prng_state_next_u64(prng2); 842*7bdf38e5Schristos } 843*7bdf38e5Schristos } 844*7bdf38e5Schristos 845*7bdf38e5Schristos fb_op(fb_result, fb1, fb2, nbits); 846*7bdf38e5Schristos 847*7bdf38e5Schristos /* Reset the prngs to replay them. */ 848*7bdf38e5Schristos prng1 = prng_init1; 849*7bdf38e5Schristos prng2 = prng_init2; 850*7bdf38e5Schristos 851*7bdf38e5Schristos for (size_t i = 0; i < nbits; i++) { 852*7bdf38e5Schristos bool bit1 = ((prng1 & (1ULL << (i % 64))) != 0); 853*7bdf38e5Schristos bool bit2 = ((prng2 & (1ULL << (i % 64))) != 0); 854*7bdf38e5Schristos 855*7bdf38e5Schristos /* Original bitmaps shouldn't change. */ 856*7bdf38e5Schristos expect_b_eq(bit1, fb_get(fb1, nbits, i), "difference at bit %zu", i); 857*7bdf38e5Schristos expect_b_eq(bit2, fb_get(fb2, nbits, i), "difference at bit %zu", i); 858*7bdf38e5Schristos 859*7bdf38e5Schristos /* New one should be bitwise and. */ 860*7bdf38e5Schristos expect_b_eq(op(bit1, bit2), fb_get(fb_result, nbits, i), 861*7bdf38e5Schristos "difference at bit %zu", i); 862*7bdf38e5Schristos 863*7bdf38e5Schristos /* Update the same way we did last time. */ 864*7bdf38e5Schristos if (i % 64 == 0) { 865*7bdf38e5Schristos prng1 = prng_state_next_u64(prng1); 866*7bdf38e5Schristos prng2 = prng_state_next_u64(prng2); 867*7bdf38e5Schristos } 868*7bdf38e5Schristos } 869*7bdf38e5Schristos 870*7bdf38e5Schristos free(fb1); 871*7bdf38e5Schristos free(fb2); 872*7bdf38e5Schristos free(fb_result); 873*7bdf38e5Schristos } 874*7bdf38e5Schristos 875*7bdf38e5Schristos static bool 876*7bdf38e5Schristos binary_and(bool a, bool b) { 877*7bdf38e5Schristos return a & b; 878*7bdf38e5Schristos } 879*7bdf38e5Schristos 880*7bdf38e5Schristos static void 881*7bdf38e5Schristos do_test_bit_and(size_t nbits) { 882*7bdf38e5Schristos do_test_bit_op(nbits, &binary_and, &fb_bit_and); 883*7bdf38e5Schristos } 884*7bdf38e5Schristos 885*7bdf38e5Schristos TEST_BEGIN(test_bit_and) { 886*7bdf38e5Schristos #define NB(nbits) \ 887*7bdf38e5Schristos do_test_bit_and(nbits); 888*7bdf38e5Schristos NBITS_TAB 889*7bdf38e5Schristos #undef NB 890*7bdf38e5Schristos } 891*7bdf38e5Schristos TEST_END 892*7bdf38e5Schristos 893*7bdf38e5Schristos static bool 894*7bdf38e5Schristos binary_or(bool a, bool b) { 895*7bdf38e5Schristos return a | b; 896*7bdf38e5Schristos } 897*7bdf38e5Schristos 898*7bdf38e5Schristos static void 899*7bdf38e5Schristos do_test_bit_or(size_t nbits) { 900*7bdf38e5Schristos do_test_bit_op(nbits, &binary_or, &fb_bit_or); 901*7bdf38e5Schristos } 902*7bdf38e5Schristos 903*7bdf38e5Schristos TEST_BEGIN(test_bit_or) { 904*7bdf38e5Schristos #define NB(nbits) \ 905*7bdf38e5Schristos do_test_bit_or(nbits); 906*7bdf38e5Schristos NBITS_TAB 907*7bdf38e5Schristos #undef NB 908*7bdf38e5Schristos } 909*7bdf38e5Schristos TEST_END 910*7bdf38e5Schristos 911*7bdf38e5Schristos static bool 912*7bdf38e5Schristos binary_not(bool a, bool b) { 913*7bdf38e5Schristos (void)b; 914*7bdf38e5Schristos return !a; 915*7bdf38e5Schristos } 916*7bdf38e5Schristos 917*7bdf38e5Schristos static void 918*7bdf38e5Schristos fb_bit_not_shim(fb_group_t *dst, fb_group_t *src1, fb_group_t *src2, 919*7bdf38e5Schristos size_t nbits) { 920*7bdf38e5Schristos (void)src2; 921*7bdf38e5Schristos fb_bit_not(dst, src1, nbits); 922*7bdf38e5Schristos } 923*7bdf38e5Schristos 924*7bdf38e5Schristos static void 925*7bdf38e5Schristos do_test_bit_not(size_t nbits) { 926*7bdf38e5Schristos do_test_bit_op(nbits, &binary_not, &fb_bit_not_shim); 927*7bdf38e5Schristos } 928*7bdf38e5Schristos 929*7bdf38e5Schristos TEST_BEGIN(test_bit_not) { 930*7bdf38e5Schristos #define NB(nbits) \ 931*7bdf38e5Schristos do_test_bit_not(nbits); 932*7bdf38e5Schristos NBITS_TAB 933*7bdf38e5Schristos #undef NB 934*7bdf38e5Schristos } 935*7bdf38e5Schristos TEST_END 936*7bdf38e5Schristos 937*7bdf38e5Schristos int 938*7bdf38e5Schristos main(void) { 939*7bdf38e5Schristos return test_no_reentrancy( 940*7bdf38e5Schristos test_fb_init, 941*7bdf38e5Schristos test_get_set_unset, 942*7bdf38e5Schristos test_search_simple, 943*7bdf38e5Schristos test_search_exhaustive, 944*7bdf38e5Schristos test_range_simple, 945*7bdf38e5Schristos test_empty_full, 946*7bdf38e5Schristos test_iter_range_simple, 947*7bdf38e5Schristos test_iter_range_exhaustive, 948*7bdf38e5Schristos test_count_contiguous_simple, 949*7bdf38e5Schristos test_count_contiguous, 950*7bdf38e5Schristos test_count_alternating, 951*7bdf38e5Schristos test_bit_and, 952*7bdf38e5Schristos test_bit_or, 953*7bdf38e5Schristos test_bit_not); 954*7bdf38e5Schristos } 955