1*8e33eff8Schristos #include "test/jemalloc_test.h" 2*8e33eff8Schristos 3*8e33eff8Schristos #include "jemalloc/internal/rtree.h" 4*8e33eff8Schristos 5*8e33eff8Schristos rtree_node_alloc_t *rtree_node_alloc_orig; 6*8e33eff8Schristos rtree_node_dalloc_t *rtree_node_dalloc_orig; 7*8e33eff8Schristos rtree_leaf_alloc_t *rtree_leaf_alloc_orig; 8*8e33eff8Schristos rtree_leaf_dalloc_t *rtree_leaf_dalloc_orig; 9*8e33eff8Schristos 10*8e33eff8Schristos /* Potentially too large to safely place on the stack. */ 11*8e33eff8Schristos rtree_t test_rtree; 12*8e33eff8Schristos 13*8e33eff8Schristos static rtree_node_elm_t * 14*8e33eff8Schristos rtree_node_alloc_intercept(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { 15*8e33eff8Schristos rtree_node_elm_t *node; 16*8e33eff8Schristos 17*8e33eff8Schristos if (rtree != &test_rtree) { 18*8e33eff8Schristos return rtree_node_alloc_orig(tsdn, rtree, nelms); 19*8e33eff8Schristos } 20*8e33eff8Schristos 21*8e33eff8Schristos malloc_mutex_unlock(tsdn, &rtree->init_lock); 22*8e33eff8Schristos node = (rtree_node_elm_t *)calloc(nelms, sizeof(rtree_node_elm_t)); 23*8e33eff8Schristos assert_ptr_not_null(node, "Unexpected calloc() failure"); 24*8e33eff8Schristos malloc_mutex_lock(tsdn, &rtree->init_lock); 25*8e33eff8Schristos 26*8e33eff8Schristos return node; 27*8e33eff8Schristos } 28*8e33eff8Schristos 29*8e33eff8Schristos static void 30*8e33eff8Schristos rtree_node_dalloc_intercept(tsdn_t *tsdn, rtree_t *rtree, 31*8e33eff8Schristos rtree_node_elm_t *node) { 32*8e33eff8Schristos if (rtree != &test_rtree) { 33*8e33eff8Schristos rtree_node_dalloc_orig(tsdn, rtree, node); 34*8e33eff8Schristos return; 35*8e33eff8Schristos } 36*8e33eff8Schristos 37*8e33eff8Schristos free(node); 38*8e33eff8Schristos } 39*8e33eff8Schristos 40*8e33eff8Schristos static rtree_leaf_elm_t * 41*8e33eff8Schristos rtree_leaf_alloc_intercept(tsdn_t *tsdn, rtree_t *rtree, size_t nelms) { 42*8e33eff8Schristos rtree_leaf_elm_t *leaf; 43*8e33eff8Schristos 44*8e33eff8Schristos if (rtree != &test_rtree) { 45*8e33eff8Schristos return rtree_leaf_alloc_orig(tsdn, rtree, nelms); 46*8e33eff8Schristos } 47*8e33eff8Schristos 48*8e33eff8Schristos malloc_mutex_unlock(tsdn, &rtree->init_lock); 49*8e33eff8Schristos leaf = (rtree_leaf_elm_t *)calloc(nelms, sizeof(rtree_leaf_elm_t)); 50*8e33eff8Schristos assert_ptr_not_null(leaf, "Unexpected calloc() failure"); 51*8e33eff8Schristos malloc_mutex_lock(tsdn, &rtree->init_lock); 52*8e33eff8Schristos 53*8e33eff8Schristos return leaf; 54*8e33eff8Schristos } 55*8e33eff8Schristos 56*8e33eff8Schristos static void 57*8e33eff8Schristos rtree_leaf_dalloc_intercept(tsdn_t *tsdn, rtree_t *rtree, 58*8e33eff8Schristos rtree_leaf_elm_t *leaf) { 59*8e33eff8Schristos if (rtree != &test_rtree) { 60*8e33eff8Schristos rtree_leaf_dalloc_orig(tsdn, rtree, leaf); 61*8e33eff8Schristos return; 62*8e33eff8Schristos } 63*8e33eff8Schristos 64*8e33eff8Schristos free(leaf); 65*8e33eff8Schristos } 66*8e33eff8Schristos 67*8e33eff8Schristos TEST_BEGIN(test_rtree_read_empty) { 68*8e33eff8Schristos tsdn_t *tsdn; 69*8e33eff8Schristos 70*8e33eff8Schristos tsdn = tsdn_fetch(); 71*8e33eff8Schristos 72*8e33eff8Schristos rtree_t *rtree = &test_rtree; 73*8e33eff8Schristos rtree_ctx_t rtree_ctx; 74*8e33eff8Schristos rtree_ctx_data_init(&rtree_ctx); 75*8e33eff8Schristos assert_false(rtree_new(rtree, false), "Unexpected rtree_new() failure"); 76*8e33eff8Schristos assert_ptr_null(rtree_extent_read(tsdn, rtree, &rtree_ctx, PAGE, 77*8e33eff8Schristos false), "rtree_extent_read() should return NULL for empty tree"); 78*8e33eff8Schristos rtree_delete(tsdn, rtree); 79*8e33eff8Schristos } 80*8e33eff8Schristos TEST_END 81*8e33eff8Schristos 82*8e33eff8Schristos #undef NTHREADS 83*8e33eff8Schristos #undef NITERS 84*8e33eff8Schristos #undef SEED 85*8e33eff8Schristos 86*8e33eff8Schristos TEST_BEGIN(test_rtree_extrema) { 87*8e33eff8Schristos extent_t extent_a, extent_b; 88*8e33eff8Schristos extent_init(&extent_a, NULL, NULL, LARGE_MINCLASS, false, 89*8e33eff8Schristos sz_size2index(LARGE_MINCLASS), 0, extent_state_active, false, 90*8e33eff8Schristos false, true); 91*8e33eff8Schristos extent_init(&extent_b, NULL, NULL, 0, false, NSIZES, 0, 92*8e33eff8Schristos extent_state_active, false, false, true); 93*8e33eff8Schristos 94*8e33eff8Schristos tsdn_t *tsdn = tsdn_fetch(); 95*8e33eff8Schristos 96*8e33eff8Schristos rtree_t *rtree = &test_rtree; 97*8e33eff8Schristos rtree_ctx_t rtree_ctx; 98*8e33eff8Schristos rtree_ctx_data_init(&rtree_ctx); 99*8e33eff8Schristos assert_false(rtree_new(rtree, false), "Unexpected rtree_new() failure"); 100*8e33eff8Schristos 101*8e33eff8Schristos assert_false(rtree_write(tsdn, rtree, &rtree_ctx, PAGE, &extent_a, 102*8e33eff8Schristos extent_szind_get(&extent_a), extent_slab_get(&extent_a)), 103*8e33eff8Schristos "Unexpected rtree_write() failure"); 104*8e33eff8Schristos rtree_szind_slab_update(tsdn, rtree, &rtree_ctx, PAGE, 105*8e33eff8Schristos extent_szind_get(&extent_a), extent_slab_get(&extent_a)); 106*8e33eff8Schristos assert_ptr_eq(rtree_extent_read(tsdn, rtree, &rtree_ctx, PAGE, true), 107*8e33eff8Schristos &extent_a, 108*8e33eff8Schristos "rtree_extent_read() should return previously set value"); 109*8e33eff8Schristos 110*8e33eff8Schristos assert_false(rtree_write(tsdn, rtree, &rtree_ctx, ~((uintptr_t)0), 111*8e33eff8Schristos &extent_b, extent_szind_get_maybe_invalid(&extent_b), 112*8e33eff8Schristos extent_slab_get(&extent_b)), "Unexpected rtree_write() failure"); 113*8e33eff8Schristos assert_ptr_eq(rtree_extent_read(tsdn, rtree, &rtree_ctx, 114*8e33eff8Schristos ~((uintptr_t)0), true), &extent_b, 115*8e33eff8Schristos "rtree_extent_read() should return previously set value"); 116*8e33eff8Schristos 117*8e33eff8Schristos rtree_delete(tsdn, rtree); 118*8e33eff8Schristos } 119*8e33eff8Schristos TEST_END 120*8e33eff8Schristos 121*8e33eff8Schristos TEST_BEGIN(test_rtree_bits) { 122*8e33eff8Schristos tsdn_t *tsdn = tsdn_fetch(); 123*8e33eff8Schristos 124*8e33eff8Schristos uintptr_t keys[] = {PAGE, PAGE + 1, 125*8e33eff8Schristos PAGE + (((uintptr_t)1) << LG_PAGE) - 1}; 126*8e33eff8Schristos 127*8e33eff8Schristos extent_t extent; 128*8e33eff8Schristos extent_init(&extent, NULL, NULL, 0, false, NSIZES, 0, 129*8e33eff8Schristos extent_state_active, false, false, true); 130*8e33eff8Schristos 131*8e33eff8Schristos rtree_t *rtree = &test_rtree; 132*8e33eff8Schristos rtree_ctx_t rtree_ctx; 133*8e33eff8Schristos rtree_ctx_data_init(&rtree_ctx); 134*8e33eff8Schristos assert_false(rtree_new(rtree, false), "Unexpected rtree_new() failure"); 135*8e33eff8Schristos 136*8e33eff8Schristos for (unsigned i = 0; i < sizeof(keys)/sizeof(uintptr_t); i++) { 137*8e33eff8Schristos assert_false(rtree_write(tsdn, rtree, &rtree_ctx, keys[i], 138*8e33eff8Schristos &extent, NSIZES, false), 139*8e33eff8Schristos "Unexpected rtree_write() failure"); 140*8e33eff8Schristos for (unsigned j = 0; j < sizeof(keys)/sizeof(uintptr_t); j++) { 141*8e33eff8Schristos assert_ptr_eq(rtree_extent_read(tsdn, rtree, &rtree_ctx, 142*8e33eff8Schristos keys[j], true), &extent, 143*8e33eff8Schristos "rtree_extent_read() should return previously set " 144*8e33eff8Schristos "value and ignore insignificant key bits; i=%u, " 145*8e33eff8Schristos "j=%u, set key=%#"FMTxPTR", get key=%#"FMTxPTR, i, 146*8e33eff8Schristos j, keys[i], keys[j]); 147*8e33eff8Schristos } 148*8e33eff8Schristos assert_ptr_null(rtree_extent_read(tsdn, rtree, &rtree_ctx, 149*8e33eff8Schristos (((uintptr_t)2) << LG_PAGE), false), 150*8e33eff8Schristos "Only leftmost rtree leaf should be set; i=%u", i); 151*8e33eff8Schristos rtree_clear(tsdn, rtree, &rtree_ctx, keys[i]); 152*8e33eff8Schristos } 153*8e33eff8Schristos 154*8e33eff8Schristos rtree_delete(tsdn, rtree); 155*8e33eff8Schristos } 156*8e33eff8Schristos TEST_END 157*8e33eff8Schristos 158*8e33eff8Schristos TEST_BEGIN(test_rtree_random) { 159*8e33eff8Schristos #define NSET 16 160*8e33eff8Schristos #define SEED 42 161*8e33eff8Schristos sfmt_t *sfmt = init_gen_rand(SEED); 162*8e33eff8Schristos tsdn_t *tsdn = tsdn_fetch(); 163*8e33eff8Schristos uintptr_t keys[NSET]; 164*8e33eff8Schristos rtree_t *rtree = &test_rtree; 165*8e33eff8Schristos rtree_ctx_t rtree_ctx; 166*8e33eff8Schristos rtree_ctx_data_init(&rtree_ctx); 167*8e33eff8Schristos 168*8e33eff8Schristos extent_t extent; 169*8e33eff8Schristos extent_init(&extent, NULL, NULL, 0, false, NSIZES, 0, 170*8e33eff8Schristos extent_state_active, false, false, true); 171*8e33eff8Schristos 172*8e33eff8Schristos assert_false(rtree_new(rtree, false), "Unexpected rtree_new() failure"); 173*8e33eff8Schristos 174*8e33eff8Schristos for (unsigned i = 0; i < NSET; i++) { 175*8e33eff8Schristos keys[i] = (uintptr_t)gen_rand64(sfmt); 176*8e33eff8Schristos rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, rtree, 177*8e33eff8Schristos &rtree_ctx, keys[i], false, true); 178*8e33eff8Schristos assert_ptr_not_null(elm, 179*8e33eff8Schristos "Unexpected rtree_leaf_elm_lookup() failure"); 180*8e33eff8Schristos rtree_leaf_elm_write(tsdn, rtree, elm, &extent, NSIZES, false); 181*8e33eff8Schristos assert_ptr_eq(rtree_extent_read(tsdn, rtree, &rtree_ctx, 182*8e33eff8Schristos keys[i], true), &extent, 183*8e33eff8Schristos "rtree_extent_read() should return previously set value"); 184*8e33eff8Schristos } 185*8e33eff8Schristos for (unsigned i = 0; i < NSET; i++) { 186*8e33eff8Schristos assert_ptr_eq(rtree_extent_read(tsdn, rtree, &rtree_ctx, 187*8e33eff8Schristos keys[i], true), &extent, 188*8e33eff8Schristos "rtree_extent_read() should return previously set value, " 189*8e33eff8Schristos "i=%u", i); 190*8e33eff8Schristos } 191*8e33eff8Schristos 192*8e33eff8Schristos for (unsigned i = 0; i < NSET; i++) { 193*8e33eff8Schristos rtree_clear(tsdn, rtree, &rtree_ctx, keys[i]); 194*8e33eff8Schristos assert_ptr_null(rtree_extent_read(tsdn, rtree, &rtree_ctx, 195*8e33eff8Schristos keys[i], true), 196*8e33eff8Schristos "rtree_extent_read() should return previously set value"); 197*8e33eff8Schristos } 198*8e33eff8Schristos for (unsigned i = 0; i < NSET; i++) { 199*8e33eff8Schristos assert_ptr_null(rtree_extent_read(tsdn, rtree, &rtree_ctx, 200*8e33eff8Schristos keys[i], true), 201*8e33eff8Schristos "rtree_extent_read() should return previously set value"); 202*8e33eff8Schristos } 203*8e33eff8Schristos 204*8e33eff8Schristos rtree_delete(tsdn, rtree); 205*8e33eff8Schristos fini_gen_rand(sfmt); 206*8e33eff8Schristos #undef NSET 207*8e33eff8Schristos #undef SEED 208*8e33eff8Schristos } 209*8e33eff8Schristos TEST_END 210*8e33eff8Schristos 211*8e33eff8Schristos int 212*8e33eff8Schristos main(void) { 213*8e33eff8Schristos rtree_node_alloc_orig = rtree_node_alloc; 214*8e33eff8Schristos rtree_node_alloc = rtree_node_alloc_intercept; 215*8e33eff8Schristos rtree_node_dalloc_orig = rtree_node_dalloc; 216*8e33eff8Schristos rtree_node_dalloc = rtree_node_dalloc_intercept; 217*8e33eff8Schristos rtree_leaf_alloc_orig = rtree_leaf_alloc; 218*8e33eff8Schristos rtree_leaf_alloc = rtree_leaf_alloc_intercept; 219*8e33eff8Schristos rtree_leaf_dalloc_orig = rtree_leaf_dalloc; 220*8e33eff8Schristos rtree_leaf_dalloc = rtree_leaf_dalloc_intercept; 221*8e33eff8Schristos 222*8e33eff8Schristos return test( 223*8e33eff8Schristos test_rtree_read_empty, 224*8e33eff8Schristos test_rtree_extrema, 225*8e33eff8Schristos test_rtree_bits, 226*8e33eff8Schristos test_rtree_random); 227*8e33eff8Schristos } 228