7c00f04ff4
Remove tree-structured bitmap support, in order to reduce complexity and ease maintenance. No bitmaps larger than 512 bits have been necessary since before 4.0.0, and there is no current plan that would increase maximum bitmap size. Although tree-structured bitmaps were used on 32-bit platforms prior to this change, the overall benefits were questionable (higher metadata overhead, higher bitmap modification cost, marginally lower search cost).
416 lines
10 KiB
C
416 lines
10 KiB
C
#include "test/jemalloc_test.h"
|
|
|
|
#define NBITS_TAB \
|
|
NB( 1) \
|
|
NB( 2) \
|
|
NB( 3) \
|
|
NB( 4) \
|
|
NB( 5) \
|
|
NB( 6) \
|
|
NB( 7) \
|
|
NB( 8) \
|
|
NB( 9) \
|
|
NB(10) \
|
|
NB(11) \
|
|
NB(12) \
|
|
NB(13) \
|
|
NB(14) \
|
|
NB(15) \
|
|
NB(16) \
|
|
NB(17) \
|
|
NB(18) \
|
|
NB(19) \
|
|
NB(20) \
|
|
NB(21) \
|
|
NB(22) \
|
|
NB(23) \
|
|
NB(24) \
|
|
NB(25) \
|
|
NB(26) \
|
|
NB(27) \
|
|
NB(28) \
|
|
NB(29) \
|
|
NB(30) \
|
|
NB(31) \
|
|
NB(32) \
|
|
\
|
|
NB(33) \
|
|
NB(34) \
|
|
NB(35) \
|
|
NB(36) \
|
|
NB(37) \
|
|
NB(38) \
|
|
NB(39) \
|
|
NB(40) \
|
|
NB(41) \
|
|
NB(42) \
|
|
NB(43) \
|
|
NB(44) \
|
|
NB(45) \
|
|
NB(46) \
|
|
NB(47) \
|
|
NB(48) \
|
|
NB(49) \
|
|
NB(50) \
|
|
NB(51) \
|
|
NB(52) \
|
|
NB(53) \
|
|
NB(54) \
|
|
NB(55) \
|
|
NB(56) \
|
|
NB(57) \
|
|
NB(58) \
|
|
NB(59) \
|
|
NB(60) \
|
|
NB(61) \
|
|
NB(62) \
|
|
NB(63) \
|
|
NB(64) \
|
|
NB(65) \
|
|
\
|
|
NB(126) \
|
|
NB(127) \
|
|
NB(128) \
|
|
NB(129) \
|
|
NB(130) \
|
|
\
|
|
NB(254) \
|
|
NB(255) \
|
|
NB(256) \
|
|
NB(257) \
|
|
NB(258) \
|
|
\
|
|
NB(510) \
|
|
NB(511) \
|
|
NB(512) \
|
|
NB(513) \
|
|
NB(514) \
|
|
\
|
|
NB(1024) \
|
|
NB(2048) \
|
|
NB(4096) \
|
|
NB(8192) \
|
|
NB(16384) \
|
|
|
|
static void
|
|
test_bitmap_initializer_body(const bitmap_info_t *binfo, size_t nbits) {
|
|
bitmap_info_t binfo_dyn;
|
|
bitmap_info_init(&binfo_dyn, nbits);
|
|
|
|
assert_zu_eq(bitmap_size(binfo), bitmap_size(&binfo_dyn),
|
|
"Unexpected difference between static and dynamic initialization, "
|
|
"nbits=%zu", nbits);
|
|
assert_zu_eq(binfo->nbits, binfo_dyn.nbits,
|
|
"Unexpected difference between static and dynamic initialization, "
|
|
"nbits=%zu", nbits);
|
|
assert_zu_eq(binfo->ngroups, binfo_dyn.ngroups,
|
|
"Unexpected difference between static and dynamic initialization");
|
|
}
|
|
|
|
TEST_BEGIN(test_bitmap_initializer) {
|
|
#define NB(nbits) { \
|
|
if (nbits <= BITMAP_MAXBITS) { \
|
|
bitmap_info_t binfo = \
|
|
BITMAP_INFO_INITIALIZER(nbits); \
|
|
test_bitmap_initializer_body(&binfo, nbits); \
|
|
} \
|
|
}
|
|
NBITS_TAB
|
|
#undef NB
|
|
}
|
|
TEST_END
|
|
|
|
static size_t
|
|
test_bitmap_size_body(const bitmap_info_t *binfo, size_t nbits,
|
|
size_t prev_size) {
|
|
size_t size = bitmap_size(binfo);
|
|
assert_zu_ge(size, (nbits >> 3),
|
|
"Bitmap size is smaller than expected");
|
|
assert_zu_ge(size, prev_size, "Bitmap size is smaller than expected");
|
|
return size;
|
|
}
|
|
|
|
TEST_BEGIN(test_bitmap_size) {
|
|
size_t nbits, prev_size;
|
|
|
|
prev_size = 0;
|
|
for (nbits = 1; nbits <= BITMAP_MAXBITS; nbits++) {
|
|
bitmap_info_t binfo;
|
|
bitmap_info_init(&binfo, nbits);
|
|
prev_size = test_bitmap_size_body(&binfo, nbits, prev_size);
|
|
}
|
|
#define NB(nbits) { \
|
|
bitmap_info_t binfo = BITMAP_INFO_INITIALIZER(nbits); \
|
|
prev_size = test_bitmap_size_body(&binfo, nbits, \
|
|
prev_size); \
|
|
}
|
|
prev_size = 0;
|
|
NBITS_TAB
|
|
#undef NB
|
|
}
|
|
TEST_END
|
|
|
|
static void
|
|
test_bitmap_init_body(const bitmap_info_t *binfo, size_t nbits) {
|
|
size_t i;
|
|
bitmap_t *bitmap = (bitmap_t *)malloc(bitmap_size(binfo));
|
|
assert_ptr_not_null(bitmap, "Unexpected malloc() failure");
|
|
|
|
bitmap_init(bitmap, binfo, false);
|
|
for (i = 0; i < nbits; i++) {
|
|
assert_false(bitmap_get(bitmap, binfo, i),
|
|
"Bit should be unset");
|
|
}
|
|
|
|
bitmap_init(bitmap, binfo, true);
|
|
for (i = 0; i < nbits; i++) {
|
|
assert_true(bitmap_get(bitmap, binfo, i), "Bit should be set");
|
|
}
|
|
|
|
free(bitmap);
|
|
}
|
|
|
|
TEST_BEGIN(test_bitmap_init) {
|
|
size_t nbits;
|
|
|
|
for (nbits = 1; nbits <= BITMAP_MAXBITS; nbits++) {
|
|
bitmap_info_t binfo;
|
|
bitmap_info_init(&binfo, nbits);
|
|
test_bitmap_init_body(&binfo, nbits);
|
|
}
|
|
#define NB(nbits) { \
|
|
bitmap_info_t binfo = BITMAP_INFO_INITIALIZER(nbits); \
|
|
test_bitmap_init_body(&binfo, nbits); \
|
|
}
|
|
NBITS_TAB
|
|
#undef NB
|
|
}
|
|
TEST_END
|
|
|
|
static void
|
|
test_bitmap_set_body(const bitmap_info_t *binfo, size_t nbits) {
|
|
size_t i;
|
|
bitmap_t *bitmap = (bitmap_t *)malloc(bitmap_size(binfo));
|
|
assert_ptr_not_null(bitmap, "Unexpected malloc() failure");
|
|
bitmap_init(bitmap, binfo, false);
|
|
|
|
for (i = 0; i < nbits; i++) {
|
|
bitmap_set(bitmap, binfo, i);
|
|
}
|
|
assert_true(bitmap_full(bitmap, binfo), "All bits should be set");
|
|
free(bitmap);
|
|
}
|
|
|
|
TEST_BEGIN(test_bitmap_set) {
|
|
size_t nbits;
|
|
|
|
for (nbits = 1; nbits <= BITMAP_MAXBITS; nbits++) {
|
|
bitmap_info_t binfo;
|
|
bitmap_info_init(&binfo, nbits);
|
|
test_bitmap_set_body(&binfo, nbits);
|
|
}
|
|
#define NB(nbits) { \
|
|
bitmap_info_t binfo = BITMAP_INFO_INITIALIZER(nbits); \
|
|
test_bitmap_set_body(&binfo, nbits); \
|
|
}
|
|
NBITS_TAB
|
|
#undef NB
|
|
}
|
|
TEST_END
|
|
|
|
static void
|
|
test_bitmap_unset_body(const bitmap_info_t *binfo, size_t nbits) {
|
|
size_t i;
|
|
bitmap_t *bitmap = (bitmap_t *)malloc(bitmap_size(binfo));
|
|
assert_ptr_not_null(bitmap, "Unexpected malloc() failure");
|
|
bitmap_init(bitmap, binfo, false);
|
|
|
|
for (i = 0; i < nbits; i++) {
|
|
bitmap_set(bitmap, binfo, i);
|
|
}
|
|
assert_true(bitmap_full(bitmap, binfo), "All bits should be set");
|
|
for (i = 0; i < nbits; i++) {
|
|
bitmap_unset(bitmap, binfo, i);
|
|
}
|
|
for (i = 0; i < nbits; i++) {
|
|
bitmap_set(bitmap, binfo, i);
|
|
}
|
|
assert_true(bitmap_full(bitmap, binfo), "All bits should be set");
|
|
free(bitmap);
|
|
}
|
|
|
|
TEST_BEGIN(test_bitmap_unset) {
|
|
size_t nbits;
|
|
|
|
for (nbits = 1; nbits <= BITMAP_MAXBITS; nbits++) {
|
|
bitmap_info_t binfo;
|
|
bitmap_info_init(&binfo, nbits);
|
|
test_bitmap_unset_body(&binfo, nbits);
|
|
}
|
|
#define NB(nbits) { \
|
|
bitmap_info_t binfo = BITMAP_INFO_INITIALIZER(nbits); \
|
|
test_bitmap_unset_body(&binfo, nbits); \
|
|
}
|
|
NBITS_TAB
|
|
#undef NB
|
|
}
|
|
TEST_END
|
|
|
|
static void
|
|
test_bitmap_xfu_body(const bitmap_info_t *binfo, size_t nbits) {
|
|
bitmap_t *bitmap = (bitmap_t *)malloc(bitmap_size(binfo));
|
|
assert_ptr_not_null(bitmap, "Unexpected malloc() failure");
|
|
bitmap_init(bitmap, binfo, false);
|
|
|
|
/* Iteratively set bits starting at the beginning. */
|
|
for (size_t i = 0; i < nbits; i++) {
|
|
assert_zu_eq(bitmap_ffu(bitmap, binfo, 0), i,
|
|
"First unset bit should be just after previous first unset "
|
|
"bit");
|
|
assert_zu_eq(bitmap_ffu(bitmap, binfo, (i > 0) ? i-1 : i), i,
|
|
"First unset bit should be just after previous first unset "
|
|
"bit");
|
|
assert_zu_eq(bitmap_ffu(bitmap, binfo, i), i,
|
|
"First unset bit should be just after previous first unset "
|
|
"bit");
|
|
assert_zu_eq(bitmap_sfu(bitmap, binfo), i,
|
|
"First unset bit should be just after previous first unset "
|
|
"bit");
|
|
}
|
|
assert_true(bitmap_full(bitmap, binfo), "All bits should be set");
|
|
|
|
/*
|
|
* Iteratively unset bits starting at the end, and verify that
|
|
* bitmap_sfu() reaches the unset bits.
|
|
*/
|
|
for (size_t i = nbits - 1; i < nbits; i--) { /* (nbits..0] */
|
|
bitmap_unset(bitmap, binfo, i);
|
|
assert_zu_eq(bitmap_ffu(bitmap, binfo, 0), i,
|
|
"First unset bit should the bit previously unset");
|
|
assert_zu_eq(bitmap_ffu(bitmap, binfo, (i > 0) ? i-1 : i), i,
|
|
"First unset bit should the bit previously unset");
|
|
assert_zu_eq(bitmap_ffu(bitmap, binfo, i), i,
|
|
"First unset bit should the bit previously unset");
|
|
assert_zu_eq(bitmap_sfu(bitmap, binfo), i,
|
|
"First unset bit should the bit previously unset");
|
|
bitmap_unset(bitmap, binfo, i);
|
|
}
|
|
assert_false(bitmap_get(bitmap, binfo, 0), "Bit should be unset");
|
|
|
|
/*
|
|
* Iteratively set bits starting at the beginning, and verify that
|
|
* bitmap_sfu() looks past them.
|
|
*/
|
|
for (size_t i = 1; i < nbits; i++) {
|
|
bitmap_set(bitmap, binfo, i - 1);
|
|
assert_zu_eq(bitmap_ffu(bitmap, binfo, 0), i,
|
|
"First unset bit should be just after the bit previously "
|
|
"set");
|
|
assert_zu_eq(bitmap_ffu(bitmap, binfo, (i > 0) ? i-1 : i), i,
|
|
"First unset bit should be just after the bit previously "
|
|
"set");
|
|
assert_zu_eq(bitmap_ffu(bitmap, binfo, i), i,
|
|
"First unset bit should be just after the bit previously "
|
|
"set");
|
|
assert_zu_eq(bitmap_sfu(bitmap, binfo), i,
|
|
"First unset bit should be just after the bit previously "
|
|
"set");
|
|
bitmap_unset(bitmap, binfo, i);
|
|
}
|
|
assert_zu_eq(bitmap_ffu(bitmap, binfo, 0), nbits - 1,
|
|
"First unset bit should be the last bit");
|
|
assert_zu_eq(bitmap_ffu(bitmap, binfo, (nbits > 1) ? nbits-2 : nbits-1),
|
|
nbits - 1, "First unset bit should be the last bit");
|
|
assert_zu_eq(bitmap_ffu(bitmap, binfo, nbits - 1), nbits - 1,
|
|
"First unset bit should be the last bit");
|
|
assert_zu_eq(bitmap_sfu(bitmap, binfo), nbits - 1,
|
|
"First unset bit should be the last bit");
|
|
assert_true(bitmap_full(bitmap, binfo), "All bits should be set");
|
|
|
|
/*
|
|
* Bubble a "usu" pattern through the bitmap and verify that
|
|
* bitmap_ffu() finds the correct bit for all five min_bit cases.
|
|
*/
|
|
if (nbits >= 3) {
|
|
for (size_t i = 0; i < nbits-2; i++) {
|
|
bitmap_unset(bitmap, binfo, i);
|
|
bitmap_unset(bitmap, binfo, i+2);
|
|
if (i > 0) {
|
|
assert_zu_eq(bitmap_ffu(bitmap, binfo, i-1), i,
|
|
"Unexpected first unset bit");
|
|
}
|
|
assert_zu_eq(bitmap_ffu(bitmap, binfo, i), i,
|
|
"Unexpected first unset bit");
|
|
assert_zu_eq(bitmap_ffu(bitmap, binfo, i+1), i+2,
|
|
"Unexpected first unset bit");
|
|
assert_zu_eq(bitmap_ffu(bitmap, binfo, i+2), i+2,
|
|
"Unexpected first unset bit");
|
|
if (i + 3 < nbits) {
|
|
assert_zu_eq(bitmap_ffu(bitmap, binfo, i+3),
|
|
nbits, "Unexpected first unset bit");
|
|
}
|
|
assert_zu_eq(bitmap_sfu(bitmap, binfo), i,
|
|
"Unexpected first unset bit");
|
|
assert_zu_eq(bitmap_sfu(bitmap, binfo), i+2,
|
|
"Unexpected first unset bit");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Unset the last bit, bubble another unset bit through the bitmap, and
|
|
* verify that bitmap_ffu() finds the correct bit for all four min_bit
|
|
* cases.
|
|
*/
|
|
if (nbits >= 3) {
|
|
bitmap_unset(bitmap, binfo, nbits-1);
|
|
for (size_t i = 0; i < nbits-1; i++) {
|
|
bitmap_unset(bitmap, binfo, i);
|
|
if (i > 0) {
|
|
assert_zu_eq(bitmap_ffu(bitmap, binfo, i-1), i,
|
|
"Unexpected first unset bit");
|
|
}
|
|
assert_zu_eq(bitmap_ffu(bitmap, binfo, i), i,
|
|
"Unexpected first unset bit");
|
|
assert_zu_eq(bitmap_ffu(bitmap, binfo, i+1), nbits-1,
|
|
"Unexpected first unset bit");
|
|
assert_zu_eq(bitmap_ffu(bitmap, binfo, nbits-1),
|
|
nbits-1, "Unexpected first unset bit");
|
|
|
|
assert_zu_eq(bitmap_sfu(bitmap, binfo), i,
|
|
"Unexpected first unset bit");
|
|
}
|
|
assert_zu_eq(bitmap_sfu(bitmap, binfo), nbits-1,
|
|
"Unexpected first unset bit");
|
|
}
|
|
|
|
free(bitmap);
|
|
}
|
|
|
|
TEST_BEGIN(test_bitmap_xfu) {
|
|
size_t nbits;
|
|
|
|
for (nbits = 1; nbits <= BITMAP_MAXBITS; nbits++) {
|
|
bitmap_info_t binfo;
|
|
bitmap_info_init(&binfo, nbits);
|
|
test_bitmap_xfu_body(&binfo, nbits);
|
|
}
|
|
#define NB(nbits) { \
|
|
bitmap_info_t binfo = BITMAP_INFO_INITIALIZER(nbits); \
|
|
test_bitmap_xfu_body(&binfo, nbits); \
|
|
}
|
|
NBITS_TAB
|
|
#undef NB
|
|
}
|
|
TEST_END
|
|
|
|
int
|
|
main(void) {
|
|
return test(
|
|
test_bitmap_initializer,
|
|
test_bitmap_size,
|
|
test_bitmap_init,
|
|
test_bitmap_set,
|
|
test_bitmap_unset,
|
|
test_bitmap_xfu);
|
|
}
|