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