xref: /netbsd-src/external/bsd/jemalloc/dist/test/unit/batch_alloc.c (revision 7bdf38e5b7a28439665f2fdeff81e36913eef7dd)
1*7bdf38e5Schristos #include "test/jemalloc_test.h"
2*7bdf38e5Schristos 
3*7bdf38e5Schristos #define BATCH_MAX ((1U << 16) + 1024)
4*7bdf38e5Schristos static void *global_ptrs[BATCH_MAX];
5*7bdf38e5Schristos 
6*7bdf38e5Schristos #define PAGE_ALIGNED(ptr) (((uintptr_t)ptr & PAGE_MASK) == 0)
7*7bdf38e5Schristos 
8*7bdf38e5Schristos static void
9*7bdf38e5Schristos verify_batch_basic(tsd_t *tsd, void **ptrs, size_t batch, size_t usize,
10*7bdf38e5Schristos     bool zero) {
11*7bdf38e5Schristos 	for (size_t i = 0; i < batch; ++i) {
12*7bdf38e5Schristos 		void *p = ptrs[i];
13*7bdf38e5Schristos 		expect_zu_eq(isalloc(tsd_tsdn(tsd), p), usize, "");
14*7bdf38e5Schristos 		if (zero) {
15*7bdf38e5Schristos 			for (size_t k = 0; k < usize; ++k) {
16*7bdf38e5Schristos 				expect_true(*((unsigned char *)p + k) == 0, "");
17*7bdf38e5Schristos 			}
18*7bdf38e5Schristos 		}
19*7bdf38e5Schristos 	}
20*7bdf38e5Schristos }
21*7bdf38e5Schristos 
22*7bdf38e5Schristos static void
23*7bdf38e5Schristos verify_batch_locality(tsd_t *tsd, void **ptrs, size_t batch, size_t usize,
24*7bdf38e5Schristos     arena_t *arena, unsigned nregs) {
25*7bdf38e5Schristos 	if (config_prof && opt_prof) {
26*7bdf38e5Schristos 		/*
27*7bdf38e5Schristos 		 * Checking batch locality when prof is on is feasible but
28*7bdf38e5Schristos 		 * complicated, while checking the non-prof case suffices for
29*7bdf38e5Schristos 		 * unit-test purpose.
30*7bdf38e5Schristos 		 */
31*7bdf38e5Schristos 		return;
32*7bdf38e5Schristos 	}
33*7bdf38e5Schristos 	for (size_t i = 0, j = 0; i < batch; ++i, ++j) {
34*7bdf38e5Schristos 		if (j == nregs) {
35*7bdf38e5Schristos 			j = 0;
36*7bdf38e5Schristos 		}
37*7bdf38e5Schristos 		if (j == 0 && batch - i < nregs) {
38*7bdf38e5Schristos 			break;
39*7bdf38e5Schristos 		}
40*7bdf38e5Schristos 		void *p = ptrs[i];
41*7bdf38e5Schristos 		expect_ptr_eq(iaalloc(tsd_tsdn(tsd), p), arena, "");
42*7bdf38e5Schristos 		if (j == 0) {
43*7bdf38e5Schristos 			expect_true(PAGE_ALIGNED(p), "");
44*7bdf38e5Schristos 			continue;
45*7bdf38e5Schristos 		}
46*7bdf38e5Schristos 		assert(i > 0);
47*7bdf38e5Schristos 		void *q = ptrs[i - 1];
48*7bdf38e5Schristos 		expect_true((uintptr_t)p > (uintptr_t)q
49*7bdf38e5Schristos 		    && (size_t)((uintptr_t)p - (uintptr_t)q) == usize, "");
50*7bdf38e5Schristos 	}
51*7bdf38e5Schristos }
52*7bdf38e5Schristos 
53*7bdf38e5Schristos static void
54*7bdf38e5Schristos release_batch(void **ptrs, size_t batch, size_t size) {
55*7bdf38e5Schristos 	for (size_t i = 0; i < batch; ++i) {
56*7bdf38e5Schristos 		sdallocx(ptrs[i], size, 0);
57*7bdf38e5Schristos 	}
58*7bdf38e5Schristos }
59*7bdf38e5Schristos 
60*7bdf38e5Schristos typedef struct batch_alloc_packet_s batch_alloc_packet_t;
61*7bdf38e5Schristos struct batch_alloc_packet_s {
62*7bdf38e5Schristos 	void **ptrs;
63*7bdf38e5Schristos 	size_t num;
64*7bdf38e5Schristos 	size_t size;
65*7bdf38e5Schristos 	int flags;
66*7bdf38e5Schristos };
67*7bdf38e5Schristos 
68*7bdf38e5Schristos static size_t
69*7bdf38e5Schristos batch_alloc_wrapper(void **ptrs, size_t num, size_t size, int flags) {
70*7bdf38e5Schristos 	batch_alloc_packet_t batch_alloc_packet = {ptrs, num, size, flags};
71*7bdf38e5Schristos 	size_t filled;
72*7bdf38e5Schristos 	size_t len = sizeof(size_t);
73*7bdf38e5Schristos 	assert_d_eq(mallctl("experimental.batch_alloc", &filled, &len,
74*7bdf38e5Schristos 	    &batch_alloc_packet, sizeof(batch_alloc_packet)), 0, "");
75*7bdf38e5Schristos 	return filled;
76*7bdf38e5Schristos }
77*7bdf38e5Schristos 
78*7bdf38e5Schristos static void
79*7bdf38e5Schristos test_wrapper(size_t size, size_t alignment, bool zero, unsigned arena_flag) {
80*7bdf38e5Schristos 	tsd_t *tsd = tsd_fetch();
81*7bdf38e5Schristos 	assert(tsd != NULL);
82*7bdf38e5Schristos 	const size_t usize =
83*7bdf38e5Schristos 	    (alignment != 0 ? sz_sa2u(size, alignment) : sz_s2u(size));
84*7bdf38e5Schristos 	const szind_t ind = sz_size2index(usize);
85*7bdf38e5Schristos 	const bin_info_t *bin_info = &bin_infos[ind];
86*7bdf38e5Schristos 	const unsigned nregs = bin_info->nregs;
87*7bdf38e5Schristos 	assert(nregs > 0);
88*7bdf38e5Schristos 	arena_t *arena;
89*7bdf38e5Schristos 	if (arena_flag != 0) {
90*7bdf38e5Schristos 		arena = arena_get(tsd_tsdn(tsd), MALLOCX_ARENA_GET(arena_flag),
91*7bdf38e5Schristos 		    false);
92*7bdf38e5Schristos 	} else {
93*7bdf38e5Schristos 		arena = arena_choose(tsd, NULL);
94*7bdf38e5Schristos 	}
95*7bdf38e5Schristos 	assert(arena != NULL);
96*7bdf38e5Schristos 	int flags = arena_flag;
97*7bdf38e5Schristos 	if (alignment != 0) {
98*7bdf38e5Schristos 		flags |= MALLOCX_ALIGN(alignment);
99*7bdf38e5Schristos 	}
100*7bdf38e5Schristos 	if (zero) {
101*7bdf38e5Schristos 		flags |= MALLOCX_ZERO;
102*7bdf38e5Schristos 	}
103*7bdf38e5Schristos 
104*7bdf38e5Schristos 	/*
105*7bdf38e5Schristos 	 * Allocate for the purpose of bootstrapping arena_tdata, so that the
106*7bdf38e5Schristos 	 * change in bin stats won't contaminate the stats to be verified below.
107*7bdf38e5Schristos 	 */
108*7bdf38e5Schristos 	void *p = mallocx(size, flags | MALLOCX_TCACHE_NONE);
109*7bdf38e5Schristos 
110*7bdf38e5Schristos 	for (size_t i = 0; i < 4; ++i) {
111*7bdf38e5Schristos 		size_t base = 0;
112*7bdf38e5Schristos 		if (i == 1) {
113*7bdf38e5Schristos 			base = nregs;
114*7bdf38e5Schristos 		} else if (i == 2) {
115*7bdf38e5Schristos 			base = nregs * 2;
116*7bdf38e5Schristos 		} else if (i == 3) {
117*7bdf38e5Schristos 			base = (1 << 16);
118*7bdf38e5Schristos 		}
119*7bdf38e5Schristos 		for (int j = -1; j <= 1; ++j) {
120*7bdf38e5Schristos 			if (base == 0 && j == -1) {
121*7bdf38e5Schristos 				continue;
122*7bdf38e5Schristos 			}
123*7bdf38e5Schristos 			size_t batch = base + (size_t)j;
124*7bdf38e5Schristos 			assert(batch < BATCH_MAX);
125*7bdf38e5Schristos 			size_t filled = batch_alloc_wrapper(global_ptrs, batch,
126*7bdf38e5Schristos 			    size, flags);
127*7bdf38e5Schristos 			assert_zu_eq(filled, batch, "");
128*7bdf38e5Schristos 			verify_batch_basic(tsd, global_ptrs, batch, usize,
129*7bdf38e5Schristos 			    zero);
130*7bdf38e5Schristos 			verify_batch_locality(tsd, global_ptrs, batch, usize,
131*7bdf38e5Schristos 			    arena, nregs);
132*7bdf38e5Schristos 			release_batch(global_ptrs, batch, usize);
133*7bdf38e5Schristos 		}
134*7bdf38e5Schristos 	}
135*7bdf38e5Schristos 
136*7bdf38e5Schristos 	free(p);
137*7bdf38e5Schristos }
138*7bdf38e5Schristos 
139*7bdf38e5Schristos TEST_BEGIN(test_batch_alloc) {
140*7bdf38e5Schristos 	test_wrapper(11, 0, false, 0);
141*7bdf38e5Schristos }
142*7bdf38e5Schristos TEST_END
143*7bdf38e5Schristos 
144*7bdf38e5Schristos TEST_BEGIN(test_batch_alloc_zero) {
145*7bdf38e5Schristos 	test_wrapper(11, 0, true, 0);
146*7bdf38e5Schristos }
147*7bdf38e5Schristos TEST_END
148*7bdf38e5Schristos 
149*7bdf38e5Schristos TEST_BEGIN(test_batch_alloc_aligned) {
150*7bdf38e5Schristos 	test_wrapper(7, 16, false, 0);
151*7bdf38e5Schristos }
152*7bdf38e5Schristos TEST_END
153*7bdf38e5Schristos 
154*7bdf38e5Schristos TEST_BEGIN(test_batch_alloc_manual_arena) {
155*7bdf38e5Schristos 	unsigned arena_ind;
156*7bdf38e5Schristos 	size_t len_unsigned = sizeof(unsigned);
157*7bdf38e5Schristos 	assert_d_eq(mallctl("arenas.create", &arena_ind, &len_unsigned, NULL,
158*7bdf38e5Schristos 	    0), 0, "");
159*7bdf38e5Schristos 	test_wrapper(11, 0, false, MALLOCX_ARENA(arena_ind));
160*7bdf38e5Schristos }
161*7bdf38e5Schristos TEST_END
162*7bdf38e5Schristos 
163*7bdf38e5Schristos TEST_BEGIN(test_batch_alloc_large) {
164*7bdf38e5Schristos 	size_t size = SC_LARGE_MINCLASS;
165*7bdf38e5Schristos 	for (size_t batch = 0; batch < 4; ++batch) {
166*7bdf38e5Schristos 		assert(batch < BATCH_MAX);
167*7bdf38e5Schristos 		size_t filled = batch_alloc(global_ptrs, batch, size, 0);
168*7bdf38e5Schristos 		assert_zu_eq(filled, batch, "");
169*7bdf38e5Schristos 		release_batch(global_ptrs, batch, size);
170*7bdf38e5Schristos 	}
171*7bdf38e5Schristos 	size = tcache_maxclass + 1;
172*7bdf38e5Schristos 	for (size_t batch = 0; batch < 4; ++batch) {
173*7bdf38e5Schristos 		assert(batch < BATCH_MAX);
174*7bdf38e5Schristos 		size_t filled = batch_alloc(global_ptrs, batch, size, 0);
175*7bdf38e5Schristos 		assert_zu_eq(filled, batch, "");
176*7bdf38e5Schristos 		release_batch(global_ptrs, batch, size);
177*7bdf38e5Schristos 	}
178*7bdf38e5Schristos }
179*7bdf38e5Schristos TEST_END
180*7bdf38e5Schristos 
181*7bdf38e5Schristos int
182*7bdf38e5Schristos main(void) {
183*7bdf38e5Schristos 	return test(
184*7bdf38e5Schristos 	    test_batch_alloc,
185*7bdf38e5Schristos 	    test_batch_alloc_zero,
186*7bdf38e5Schristos 	    test_batch_alloc_aligned,
187*7bdf38e5Schristos 	    test_batch_alloc_manual_arena,
188*7bdf38e5Schristos 	    test_batch_alloc_large);
189*7bdf38e5Schristos }
190