xref: /netbsd-src/external/bsd/jemalloc/dist/test/unit/rtree.c (revision 7bdf38e5b7a28439665f2fdeff81e36913eef7dd)
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