extent.c revision 1.1.1.3 1 #include "test/jemalloc_test.h"
2
3 #include "test/extent_hooks.h"
4
5 #include "jemalloc/internal/arena_types.h"
6
7 static void
8 test_extent_body(unsigned arena_ind) {
9 void *p;
10 size_t large0, large1, large2, sz;
11 size_t purge_mib[3];
12 size_t purge_miblen;
13 int flags;
14 bool xallocx_success_a, xallocx_success_b, xallocx_success_c;
15
16 flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE;
17
18 /* Get large size classes. */
19 sz = sizeof(size_t);
20 expect_d_eq(
21 mallctl("arenas.lextent.0.size", (void *)&large0, &sz, NULL, 0), 0,
22 "Unexpected arenas.lextent.0.size failure");
23 expect_d_eq(
24 mallctl("arenas.lextent.1.size", (void *)&large1, &sz, NULL, 0), 0,
25 "Unexpected arenas.lextent.1.size failure");
26 expect_d_eq(
27 mallctl("arenas.lextent.2.size", (void *)&large2, &sz, NULL, 0), 0,
28 "Unexpected arenas.lextent.2.size failure");
29
30 /* Test dalloc/decommit/purge cascade. */
31 purge_miblen = sizeof(purge_mib) / sizeof(size_t);
32 expect_d_eq(mallctlnametomib("arena.0.purge", purge_mib, &purge_miblen),
33 0, "Unexpected mallctlnametomib() failure");
34 purge_mib[1] = (size_t)arena_ind;
35 called_alloc = false;
36 try_alloc = true;
37 try_dalloc = false;
38 try_decommit = false;
39 p = mallocx(large0 * 2, flags);
40 expect_ptr_not_null(p, "Unexpected mallocx() error");
41 expect_true(called_alloc, "Expected alloc call");
42 called_dalloc = false;
43 called_decommit = false;
44 did_purge_lazy = false;
45 did_purge_forced = false;
46 called_split = false;
47 xallocx_success_a = (xallocx(p, large0, 0, flags) == large0);
48 expect_d_eq(mallctlbymib(purge_mib, purge_miblen, NULL, NULL, NULL, 0),
49 0, "Unexpected arena.%u.purge error", arena_ind);
50 if (xallocx_success_a) {
51 expect_true(called_dalloc, "Expected dalloc call");
52 expect_true(called_decommit, "Expected decommit call");
53 expect_true(
54 did_purge_lazy || did_purge_forced, "Expected purge");
55 expect_true(called_split, "Expected split call");
56 }
57 dallocx(p, flags);
58 try_dalloc = true;
59
60 /* Test decommit/commit and observe split/merge. */
61 try_dalloc = false;
62 try_decommit = true;
63 p = mallocx(large0 * 2, flags);
64 expect_ptr_not_null(p, "Unexpected mallocx() error");
65 did_decommit = false;
66 did_commit = false;
67 called_split = false;
68 did_split = false;
69 did_merge = false;
70 xallocx_success_b = (xallocx(p, large0, 0, flags) == large0);
71 expect_d_eq(mallctlbymib(purge_mib, purge_miblen, NULL, NULL, NULL, 0),
72 0, "Unexpected arena.%u.purge error", arena_ind);
73 if (xallocx_success_b) {
74 expect_true(did_split, "Expected split");
75 }
76 xallocx_success_c = (xallocx(p, large0 * 2, 0, flags) == large0 * 2);
77 if (did_split) {
78 expect_b_eq(
79 did_decommit, did_commit, "Expected decommit/commit match");
80 }
81 if (xallocx_success_b && xallocx_success_c) {
82 expect_true(did_merge, "Expected merge");
83 }
84 dallocx(p, flags);
85 try_dalloc = true;
86 try_decommit = false;
87
88 /* Make sure non-large allocation succeeds. */
89 p = mallocx(42, flags);
90 expect_ptr_not_null(p, "Unexpected mallocx() error");
91 dallocx(p, flags);
92 }
93
94 static void
95 test_manual_hook_auto_arena(void) {
96 unsigned narenas;
97 size_t old_size, new_size, sz;
98 size_t hooks_mib[3];
99 size_t hooks_miblen;
100 extent_hooks_t *new_hooks, *old_hooks;
101
102 extent_hooks_prep();
103
104 sz = sizeof(unsigned);
105 /* Get number of auto arenas. */
106 expect_d_eq(mallctl("opt.narenas", (void *)&narenas, &sz, NULL, 0), 0,
107 "Unexpected mallctl() failure");
108 if (narenas == 1) {
109 return;
110 }
111
112 /* Install custom extent hooks on arena 1 (might not be initialized). */
113 hooks_miblen = sizeof(hooks_mib) / sizeof(size_t);
114 expect_d_eq(
115 mallctlnametomib("arena.0.extent_hooks", hooks_mib, &hooks_miblen),
116 0, "Unexpected mallctlnametomib() failure");
117 hooks_mib[1] = 1;
118 old_size = sizeof(extent_hooks_t *);
119 new_hooks = &hooks;
120 new_size = sizeof(extent_hooks_t *);
121 expect_d_eq(mallctlbymib(hooks_mib, hooks_miblen, (void *)&old_hooks,
122 &old_size, (void *)&new_hooks, new_size),
123 0, "Unexpected extent_hooks error");
124 static bool auto_arena_created = false;
125 if (old_hooks != &hooks) {
126 expect_b_eq(auto_arena_created, false,
127 "Expected auto arena 1 created only once.");
128 auto_arena_created = true;
129 }
130 }
131
132 static void
133 test_manual_hook_body(void) {
134 unsigned arena_ind;
135 size_t old_size, new_size, sz;
136 size_t hooks_mib[3];
137 size_t hooks_miblen;
138 extent_hooks_t *new_hooks, *old_hooks;
139
140 extent_hooks_prep();
141
142 sz = sizeof(unsigned);
143 expect_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0),
144 0, "Unexpected mallctl() failure");
145
146 /* Install custom extent hooks. */
147 hooks_miblen = sizeof(hooks_mib) / sizeof(size_t);
148 expect_d_eq(
149 mallctlnametomib("arena.0.extent_hooks", hooks_mib, &hooks_miblen),
150 0, "Unexpected mallctlnametomib() failure");
151 hooks_mib[1] = (size_t)arena_ind;
152 old_size = sizeof(extent_hooks_t *);
153 new_hooks = &hooks;
154 new_size = sizeof(extent_hooks_t *);
155 expect_d_eq(mallctlbymib(hooks_mib, hooks_miblen, (void *)&old_hooks,
156 &old_size, (void *)&new_hooks, new_size),
157 0, "Unexpected extent_hooks error");
158 expect_ptr_ne(old_hooks->alloc, extent_alloc_hook,
159 "Unexpected extent_hooks error");
160 expect_ptr_ne(old_hooks->dalloc, extent_dalloc_hook,
161 "Unexpected extent_hooks error");
162 expect_ptr_ne(old_hooks->commit, extent_commit_hook,
163 "Unexpected extent_hooks error");
164 expect_ptr_ne(old_hooks->decommit, extent_decommit_hook,
165 "Unexpected extent_hooks error");
166 expect_ptr_ne(old_hooks->purge_lazy, extent_purge_lazy_hook,
167 "Unexpected extent_hooks error");
168 expect_ptr_ne(old_hooks->purge_forced, extent_purge_forced_hook,
169 "Unexpected extent_hooks error");
170 expect_ptr_ne(old_hooks->split, extent_split_hook,
171 "Unexpected extent_hooks error");
172 expect_ptr_ne(old_hooks->merge, extent_merge_hook,
173 "Unexpected extent_hooks error");
174
175 if (!is_background_thread_enabled()) {
176 test_extent_body(arena_ind);
177 }
178
179 /* Restore extent hooks. */
180 expect_d_eq(mallctlbymib(hooks_mib, hooks_miblen, NULL, NULL,
181 (void *)&old_hooks, new_size),
182 0, "Unexpected extent_hooks error");
183 expect_d_eq(mallctlbymib(hooks_mib, hooks_miblen, (void *)&old_hooks,
184 &old_size, NULL, 0),
185 0, "Unexpected extent_hooks error");
186 expect_ptr_eq(
187 old_hooks, default_hooks, "Unexpected extent_hooks error");
188 expect_ptr_eq(old_hooks->alloc, default_hooks->alloc,
189 "Unexpected extent_hooks error");
190 expect_ptr_eq(old_hooks->dalloc, default_hooks->dalloc,
191 "Unexpected extent_hooks error");
192 expect_ptr_eq(old_hooks->commit, default_hooks->commit,
193 "Unexpected extent_hooks error");
194 expect_ptr_eq(old_hooks->decommit, default_hooks->decommit,
195 "Unexpected extent_hooks error");
196 expect_ptr_eq(old_hooks->purge_lazy, default_hooks->purge_lazy,
197 "Unexpected extent_hooks error");
198 expect_ptr_eq(old_hooks->purge_forced, default_hooks->purge_forced,
199 "Unexpected extent_hooks error");
200 expect_ptr_eq(old_hooks->split, default_hooks->split,
201 "Unexpected extent_hooks error");
202 expect_ptr_eq(old_hooks->merge, default_hooks->merge,
203 "Unexpected extent_hooks error");
204 }
205
206 TEST_BEGIN(test_extent_manual_hook) {
207 test_manual_hook_auto_arena();
208 test_manual_hook_body();
209
210 /* Test failure paths. */
211 try_split = false;
212 test_manual_hook_body();
213 try_merge = false;
214 test_manual_hook_body();
215 try_purge_lazy = false;
216 try_purge_forced = false;
217 test_manual_hook_body();
218
219 try_split = try_merge = try_purge_lazy = try_purge_forced = true;
220 }
221 TEST_END
222
223 TEST_BEGIN(test_extent_auto_hook) {
224 unsigned arena_ind;
225 size_t new_size, sz;
226 extent_hooks_t *new_hooks;
227
228 extent_hooks_prep();
229
230 sz = sizeof(unsigned);
231 new_hooks = &hooks;
232 new_size = sizeof(extent_hooks_t *);
233 expect_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz,
234 (void *)&new_hooks, new_size),
235 0, "Unexpected mallctl() failure");
236
237 test_skip_if(is_background_thread_enabled());
238 test_extent_body(arena_ind);
239 }
240 TEST_END
241
242 static void
243 test_arenas_create_ext_base(
244 arena_config_t config, bool expect_hook_data, bool expect_hook_metadata) {
245 unsigned arena, arena1;
246 void *ptr;
247 size_t sz = sizeof(unsigned);
248
249 extent_hooks_prep();
250
251 called_alloc = false;
252 expect_d_eq(mallctl("experimental.arenas_create_ext", (void *)&arena,
253 &sz, &config, sizeof(arena_config_t)),
254 0, "Unexpected mallctl() failure");
255 expect_b_eq(called_alloc, expect_hook_metadata,
256 "expected hook metadata alloc mismatch");
257
258 called_alloc = false;
259 ptr = mallocx(42, MALLOCX_ARENA(arena) | MALLOCX_TCACHE_NONE);
260 expect_b_eq(called_alloc, expect_hook_data,
261 "expected hook data alloc mismatch");
262
263 expect_ptr_not_null(ptr, "Unexpected mallocx() failure");
264 expect_d_eq(mallctl("arenas.lookup", &arena1, &sz, &ptr, sizeof(ptr)),
265 0, "Unexpected mallctl() failure");
266 expect_u_eq(arena, arena1, "Unexpected arena index");
267 dallocx(ptr, 0);
268 }
269
270 TEST_BEGIN(test_arenas_create_ext_with_ehooks_no_metadata) {
271 arena_config_t config;
272 config.extent_hooks = &hooks;
273 config.metadata_use_hooks = false;
274
275 test_arenas_create_ext_base(config, true, false);
276 }
277 TEST_END
278
279 TEST_BEGIN(test_arenas_create_ext_with_ehooks_with_metadata) {
280 arena_config_t config;
281 config.extent_hooks = &hooks;
282 config.metadata_use_hooks = true;
283
284 test_arenas_create_ext_base(config, true, true);
285 }
286 TEST_END
287
288 int
289 main(void) {
290 return test(test_extent_manual_hook, test_extent_auto_hook,
291 test_arenas_create_ext_with_ehooks_no_metadata,
292 test_arenas_create_ext_with_ehooks_with_metadata);
293 }
294