1a0698ed9Schristos #include "test/jemalloc_test.h" 2a0698ed9Schristos 3a0698ed9Schristos #include "jemalloc/internal/rtree.h" 4a0698ed9Schristos 5*7bdf38e5Schristos #define INVALID_ARENA_IND ((1U << MALLOCX_ARENA_BITS) - 1) 6a0698ed9Schristos 7a0698ed9Schristos /* Potentially too large to safely place on the stack. */ 8a0698ed9Schristos rtree_t test_rtree; 9a0698ed9Schristos 10a0698ed9Schristos TEST_BEGIN(test_rtree_read_empty) { 11a0698ed9Schristos tsdn_t *tsdn; 12a0698ed9Schristos 13a0698ed9Schristos tsdn = tsdn_fetch(); 14a0698ed9Schristos 15*7bdf38e5Schristos base_t *base = base_new(tsdn, 0, &ehooks_default_extent_hooks, 16*7bdf38e5Schristos /* metadata_use_hooks */ true); 17*7bdf38e5Schristos expect_ptr_not_null(base, "Unexpected base_new failure"); 18*7bdf38e5Schristos 19a0698ed9Schristos rtree_t *rtree = &test_rtree; 20a0698ed9Schristos rtree_ctx_t rtree_ctx; 21a0698ed9Schristos rtree_ctx_data_init(&rtree_ctx); 22*7bdf38e5Schristos expect_false(rtree_new(rtree, base, false), 23*7bdf38e5Schristos "Unexpected rtree_new() failure"); 24*7bdf38e5Schristos rtree_contents_t contents; 25*7bdf38e5Schristos expect_true(rtree_read_independent(tsdn, rtree, &rtree_ctx, PAGE, 26*7bdf38e5Schristos &contents), "rtree_read_independent() should fail on empty rtree."); 27*7bdf38e5Schristos 28*7bdf38e5Schristos base_delete(tsdn, base); 29a0698ed9Schristos } 30a0698ed9Schristos TEST_END 31a0698ed9Schristos 32a0698ed9Schristos #undef NTHREADS 33a0698ed9Schristos #undef NITERS 34a0698ed9Schristos #undef SEED 35a0698ed9Schristos 36*7bdf38e5Schristos static edata_t * 37*7bdf38e5Schristos alloc_edata(void) { 38*7bdf38e5Schristos void *ret = mallocx(sizeof(edata_t), MALLOCX_ALIGN(EDATA_ALIGNMENT)); 39*7bdf38e5Schristos assert_ptr_not_null(ret, "Unexpected mallocx() failure"); 40*7bdf38e5Schristos 41*7bdf38e5Schristos return ret; 42*7bdf38e5Schristos } 43*7bdf38e5Schristos 44a0698ed9Schristos TEST_BEGIN(test_rtree_extrema) { 45*7bdf38e5Schristos edata_t *edata_a, *edata_b; 46*7bdf38e5Schristos edata_a = alloc_edata(); 47*7bdf38e5Schristos edata_b = alloc_edata(); 48*7bdf38e5Schristos edata_init(edata_a, INVALID_ARENA_IND, NULL, SC_LARGE_MINCLASS, 49*7bdf38e5Schristos false, sz_size2index(SC_LARGE_MINCLASS), 0, 50*7bdf38e5Schristos extent_state_active, false, false, EXTENT_PAI_PAC, EXTENT_NOT_HEAD); 51*7bdf38e5Schristos edata_init(edata_b, INVALID_ARENA_IND, NULL, 0, false, SC_NSIZES, 0, 52*7bdf38e5Schristos extent_state_active, false, false, EXTENT_PAI_PAC, EXTENT_NOT_HEAD); 53a0698ed9Schristos 54a0698ed9Schristos tsdn_t *tsdn = tsdn_fetch(); 55a0698ed9Schristos 56*7bdf38e5Schristos base_t *base = base_new(tsdn, 0, &ehooks_default_extent_hooks, 57*7bdf38e5Schristos /* metadata_use_hooks */ true); 58*7bdf38e5Schristos expect_ptr_not_null(base, "Unexpected base_new failure"); 59*7bdf38e5Schristos 60a0698ed9Schristos rtree_t *rtree = &test_rtree; 61a0698ed9Schristos rtree_ctx_t rtree_ctx; 62a0698ed9Schristos rtree_ctx_data_init(&rtree_ctx); 63*7bdf38e5Schristos expect_false(rtree_new(rtree, base, false), 64*7bdf38e5Schristos "Unexpected rtree_new() failure"); 65a0698ed9Schristos 66*7bdf38e5Schristos rtree_contents_t contents_a; 67*7bdf38e5Schristos contents_a.edata = edata_a; 68*7bdf38e5Schristos contents_a.metadata.szind = edata_szind_get(edata_a); 69*7bdf38e5Schristos contents_a.metadata.slab = edata_slab_get(edata_a); 70*7bdf38e5Schristos contents_a.metadata.is_head = edata_is_head_get(edata_a); 71*7bdf38e5Schristos contents_a.metadata.state = edata_state_get(edata_a); 72*7bdf38e5Schristos expect_false(rtree_write(tsdn, rtree, &rtree_ctx, PAGE, contents_a), 73a0698ed9Schristos "Unexpected rtree_write() failure"); 74*7bdf38e5Schristos expect_false(rtree_write(tsdn, rtree, &rtree_ctx, PAGE, contents_a), 75*7bdf38e5Schristos "Unexpected rtree_write() failure"); 76*7bdf38e5Schristos rtree_contents_t read_contents_a = rtree_read(tsdn, rtree, &rtree_ctx, 77*7bdf38e5Schristos PAGE); 78*7bdf38e5Schristos expect_true(contents_a.edata == read_contents_a.edata 79*7bdf38e5Schristos && contents_a.metadata.szind == read_contents_a.metadata.szind 80*7bdf38e5Schristos && contents_a.metadata.slab == read_contents_a.metadata.slab 81*7bdf38e5Schristos && contents_a.metadata.is_head == read_contents_a.metadata.is_head 82*7bdf38e5Schristos && contents_a.metadata.state == read_contents_a.metadata.state, 83*7bdf38e5Schristos "rtree_read() should return previously set value"); 84a0698ed9Schristos 85*7bdf38e5Schristos rtree_contents_t contents_b; 86*7bdf38e5Schristos contents_b.edata = edata_b; 87*7bdf38e5Schristos contents_b.metadata.szind = edata_szind_get_maybe_invalid(edata_b); 88*7bdf38e5Schristos contents_b.metadata.slab = edata_slab_get(edata_b); 89*7bdf38e5Schristos contents_b.metadata.is_head = edata_is_head_get(edata_b); 90*7bdf38e5Schristos contents_b.metadata.state = edata_state_get(edata_b); 91*7bdf38e5Schristos expect_false(rtree_write(tsdn, rtree, &rtree_ctx, ~((uintptr_t)0), 92*7bdf38e5Schristos contents_b), "Unexpected rtree_write() failure"); 93*7bdf38e5Schristos rtree_contents_t read_contents_b = rtree_read(tsdn, rtree, &rtree_ctx, 94*7bdf38e5Schristos ~((uintptr_t)0)); 95*7bdf38e5Schristos assert_true(contents_b.edata == read_contents_b.edata 96*7bdf38e5Schristos && contents_b.metadata.szind == read_contents_b.metadata.szind 97*7bdf38e5Schristos && contents_b.metadata.slab == read_contents_b.metadata.slab 98*7bdf38e5Schristos && contents_b.metadata.is_head == read_contents_b.metadata.is_head 99*7bdf38e5Schristos && contents_b.metadata.state == read_contents_b.metadata.state, 100*7bdf38e5Schristos "rtree_read() should return previously set value"); 101a0698ed9Schristos 102*7bdf38e5Schristos base_delete(tsdn, base); 103a0698ed9Schristos } 104a0698ed9Schristos TEST_END 105a0698ed9Schristos 106a0698ed9Schristos TEST_BEGIN(test_rtree_bits) { 107a0698ed9Schristos tsdn_t *tsdn = tsdn_fetch(); 108*7bdf38e5Schristos base_t *base = base_new(tsdn, 0, &ehooks_default_extent_hooks, 109*7bdf38e5Schristos /* metadata_use_hooks */ true); 110*7bdf38e5Schristos expect_ptr_not_null(base, "Unexpected base_new failure"); 111a0698ed9Schristos 112a0698ed9Schristos uintptr_t keys[] = {PAGE, PAGE + 1, 113a0698ed9Schristos PAGE + (((uintptr_t)1) << LG_PAGE) - 1}; 114*7bdf38e5Schristos edata_t *edata_c = alloc_edata(); 115*7bdf38e5Schristos edata_init(edata_c, INVALID_ARENA_IND, NULL, 0, false, SC_NSIZES, 0, 116*7bdf38e5Schristos extent_state_active, false, false, EXTENT_PAI_PAC, EXTENT_NOT_HEAD); 117a0698ed9Schristos 118a0698ed9Schristos rtree_t *rtree = &test_rtree; 119a0698ed9Schristos rtree_ctx_t rtree_ctx; 120a0698ed9Schristos rtree_ctx_data_init(&rtree_ctx); 121*7bdf38e5Schristos expect_false(rtree_new(rtree, base, false), 122*7bdf38e5Schristos "Unexpected rtree_new() failure"); 123a0698ed9Schristos 124a0698ed9Schristos for (unsigned i = 0; i < sizeof(keys)/sizeof(uintptr_t); i++) { 125*7bdf38e5Schristos rtree_contents_t contents; 126*7bdf38e5Schristos contents.edata = edata_c; 127*7bdf38e5Schristos contents.metadata.szind = SC_NSIZES; 128*7bdf38e5Schristos contents.metadata.slab = false; 129*7bdf38e5Schristos contents.metadata.is_head = false; 130*7bdf38e5Schristos contents.metadata.state = extent_state_active; 131*7bdf38e5Schristos 132*7bdf38e5Schristos expect_false(rtree_write(tsdn, rtree, &rtree_ctx, keys[i], 133*7bdf38e5Schristos contents), "Unexpected rtree_write() failure"); 134a0698ed9Schristos for (unsigned j = 0; j < sizeof(keys)/sizeof(uintptr_t); j++) { 135*7bdf38e5Schristos expect_ptr_eq(rtree_read(tsdn, rtree, &rtree_ctx, 136*7bdf38e5Schristos keys[j]).edata, edata_c, 137*7bdf38e5Schristos "rtree_edata_read() should return previously set " 138a0698ed9Schristos "value and ignore insignificant key bits; i=%u, " 139a0698ed9Schristos "j=%u, set key=%#"FMTxPTR", get key=%#"FMTxPTR, i, 140a0698ed9Schristos j, keys[i], keys[j]); 141a0698ed9Schristos } 142*7bdf38e5Schristos expect_ptr_null(rtree_read(tsdn, rtree, &rtree_ctx, 143*7bdf38e5Schristos (((uintptr_t)2) << LG_PAGE)).edata, 144a0698ed9Schristos "Only leftmost rtree leaf should be set; i=%u", i); 145a0698ed9Schristos rtree_clear(tsdn, rtree, &rtree_ctx, keys[i]); 146a0698ed9Schristos } 147a0698ed9Schristos 148*7bdf38e5Schristos base_delete(tsdn, base); 149a0698ed9Schristos } 150a0698ed9Schristos TEST_END 151a0698ed9Schristos 152a0698ed9Schristos TEST_BEGIN(test_rtree_random) { 153a0698ed9Schristos #define NSET 16 154a0698ed9Schristos #define SEED 42 155a0698ed9Schristos sfmt_t *sfmt = init_gen_rand(SEED); 156a0698ed9Schristos tsdn_t *tsdn = tsdn_fetch(); 157*7bdf38e5Schristos 158*7bdf38e5Schristos base_t *base = base_new(tsdn, 0, &ehooks_default_extent_hooks, 159*7bdf38e5Schristos /* metadata_use_hooks */ true); 160*7bdf38e5Schristos expect_ptr_not_null(base, "Unexpected base_new failure"); 161*7bdf38e5Schristos 162a0698ed9Schristos uintptr_t keys[NSET]; 163a0698ed9Schristos rtree_t *rtree = &test_rtree; 164a0698ed9Schristos rtree_ctx_t rtree_ctx; 165a0698ed9Schristos rtree_ctx_data_init(&rtree_ctx); 166a0698ed9Schristos 167*7bdf38e5Schristos edata_t *edata_d = alloc_edata(); 168*7bdf38e5Schristos edata_init(edata_d, INVALID_ARENA_IND, NULL, 0, false, SC_NSIZES, 0, 169*7bdf38e5Schristos extent_state_active, false, false, EXTENT_PAI_PAC, EXTENT_NOT_HEAD); 170a0698ed9Schristos 171*7bdf38e5Schristos expect_false(rtree_new(rtree, base, false), 172*7bdf38e5Schristos "Unexpected rtree_new() failure"); 173a0698ed9Schristos 174a0698ed9Schristos for (unsigned i = 0; i < NSET; i++) { 175a0698ed9Schristos keys[i] = (uintptr_t)gen_rand64(sfmt); 176a0698ed9Schristos rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, rtree, 177a0698ed9Schristos &rtree_ctx, keys[i], false, true); 178*7bdf38e5Schristos expect_ptr_not_null(elm, 179a0698ed9Schristos "Unexpected rtree_leaf_elm_lookup() failure"); 180*7bdf38e5Schristos rtree_contents_t contents; 181*7bdf38e5Schristos contents.edata = edata_d; 182*7bdf38e5Schristos contents.metadata.szind = SC_NSIZES; 183*7bdf38e5Schristos contents.metadata.slab = false; 184*7bdf38e5Schristos contents.metadata.is_head = false; 185*7bdf38e5Schristos contents.metadata.state = edata_state_get(edata_d); 186*7bdf38e5Schristos rtree_leaf_elm_write(tsdn, rtree, elm, contents); 187*7bdf38e5Schristos expect_ptr_eq(rtree_read(tsdn, rtree, &rtree_ctx, 188*7bdf38e5Schristos keys[i]).edata, edata_d, 189*7bdf38e5Schristos "rtree_edata_read() should return previously set value"); 190a0698ed9Schristos } 191a0698ed9Schristos for (unsigned i = 0; i < NSET; i++) { 192*7bdf38e5Schristos expect_ptr_eq(rtree_read(tsdn, rtree, &rtree_ctx, 193*7bdf38e5Schristos keys[i]).edata, edata_d, 194*7bdf38e5Schristos "rtree_edata_read() should return previously set value, " 195a0698ed9Schristos "i=%u", i); 196a0698ed9Schristos } 197a0698ed9Schristos 198a0698ed9Schristos for (unsigned i = 0; i < NSET; i++) { 199a0698ed9Schristos rtree_clear(tsdn, rtree, &rtree_ctx, keys[i]); 200*7bdf38e5Schristos expect_ptr_null(rtree_read(tsdn, rtree, &rtree_ctx, 201*7bdf38e5Schristos keys[i]).edata, 202*7bdf38e5Schristos "rtree_edata_read() should return previously set value"); 203a0698ed9Schristos } 204a0698ed9Schristos for (unsigned i = 0; i < NSET; i++) { 205*7bdf38e5Schristos expect_ptr_null(rtree_read(tsdn, rtree, &rtree_ctx, 206*7bdf38e5Schristos keys[i]).edata, 207*7bdf38e5Schristos "rtree_edata_read() should return previously set value"); 208a0698ed9Schristos } 209a0698ed9Schristos 210*7bdf38e5Schristos base_delete(tsdn, base); 211a0698ed9Schristos fini_gen_rand(sfmt); 212a0698ed9Schristos #undef NSET 213a0698ed9Schristos #undef SEED 214a0698ed9Schristos } 215a0698ed9Schristos TEST_END 216a0698ed9Schristos 217*7bdf38e5Schristos static void 218*7bdf38e5Schristos test_rtree_range_write(tsdn_t *tsdn, rtree_t *rtree, uintptr_t start, 219*7bdf38e5Schristos uintptr_t end) { 220*7bdf38e5Schristos rtree_ctx_t rtree_ctx; 221*7bdf38e5Schristos rtree_ctx_data_init(&rtree_ctx); 222*7bdf38e5Schristos 223*7bdf38e5Schristos edata_t *edata_e = alloc_edata(); 224*7bdf38e5Schristos edata_init(edata_e, INVALID_ARENA_IND, NULL, 0, false, SC_NSIZES, 0, 225*7bdf38e5Schristos extent_state_active, false, false, EXTENT_PAI_PAC, EXTENT_NOT_HEAD); 226*7bdf38e5Schristos rtree_contents_t contents; 227*7bdf38e5Schristos contents.edata = edata_e; 228*7bdf38e5Schristos contents.metadata.szind = SC_NSIZES; 229*7bdf38e5Schristos contents.metadata.slab = false; 230*7bdf38e5Schristos contents.metadata.is_head = false; 231*7bdf38e5Schristos contents.metadata.state = extent_state_active; 232*7bdf38e5Schristos 233*7bdf38e5Schristos expect_false(rtree_write(tsdn, rtree, &rtree_ctx, start, 234*7bdf38e5Schristos contents), "Unexpected rtree_write() failure"); 235*7bdf38e5Schristos expect_false(rtree_write(tsdn, rtree, &rtree_ctx, end, 236*7bdf38e5Schristos contents), "Unexpected rtree_write() failure"); 237*7bdf38e5Schristos 238*7bdf38e5Schristos rtree_write_range(tsdn, rtree, &rtree_ctx, start, end, contents); 239*7bdf38e5Schristos for (uintptr_t i = 0; i < ((end - start) >> LG_PAGE); i++) { 240*7bdf38e5Schristos expect_ptr_eq(rtree_read(tsdn, rtree, &rtree_ctx, 241*7bdf38e5Schristos start + (i << LG_PAGE)).edata, edata_e, 242*7bdf38e5Schristos "rtree_edata_read() should return previously set value"); 243*7bdf38e5Schristos } 244*7bdf38e5Schristos rtree_clear_range(tsdn, rtree, &rtree_ctx, start, end); 245*7bdf38e5Schristos rtree_leaf_elm_t *elm; 246*7bdf38e5Schristos for (uintptr_t i = 0; i < ((end - start) >> LG_PAGE); i++) { 247*7bdf38e5Schristos elm = rtree_leaf_elm_lookup(tsdn, rtree, &rtree_ctx, 248*7bdf38e5Schristos start + (i << LG_PAGE), false, false); 249*7bdf38e5Schristos expect_ptr_not_null(elm, "Should have been initialized."); 250*7bdf38e5Schristos expect_ptr_null(rtree_leaf_elm_read(tsdn, rtree, elm, 251*7bdf38e5Schristos false).edata, "Should have been cleared."); 252*7bdf38e5Schristos } 253*7bdf38e5Schristos } 254*7bdf38e5Schristos 255*7bdf38e5Schristos TEST_BEGIN(test_rtree_range) { 256*7bdf38e5Schristos tsdn_t *tsdn = tsdn_fetch(); 257*7bdf38e5Schristos base_t *base = base_new(tsdn, 0, &ehooks_default_extent_hooks, 258*7bdf38e5Schristos /* metadata_use_hooks */ true); 259*7bdf38e5Schristos expect_ptr_not_null(base, "Unexpected base_new failure"); 260*7bdf38e5Schristos 261*7bdf38e5Schristos rtree_t *rtree = &test_rtree; 262*7bdf38e5Schristos expect_false(rtree_new(rtree, base, false), 263*7bdf38e5Schristos "Unexpected rtree_new() failure"); 264*7bdf38e5Schristos 265*7bdf38e5Schristos /* Not crossing rtree node boundary first. */ 266*7bdf38e5Schristos uintptr_t start = ZU(1) << rtree_leaf_maskbits(); 267*7bdf38e5Schristos uintptr_t end = start + (ZU(100) << LG_PAGE); 268*7bdf38e5Schristos test_rtree_range_write(tsdn, rtree, start, end); 269*7bdf38e5Schristos 270*7bdf38e5Schristos /* Crossing rtree node boundary. */ 271*7bdf38e5Schristos start = (ZU(1) << rtree_leaf_maskbits()) - (ZU(10) << LG_PAGE); 272*7bdf38e5Schristos end = start + (ZU(100) << LG_PAGE); 273*7bdf38e5Schristos assert_ptr_ne((void *)rtree_leafkey(start), (void *)rtree_leafkey(end), 274*7bdf38e5Schristos "The range should span across two rtree nodes"); 275*7bdf38e5Schristos test_rtree_range_write(tsdn, rtree, start, end); 276*7bdf38e5Schristos 277*7bdf38e5Schristos base_delete(tsdn, base); 278*7bdf38e5Schristos } 279*7bdf38e5Schristos TEST_END 280*7bdf38e5Schristos 281a0698ed9Schristos int 282a0698ed9Schristos main(void) { 283a0698ed9Schristos return test( 284a0698ed9Schristos test_rtree_read_empty, 285a0698ed9Schristos test_rtree_extrema, 286a0698ed9Schristos test_rtree_bits, 287*7bdf38e5Schristos test_rtree_random, 288*7bdf38e5Schristos test_rtree_range); 289a0698ed9Schristos } 290