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