xref: /netbsd-src/external/bsd/jemalloc/dist/test/unit/edata_cache.c (revision 7bdf38e5b7a28439665f2fdeff81e36913eef7dd)
1*7bdf38e5Schristos #include "test/jemalloc_test.h"
2*7bdf38e5Schristos 
3*7bdf38e5Schristos #include "jemalloc/internal/edata_cache.h"
4*7bdf38e5Schristos 
5*7bdf38e5Schristos static void
6*7bdf38e5Schristos test_edata_cache_init(edata_cache_t *edata_cache) {
7*7bdf38e5Schristos 	base_t *base = base_new(TSDN_NULL, /* ind */ 1,
8*7bdf38e5Schristos 	    &ehooks_default_extent_hooks, /* metadata_use_hooks */ true);
9*7bdf38e5Schristos 	assert_ptr_not_null(base, "");
10*7bdf38e5Schristos 	bool err = edata_cache_init(edata_cache, base);
11*7bdf38e5Schristos 	assert_false(err, "");
12*7bdf38e5Schristos }
13*7bdf38e5Schristos 
14*7bdf38e5Schristos static void
15*7bdf38e5Schristos test_edata_cache_destroy(edata_cache_t *edata_cache) {
16*7bdf38e5Schristos 	base_delete(TSDN_NULL, edata_cache->base);
17*7bdf38e5Schristos }
18*7bdf38e5Schristos 
19*7bdf38e5Schristos TEST_BEGIN(test_edata_cache) {
20*7bdf38e5Schristos 	edata_cache_t ec;
21*7bdf38e5Schristos 	test_edata_cache_init(&ec);
22*7bdf38e5Schristos 
23*7bdf38e5Schristos 	/* Get one */
24*7bdf38e5Schristos 	edata_t *ed1 = edata_cache_get(TSDN_NULL, &ec);
25*7bdf38e5Schristos 	assert_ptr_not_null(ed1, "");
26*7bdf38e5Schristos 
27*7bdf38e5Schristos 	/* Cache should be empty */
28*7bdf38e5Schristos 	assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
29*7bdf38e5Schristos 
30*7bdf38e5Schristos 	/* Get another */
31*7bdf38e5Schristos 	edata_t *ed2 = edata_cache_get(TSDN_NULL, &ec);
32*7bdf38e5Schristos 	assert_ptr_not_null(ed2, "");
33*7bdf38e5Schristos 
34*7bdf38e5Schristos 	/* Still empty */
35*7bdf38e5Schristos 	assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
36*7bdf38e5Schristos 
37*7bdf38e5Schristos 	/* Put one back, and the cache should now have one item */
38*7bdf38e5Schristos 	edata_cache_put(TSDN_NULL, &ec, ed1);
39*7bdf38e5Schristos 	assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 1, "");
40*7bdf38e5Schristos 
41*7bdf38e5Schristos 	/* Reallocating should reuse the item, and leave an empty cache. */
42*7bdf38e5Schristos 	edata_t *ed1_again = edata_cache_get(TSDN_NULL, &ec);
43*7bdf38e5Schristos 	assert_ptr_eq(ed1, ed1_again, "");
44*7bdf38e5Schristos 	assert_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
45*7bdf38e5Schristos 
46*7bdf38e5Schristos 	test_edata_cache_destroy(&ec);
47*7bdf38e5Schristos }
48*7bdf38e5Schristos TEST_END
49*7bdf38e5Schristos 
50*7bdf38e5Schristos static size_t
51*7bdf38e5Schristos ecf_count(edata_cache_fast_t *ecf) {
52*7bdf38e5Schristos 	size_t count = 0;
53*7bdf38e5Schristos 	edata_t *cur;
54*7bdf38e5Schristos 	ql_foreach(cur, &ecf->list.head, ql_link_inactive) {
55*7bdf38e5Schristos 		count++;
56*7bdf38e5Schristos 	}
57*7bdf38e5Schristos 	return count;
58*7bdf38e5Schristos }
59*7bdf38e5Schristos 
60*7bdf38e5Schristos TEST_BEGIN(test_edata_cache_fast_simple) {
61*7bdf38e5Schristos 	edata_cache_t ec;
62*7bdf38e5Schristos 	edata_cache_fast_t ecf;
63*7bdf38e5Schristos 
64*7bdf38e5Schristos 	test_edata_cache_init(&ec);
65*7bdf38e5Schristos 	edata_cache_fast_init(&ecf, &ec);
66*7bdf38e5Schristos 
67*7bdf38e5Schristos 	edata_t *ed1 = edata_cache_fast_get(TSDN_NULL, &ecf);
68*7bdf38e5Schristos 	expect_ptr_not_null(ed1, "");
69*7bdf38e5Schristos 	expect_zu_eq(ecf_count(&ecf), 0, "");
70*7bdf38e5Schristos 	expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
71*7bdf38e5Schristos 
72*7bdf38e5Schristos 	edata_t *ed2 = edata_cache_fast_get(TSDN_NULL, &ecf);
73*7bdf38e5Schristos 	expect_ptr_not_null(ed2, "");
74*7bdf38e5Schristos 	expect_zu_eq(ecf_count(&ecf), 0, "");
75*7bdf38e5Schristos 	expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
76*7bdf38e5Schristos 
77*7bdf38e5Schristos 	edata_cache_fast_put(TSDN_NULL, &ecf, ed1);
78*7bdf38e5Schristos 	expect_zu_eq(ecf_count(&ecf), 1, "");
79*7bdf38e5Schristos 	expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
80*7bdf38e5Schristos 
81*7bdf38e5Schristos 	edata_cache_fast_put(TSDN_NULL, &ecf, ed2);
82*7bdf38e5Schristos 	expect_zu_eq(ecf_count(&ecf), 2, "");
83*7bdf38e5Schristos 	expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
84*7bdf38e5Schristos 
85*7bdf38e5Schristos 	/* LIFO ordering. */
86*7bdf38e5Schristos 	expect_ptr_eq(ed2, edata_cache_fast_get(TSDN_NULL, &ecf), "");
87*7bdf38e5Schristos 	expect_zu_eq(ecf_count(&ecf), 1, "");
88*7bdf38e5Schristos 	expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
89*7bdf38e5Schristos 
90*7bdf38e5Schristos 	expect_ptr_eq(ed1, edata_cache_fast_get(TSDN_NULL, &ecf), "");
91*7bdf38e5Schristos 	expect_zu_eq(ecf_count(&ecf), 0, "");
92*7bdf38e5Schristos 	expect_zu_eq(atomic_load_zu(&ec.count, ATOMIC_RELAXED), 0, "");
93*7bdf38e5Schristos 
94*7bdf38e5Schristos 	test_edata_cache_destroy(&ec);
95*7bdf38e5Schristos }
96*7bdf38e5Schristos TEST_END
97*7bdf38e5Schristos 
98*7bdf38e5Schristos TEST_BEGIN(test_edata_cache_fill) {
99*7bdf38e5Schristos 	edata_cache_t ec;
100*7bdf38e5Schristos 	edata_cache_fast_t ecf;
101*7bdf38e5Schristos 
102*7bdf38e5Schristos 	test_edata_cache_init(&ec);
103*7bdf38e5Schristos 	edata_cache_fast_init(&ecf, &ec);
104*7bdf38e5Schristos 
105*7bdf38e5Schristos 	edata_t *allocs[EDATA_CACHE_FAST_FILL * 2];
106*7bdf38e5Schristos 
107*7bdf38e5Schristos 	/*
108*7bdf38e5Schristos 	 * If the fallback cache can't satisfy the request, we shouldn't do
109*7bdf38e5Schristos 	 * extra allocations until compelled to.  Put half the fill goal in the
110*7bdf38e5Schristos 	 * fallback.
111*7bdf38e5Schristos 	 */
112*7bdf38e5Schristos 	for (int i = 0; i < EDATA_CACHE_FAST_FILL / 2; i++) {
113*7bdf38e5Schristos 		allocs[i] = edata_cache_get(TSDN_NULL, &ec);
114*7bdf38e5Schristos 	}
115*7bdf38e5Schristos 	for (int i = 0; i < EDATA_CACHE_FAST_FILL / 2; i++) {
116*7bdf38e5Schristos 		edata_cache_put(TSDN_NULL, &ec, allocs[i]);
117*7bdf38e5Schristos 	}
118*7bdf38e5Schristos 	expect_zu_eq(EDATA_CACHE_FAST_FILL / 2,
119*7bdf38e5Schristos 	    atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
120*7bdf38e5Schristos 
121*7bdf38e5Schristos 	allocs[0] = edata_cache_fast_get(TSDN_NULL, &ecf);
122*7bdf38e5Schristos 	expect_zu_eq(EDATA_CACHE_FAST_FILL / 2 - 1, ecf_count(&ecf),
123*7bdf38e5Schristos 	    "Should have grabbed all edatas available but no more.");
124*7bdf38e5Schristos 
125*7bdf38e5Schristos 	for (int i = 1; i < EDATA_CACHE_FAST_FILL / 2; i++) {
126*7bdf38e5Schristos 		allocs[i] = edata_cache_fast_get(TSDN_NULL, &ecf);
127*7bdf38e5Schristos 		expect_ptr_not_null(allocs[i], "");
128*7bdf38e5Schristos 	}
129*7bdf38e5Schristos 	expect_zu_eq(0, ecf_count(&ecf), "");
130*7bdf38e5Schristos 
131*7bdf38e5Schristos 	/* When forced, we should alloc from the base. */
132*7bdf38e5Schristos 	edata_t *edata = edata_cache_fast_get(TSDN_NULL, &ecf);
133*7bdf38e5Schristos 	expect_ptr_not_null(edata, "");
134*7bdf38e5Schristos 	expect_zu_eq(0, ecf_count(&ecf), "Allocated more than necessary");
135*7bdf38e5Schristos 	expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED),
136*7bdf38e5Schristos 	    "Allocated more than necessary");
137*7bdf38e5Schristos 
138*7bdf38e5Schristos 	/*
139*7bdf38e5Schristos 	 * We should correctly fill in the common case where the fallback isn't
140*7bdf38e5Schristos 	 * exhausted, too.
141*7bdf38e5Schristos 	 */
142*7bdf38e5Schristos 	for (int i = 0; i < EDATA_CACHE_FAST_FILL * 2; i++) {
143*7bdf38e5Schristos 		allocs[i] = edata_cache_get(TSDN_NULL, &ec);
144*7bdf38e5Schristos 		expect_ptr_not_null(allocs[i], "");
145*7bdf38e5Schristos 	}
146*7bdf38e5Schristos 	for (int i = 0; i < EDATA_CACHE_FAST_FILL * 2; i++) {
147*7bdf38e5Schristos 		edata_cache_put(TSDN_NULL, &ec, allocs[i]);
148*7bdf38e5Schristos 	}
149*7bdf38e5Schristos 
150*7bdf38e5Schristos 	allocs[0] = edata_cache_fast_get(TSDN_NULL, &ecf);
151*7bdf38e5Schristos 	expect_zu_eq(EDATA_CACHE_FAST_FILL - 1, ecf_count(&ecf), "");
152*7bdf38e5Schristos 	expect_zu_eq(EDATA_CACHE_FAST_FILL,
153*7bdf38e5Schristos 	    atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
154*7bdf38e5Schristos 	for (int i = 1; i < EDATA_CACHE_FAST_FILL; i++) {
155*7bdf38e5Schristos 		expect_zu_eq(EDATA_CACHE_FAST_FILL - i, ecf_count(&ecf), "");
156*7bdf38e5Schristos 		expect_zu_eq(EDATA_CACHE_FAST_FILL,
157*7bdf38e5Schristos 		    atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
158*7bdf38e5Schristos 		allocs[i] = edata_cache_fast_get(TSDN_NULL, &ecf);
159*7bdf38e5Schristos 		expect_ptr_not_null(allocs[i], "");
160*7bdf38e5Schristos 	}
161*7bdf38e5Schristos 	expect_zu_eq(0, ecf_count(&ecf), "");
162*7bdf38e5Schristos 	expect_zu_eq(EDATA_CACHE_FAST_FILL,
163*7bdf38e5Schristos 	    atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
164*7bdf38e5Schristos 
165*7bdf38e5Schristos 	allocs[0] = edata_cache_fast_get(TSDN_NULL, &ecf);
166*7bdf38e5Schristos 	expect_zu_eq(EDATA_CACHE_FAST_FILL - 1, ecf_count(&ecf), "");
167*7bdf38e5Schristos 	expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
168*7bdf38e5Schristos 	for (int i = 1; i < EDATA_CACHE_FAST_FILL; i++) {
169*7bdf38e5Schristos 		expect_zu_eq(EDATA_CACHE_FAST_FILL - i, ecf_count(&ecf), "");
170*7bdf38e5Schristos 		expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
171*7bdf38e5Schristos 		allocs[i] = edata_cache_fast_get(TSDN_NULL, &ecf);
172*7bdf38e5Schristos 		expect_ptr_not_null(allocs[i], "");
173*7bdf38e5Schristos 	}
174*7bdf38e5Schristos 	expect_zu_eq(0, ecf_count(&ecf), "");
175*7bdf38e5Schristos 	expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
176*7bdf38e5Schristos 
177*7bdf38e5Schristos 	test_edata_cache_destroy(&ec);
178*7bdf38e5Schristos }
179*7bdf38e5Schristos TEST_END
180*7bdf38e5Schristos 
181*7bdf38e5Schristos TEST_BEGIN(test_edata_cache_disable) {
182*7bdf38e5Schristos 	edata_cache_t ec;
183*7bdf38e5Schristos 	edata_cache_fast_t ecf;
184*7bdf38e5Schristos 
185*7bdf38e5Schristos 	test_edata_cache_init(&ec);
186*7bdf38e5Schristos 	edata_cache_fast_init(&ecf, &ec);
187*7bdf38e5Schristos 
188*7bdf38e5Schristos 	for (int i = 0; i < EDATA_CACHE_FAST_FILL; i++) {
189*7bdf38e5Schristos 		edata_t *edata = edata_cache_get(TSDN_NULL, &ec);
190*7bdf38e5Schristos 		expect_ptr_not_null(edata, "");
191*7bdf38e5Schristos 		edata_cache_fast_put(TSDN_NULL, &ecf, edata);
192*7bdf38e5Schristos 	}
193*7bdf38e5Schristos 
194*7bdf38e5Schristos 	expect_zu_eq(EDATA_CACHE_FAST_FILL, ecf_count(&ecf), "");
195*7bdf38e5Schristos 	expect_zu_eq(0, atomic_load_zu(&ec.count, ATOMIC_RELAXED), "");
196*7bdf38e5Schristos 
197*7bdf38e5Schristos 	edata_cache_fast_disable(TSDN_NULL, &ecf);
198*7bdf38e5Schristos 
199*7bdf38e5Schristos 	expect_zu_eq(0, ecf_count(&ecf), "");
200*7bdf38e5Schristos 	expect_zu_eq(EDATA_CACHE_FAST_FILL,
201*7bdf38e5Schristos 	    atomic_load_zu(&ec.count, ATOMIC_RELAXED), "Disabling should flush");
202*7bdf38e5Schristos 
203*7bdf38e5Schristos 	edata_t *edata = edata_cache_fast_get(TSDN_NULL, &ecf);
204*7bdf38e5Schristos 	expect_zu_eq(0, ecf_count(&ecf), "");
205*7bdf38e5Schristos 	expect_zu_eq(EDATA_CACHE_FAST_FILL - 1,
206*7bdf38e5Schristos 	    atomic_load_zu(&ec.count, ATOMIC_RELAXED),
207*7bdf38e5Schristos 	    "Disabled ecf should forward on get");
208*7bdf38e5Schristos 
209*7bdf38e5Schristos 	edata_cache_fast_put(TSDN_NULL, &ecf, edata);
210*7bdf38e5Schristos 	expect_zu_eq(0, ecf_count(&ecf), "");
211*7bdf38e5Schristos 	expect_zu_eq(EDATA_CACHE_FAST_FILL,
212*7bdf38e5Schristos 	    atomic_load_zu(&ec.count, ATOMIC_RELAXED),
213*7bdf38e5Schristos 	    "Disabled ecf should forward on put");
214*7bdf38e5Schristos 
215*7bdf38e5Schristos 	test_edata_cache_destroy(&ec);
216*7bdf38e5Schristos }
217*7bdf38e5Schristos TEST_END
218*7bdf38e5Schristos 
219*7bdf38e5Schristos int
220*7bdf38e5Schristos main(void) {
221*7bdf38e5Schristos 	return test(
222*7bdf38e5Schristos 	    test_edata_cache,
223*7bdf38e5Schristos 	    test_edata_cache_fast_simple,
224*7bdf38e5Schristos 	    test_edata_cache_fill,
225*7bdf38e5Schristos 	    test_edata_cache_disable);
226*7bdf38e5Schristos }
227