1 #include "test/jemalloc_test.h"
2
3 #include "jemalloc/internal/util.h"
4
TEST_BEGIN(test_mallctl_errors)5 TEST_BEGIN(test_mallctl_errors) {
6 uint64_t epoch;
7 size_t sz;
8
9 assert_d_eq(mallctl("no_such_name", NULL, NULL, NULL, 0), ENOENT,
10 "mallctl() should return ENOENT for non-existent names");
11
12 assert_d_eq(mallctl("version", NULL, NULL, "0.0.0", strlen("0.0.0")),
13 EPERM, "mallctl() should return EPERM on attempt to write "
14 "read-only value");
15
16 assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch,
17 sizeof(epoch)-1), EINVAL,
18 "mallctl() should return EINVAL for input size mismatch");
19 assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch,
20 sizeof(epoch)+1), EINVAL,
21 "mallctl() should return EINVAL for input size mismatch");
22
23 sz = sizeof(epoch)-1;
24 assert_d_eq(mallctl("epoch", (void *)&epoch, &sz, NULL, 0), EINVAL,
25 "mallctl() should return EINVAL for output size mismatch");
26 sz = sizeof(epoch)+1;
27 assert_d_eq(mallctl("epoch", (void *)&epoch, &sz, NULL, 0), EINVAL,
28 "mallctl() should return EINVAL for output size mismatch");
29 }
30 TEST_END
31
TEST_BEGIN(test_mallctlnametomib_errors)32 TEST_BEGIN(test_mallctlnametomib_errors) {
33 size_t mib[1];
34 size_t miblen;
35
36 miblen = sizeof(mib)/sizeof(size_t);
37 assert_d_eq(mallctlnametomib("no_such_name", mib, &miblen), ENOENT,
38 "mallctlnametomib() should return ENOENT for non-existent names");
39 }
40 TEST_END
41
TEST_BEGIN(test_mallctlbymib_errors)42 TEST_BEGIN(test_mallctlbymib_errors) {
43 uint64_t epoch;
44 size_t sz;
45 size_t mib[1];
46 size_t miblen;
47
48 miblen = sizeof(mib)/sizeof(size_t);
49 assert_d_eq(mallctlnametomib("version", mib, &miblen), 0,
50 "Unexpected mallctlnametomib() failure");
51
52 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, "0.0.0",
53 strlen("0.0.0")), EPERM, "mallctl() should return EPERM on "
54 "attempt to write read-only value");
55
56 miblen = sizeof(mib)/sizeof(size_t);
57 assert_d_eq(mallctlnametomib("epoch", mib, &miblen), 0,
58 "Unexpected mallctlnametomib() failure");
59
60 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&epoch,
61 sizeof(epoch)-1), EINVAL,
62 "mallctlbymib() should return EINVAL for input size mismatch");
63 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, (void *)&epoch,
64 sizeof(epoch)+1), EINVAL,
65 "mallctlbymib() should return EINVAL for input size mismatch");
66
67 sz = sizeof(epoch)-1;
68 assert_d_eq(mallctlbymib(mib, miblen, (void *)&epoch, &sz, NULL, 0),
69 EINVAL,
70 "mallctlbymib() should return EINVAL for output size mismatch");
71 sz = sizeof(epoch)+1;
72 assert_d_eq(mallctlbymib(mib, miblen, (void *)&epoch, &sz, NULL, 0),
73 EINVAL,
74 "mallctlbymib() should return EINVAL for output size mismatch");
75 }
76 TEST_END
77
TEST_BEGIN(test_mallctl_read_write)78 TEST_BEGIN(test_mallctl_read_write) {
79 uint64_t old_epoch, new_epoch;
80 size_t sz = sizeof(old_epoch);
81
82 /* Blind. */
83 assert_d_eq(mallctl("epoch", NULL, NULL, NULL, 0), 0,
84 "Unexpected mallctl() failure");
85 assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
86
87 /* Read. */
88 assert_d_eq(mallctl("epoch", (void *)&old_epoch, &sz, NULL, 0), 0,
89 "Unexpected mallctl() failure");
90 assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
91
92 /* Write. */
93 assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&new_epoch,
94 sizeof(new_epoch)), 0, "Unexpected mallctl() failure");
95 assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
96
97 /* Read+write. */
98 assert_d_eq(mallctl("epoch", (void *)&old_epoch, &sz,
99 (void *)&new_epoch, sizeof(new_epoch)), 0,
100 "Unexpected mallctl() failure");
101 assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
102 }
103 TEST_END
104
TEST_BEGIN(test_mallctlnametomib_short_mib)105 TEST_BEGIN(test_mallctlnametomib_short_mib) {
106 size_t mib[4];
107 size_t miblen;
108
109 miblen = 3;
110 mib[3] = 42;
111 assert_d_eq(mallctlnametomib("arenas.bin.0.nregs", mib, &miblen), 0,
112 "Unexpected mallctlnametomib() failure");
113 assert_zu_eq(miblen, 3, "Unexpected mib output length");
114 assert_zu_eq(mib[3], 42,
115 "mallctlnametomib() wrote past the end of the input mib");
116 }
117 TEST_END
118
TEST_BEGIN(test_mallctl_config)119 TEST_BEGIN(test_mallctl_config) {
120 #define TEST_MALLCTL_CONFIG(config, t) do { \
121 t oldval; \
122 size_t sz = sizeof(oldval); \
123 assert_d_eq(mallctl("config."#config, (void *)&oldval, &sz, \
124 NULL, 0), 0, "Unexpected mallctl() failure"); \
125 assert_b_eq(oldval, config_##config, "Incorrect config value"); \
126 assert_zu_eq(sz, sizeof(oldval), "Unexpected output size"); \
127 } while (0)
128
129 TEST_MALLCTL_CONFIG(cache_oblivious, bool);
130 TEST_MALLCTL_CONFIG(debug, bool);
131 TEST_MALLCTL_CONFIG(fill, bool);
132 TEST_MALLCTL_CONFIG(lazy_lock, bool);
133 TEST_MALLCTL_CONFIG(malloc_conf, const char *);
134 TEST_MALLCTL_CONFIG(prof, bool);
135 TEST_MALLCTL_CONFIG(prof_libgcc, bool);
136 TEST_MALLCTL_CONFIG(prof_libunwind, bool);
137 TEST_MALLCTL_CONFIG(stats, bool);
138 TEST_MALLCTL_CONFIG(utrace, bool);
139 TEST_MALLCTL_CONFIG(xmalloc, bool);
140
141 #undef TEST_MALLCTL_CONFIG
142 }
143 TEST_END
144
TEST_BEGIN(test_mallctl_opt)145 TEST_BEGIN(test_mallctl_opt) {
146 bool config_always = true;
147
148 #define TEST_MALLCTL_OPT(t, opt, config) do { \
149 t oldval; \
150 size_t sz = sizeof(oldval); \
151 int expected = config_##config ? 0 : ENOENT; \
152 int result = mallctl("opt."#opt, (void *)&oldval, &sz, NULL, \
153 0); \
154 assert_d_eq(result, expected, \
155 "Unexpected mallctl() result for opt."#opt); \
156 assert_zu_eq(sz, sizeof(oldval), "Unexpected output size"); \
157 } while (0)
158
159 TEST_MALLCTL_OPT(bool, abort, always);
160 TEST_MALLCTL_OPT(bool, abort_conf, always);
161 TEST_MALLCTL_OPT(const char *, metadata_thp, always);
162 TEST_MALLCTL_OPT(bool, retain, always);
163 TEST_MALLCTL_OPT(const char *, dss, always);
164 TEST_MALLCTL_OPT(unsigned, narenas, always);
165 TEST_MALLCTL_OPT(const char *, percpu_arena, always);
166 TEST_MALLCTL_OPT(bool, background_thread, always);
167 TEST_MALLCTL_OPT(ssize_t, dirty_decay_ms, always);
168 TEST_MALLCTL_OPT(ssize_t, muzzy_decay_ms, always);
169 TEST_MALLCTL_OPT(bool, stats_print, always);
170 TEST_MALLCTL_OPT(const char *, junk, fill);
171 TEST_MALLCTL_OPT(bool, zero, fill);
172 TEST_MALLCTL_OPT(bool, utrace, utrace);
173 TEST_MALLCTL_OPT(bool, xmalloc, xmalloc);
174 TEST_MALLCTL_OPT(bool, tcache, always);
175 TEST_MALLCTL_OPT(size_t, lg_extent_max_active_fit, always);
176 TEST_MALLCTL_OPT(size_t, lg_tcache_max, always);
177 TEST_MALLCTL_OPT(const char *, thp, always);
178 TEST_MALLCTL_OPT(bool, prof, prof);
179 TEST_MALLCTL_OPT(const char *, prof_prefix, prof);
180 TEST_MALLCTL_OPT(bool, prof_active, prof);
181 TEST_MALLCTL_OPT(ssize_t, lg_prof_sample, prof);
182 TEST_MALLCTL_OPT(bool, prof_accum, prof);
183 TEST_MALLCTL_OPT(ssize_t, lg_prof_interval, prof);
184 TEST_MALLCTL_OPT(bool, prof_gdump, prof);
185 TEST_MALLCTL_OPT(bool, prof_final, prof);
186 TEST_MALLCTL_OPT(bool, prof_leak, prof);
187
188 #undef TEST_MALLCTL_OPT
189 }
190 TEST_END
191
TEST_BEGIN(test_manpage_example)192 TEST_BEGIN(test_manpage_example) {
193 unsigned nbins, i;
194 size_t mib[4];
195 size_t len, miblen;
196
197 len = sizeof(nbins);
198 assert_d_eq(mallctl("arenas.nbins", (void *)&nbins, &len, NULL, 0), 0,
199 "Unexpected mallctl() failure");
200
201 miblen = 4;
202 assert_d_eq(mallctlnametomib("arenas.bin.0.size", mib, &miblen), 0,
203 "Unexpected mallctlnametomib() failure");
204 for (i = 0; i < nbins; i++) {
205 size_t bin_size;
206
207 mib[2] = i;
208 len = sizeof(bin_size);
209 assert_d_eq(mallctlbymib(mib, miblen, (void *)&bin_size, &len,
210 NULL, 0), 0, "Unexpected mallctlbymib() failure");
211 /* Do something with bin_size... */
212 }
213 }
214 TEST_END
215
TEST_BEGIN(test_tcache_none)216 TEST_BEGIN(test_tcache_none) {
217 test_skip_if(!opt_tcache);
218
219 /* Allocate p and q. */
220 void *p0 = mallocx(42, 0);
221 assert_ptr_not_null(p0, "Unexpected mallocx() failure");
222 void *q = mallocx(42, 0);
223 assert_ptr_not_null(q, "Unexpected mallocx() failure");
224
225 /* Deallocate p and q, but bypass the tcache for q. */
226 dallocx(p0, 0);
227 dallocx(q, MALLOCX_TCACHE_NONE);
228
229 /* Make sure that tcache-based allocation returns p, not q. */
230 void *p1 = mallocx(42, 0);
231 assert_ptr_not_null(p1, "Unexpected mallocx() failure");
232 assert_ptr_eq(p0, p1, "Expected tcache to allocate cached region");
233
234 /* Clean up. */
235 dallocx(p1, MALLOCX_TCACHE_NONE);
236 }
237 TEST_END
238
TEST_BEGIN(test_tcache)239 TEST_BEGIN(test_tcache) {
240 #define NTCACHES 10
241 unsigned tis[NTCACHES];
242 void *ps[NTCACHES];
243 void *qs[NTCACHES];
244 unsigned i;
245 size_t sz, psz, qsz;
246
247 psz = 42;
248 qsz = nallocx(psz, 0) + 1;
249
250 /* Create tcaches. */
251 for (i = 0; i < NTCACHES; i++) {
252 sz = sizeof(unsigned);
253 assert_d_eq(mallctl("tcache.create", (void *)&tis[i], &sz, NULL,
254 0), 0, "Unexpected mallctl() failure, i=%u", i);
255 }
256
257 /* Exercise tcache ID recycling. */
258 for (i = 0; i < NTCACHES; i++) {
259 assert_d_eq(mallctl("tcache.destroy", NULL, NULL,
260 (void *)&tis[i], sizeof(unsigned)), 0,
261 "Unexpected mallctl() failure, i=%u", i);
262 }
263 for (i = 0; i < NTCACHES; i++) {
264 sz = sizeof(unsigned);
265 assert_d_eq(mallctl("tcache.create", (void *)&tis[i], &sz, NULL,
266 0), 0, "Unexpected mallctl() failure, i=%u", i);
267 }
268
269 /* Flush empty tcaches. */
270 for (i = 0; i < NTCACHES; i++) {
271 assert_d_eq(mallctl("tcache.flush", NULL, NULL, (void *)&tis[i],
272 sizeof(unsigned)), 0, "Unexpected mallctl() failure, i=%u",
273 i);
274 }
275
276 /* Cache some allocations. */
277 for (i = 0; i < NTCACHES; i++) {
278 ps[i] = mallocx(psz, MALLOCX_TCACHE(tis[i]));
279 assert_ptr_not_null(ps[i], "Unexpected mallocx() failure, i=%u",
280 i);
281 dallocx(ps[i], MALLOCX_TCACHE(tis[i]));
282
283 qs[i] = mallocx(qsz, MALLOCX_TCACHE(tis[i]));
284 assert_ptr_not_null(qs[i], "Unexpected mallocx() failure, i=%u",
285 i);
286 dallocx(qs[i], MALLOCX_TCACHE(tis[i]));
287 }
288
289 /* Verify that tcaches allocate cached regions. */
290 for (i = 0; i < NTCACHES; i++) {
291 void *p0 = ps[i];
292 ps[i] = mallocx(psz, MALLOCX_TCACHE(tis[i]));
293 assert_ptr_not_null(ps[i], "Unexpected mallocx() failure, i=%u",
294 i);
295 assert_ptr_eq(ps[i], p0,
296 "Expected mallocx() to allocate cached region, i=%u", i);
297 }
298
299 /* Verify that reallocation uses cached regions. */
300 for (i = 0; i < NTCACHES; i++) {
301 void *q0 = qs[i];
302 qs[i] = rallocx(ps[i], qsz, MALLOCX_TCACHE(tis[i]));
303 assert_ptr_not_null(qs[i], "Unexpected rallocx() failure, i=%u",
304 i);
305 assert_ptr_eq(qs[i], q0,
306 "Expected rallocx() to allocate cached region, i=%u", i);
307 /* Avoid undefined behavior in case of test failure. */
308 if (qs[i] == NULL) {
309 qs[i] = ps[i];
310 }
311 }
312 for (i = 0; i < NTCACHES; i++) {
313 dallocx(qs[i], MALLOCX_TCACHE(tis[i]));
314 }
315
316 /* Flush some non-empty tcaches. */
317 for (i = 0; i < NTCACHES/2; i++) {
318 assert_d_eq(mallctl("tcache.flush", NULL, NULL, (void *)&tis[i],
319 sizeof(unsigned)), 0, "Unexpected mallctl() failure, i=%u",
320 i);
321 }
322
323 /* Destroy tcaches. */
324 for (i = 0; i < NTCACHES; i++) {
325 assert_d_eq(mallctl("tcache.destroy", NULL, NULL,
326 (void *)&tis[i], sizeof(unsigned)), 0,
327 "Unexpected mallctl() failure, i=%u", i);
328 }
329 }
330 TEST_END
331
TEST_BEGIN(test_thread_arena)332 TEST_BEGIN(test_thread_arena) {
333 unsigned old_arena_ind, new_arena_ind, narenas;
334
335 const char *opa;
336 size_t sz = sizeof(opa);
337 assert_d_eq(mallctl("opt.percpu_arena", (void *)&opa, &sz, NULL, 0), 0,
338 "Unexpected mallctl() failure");
339
340 sz = sizeof(unsigned);
341 assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0),
342 0, "Unexpected mallctl() failure");
343 assert_u_eq(narenas, opt_narenas, "Number of arenas incorrect");
344
345 if (strcmp(opa, "disabled") == 0) {
346 new_arena_ind = narenas - 1;
347 assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz,
348 (void *)&new_arena_ind, sizeof(unsigned)), 0,
349 "Unexpected mallctl() failure");
350 new_arena_ind = 0;
351 assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz,
352 (void *)&new_arena_ind, sizeof(unsigned)), 0,
353 "Unexpected mallctl() failure");
354 } else {
355 assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz,
356 NULL, 0), 0, "Unexpected mallctl() failure");
357 new_arena_ind = percpu_arena_ind_limit(opt_percpu_arena) - 1;
358 if (old_arena_ind != new_arena_ind) {
359 assert_d_eq(mallctl("thread.arena",
360 (void *)&old_arena_ind, &sz, (void *)&new_arena_ind,
361 sizeof(unsigned)), EPERM, "thread.arena ctl "
362 "should not be allowed with percpu arena");
363 }
364 }
365 }
366 TEST_END
367
TEST_BEGIN(test_arena_i_initialized)368 TEST_BEGIN(test_arena_i_initialized) {
369 unsigned narenas, i;
370 size_t sz;
371 size_t mib[3];
372 size_t miblen = sizeof(mib) / sizeof(size_t);
373 bool initialized;
374
375 sz = sizeof(narenas);
376 assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0),
377 0, "Unexpected mallctl() failure");
378
379 assert_d_eq(mallctlnametomib("arena.0.initialized", mib, &miblen), 0,
380 "Unexpected mallctlnametomib() failure");
381 for (i = 0; i < narenas; i++) {
382 mib[1] = i;
383 sz = sizeof(initialized);
384 assert_d_eq(mallctlbymib(mib, miblen, &initialized, &sz, NULL,
385 0), 0, "Unexpected mallctl() failure");
386 }
387
388 mib[1] = MALLCTL_ARENAS_ALL;
389 sz = sizeof(initialized);
390 assert_d_eq(mallctlbymib(mib, miblen, &initialized, &sz, NULL, 0), 0,
391 "Unexpected mallctl() failure");
392 assert_true(initialized,
393 "Merged arena statistics should always be initialized");
394
395 /* Equivalent to the above but using mallctl() directly. */
396 sz = sizeof(initialized);
397 assert_d_eq(mallctl(
398 "arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".initialized",
399 (void *)&initialized, &sz, NULL, 0), 0,
400 "Unexpected mallctl() failure");
401 assert_true(initialized,
402 "Merged arena statistics should always be initialized");
403 }
404 TEST_END
405
TEST_BEGIN(test_arena_i_dirty_decay_ms)406 TEST_BEGIN(test_arena_i_dirty_decay_ms) {
407 ssize_t dirty_decay_ms, orig_dirty_decay_ms, prev_dirty_decay_ms;
408 size_t sz = sizeof(ssize_t);
409
410 assert_d_eq(mallctl("arena.0.dirty_decay_ms",
411 (void *)&orig_dirty_decay_ms, &sz, NULL, 0), 0,
412 "Unexpected mallctl() failure");
413
414 dirty_decay_ms = -2;
415 assert_d_eq(mallctl("arena.0.dirty_decay_ms", NULL, NULL,
416 (void *)&dirty_decay_ms, sizeof(ssize_t)), EFAULT,
417 "Unexpected mallctl() success");
418
419 dirty_decay_ms = 0x7fffffff;
420 assert_d_eq(mallctl("arena.0.dirty_decay_ms", NULL, NULL,
421 (void *)&dirty_decay_ms, sizeof(ssize_t)), 0,
422 "Unexpected mallctl() failure");
423
424 for (prev_dirty_decay_ms = dirty_decay_ms, dirty_decay_ms = -1;
425 dirty_decay_ms < 20; prev_dirty_decay_ms = dirty_decay_ms,
426 dirty_decay_ms++) {
427 ssize_t old_dirty_decay_ms;
428
429 assert_d_eq(mallctl("arena.0.dirty_decay_ms",
430 (void *)&old_dirty_decay_ms, &sz, (void *)&dirty_decay_ms,
431 sizeof(ssize_t)), 0, "Unexpected mallctl() failure");
432 assert_zd_eq(old_dirty_decay_ms, prev_dirty_decay_ms,
433 "Unexpected old arena.0.dirty_decay_ms");
434 }
435 }
436 TEST_END
437
TEST_BEGIN(test_arena_i_muzzy_decay_ms)438 TEST_BEGIN(test_arena_i_muzzy_decay_ms) {
439 ssize_t muzzy_decay_ms, orig_muzzy_decay_ms, prev_muzzy_decay_ms;
440 size_t sz = sizeof(ssize_t);
441
442 assert_d_eq(mallctl("arena.0.muzzy_decay_ms",
443 (void *)&orig_muzzy_decay_ms, &sz, NULL, 0), 0,
444 "Unexpected mallctl() failure");
445
446 muzzy_decay_ms = -2;
447 assert_d_eq(mallctl("arena.0.muzzy_decay_ms", NULL, NULL,
448 (void *)&muzzy_decay_ms, sizeof(ssize_t)), EFAULT,
449 "Unexpected mallctl() success");
450
451 muzzy_decay_ms = 0x7fffffff;
452 assert_d_eq(mallctl("arena.0.muzzy_decay_ms", NULL, NULL,
453 (void *)&muzzy_decay_ms, sizeof(ssize_t)), 0,
454 "Unexpected mallctl() failure");
455
456 for (prev_muzzy_decay_ms = muzzy_decay_ms, muzzy_decay_ms = -1;
457 muzzy_decay_ms < 20; prev_muzzy_decay_ms = muzzy_decay_ms,
458 muzzy_decay_ms++) {
459 ssize_t old_muzzy_decay_ms;
460
461 assert_d_eq(mallctl("arena.0.muzzy_decay_ms",
462 (void *)&old_muzzy_decay_ms, &sz, (void *)&muzzy_decay_ms,
463 sizeof(ssize_t)), 0, "Unexpected mallctl() failure");
464 assert_zd_eq(old_muzzy_decay_ms, prev_muzzy_decay_ms,
465 "Unexpected old arena.0.muzzy_decay_ms");
466 }
467 }
468 TEST_END
469
TEST_BEGIN(test_arena_i_purge)470 TEST_BEGIN(test_arena_i_purge) {
471 unsigned narenas;
472 size_t sz = sizeof(unsigned);
473 size_t mib[3];
474 size_t miblen = 3;
475
476 assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
477 "Unexpected mallctl() failure");
478
479 assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0),
480 0, "Unexpected mallctl() failure");
481 assert_d_eq(mallctlnametomib("arena.0.purge", mib, &miblen), 0,
482 "Unexpected mallctlnametomib() failure");
483 mib[1] = narenas;
484 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
485 "Unexpected mallctlbymib() failure");
486
487 mib[1] = MALLCTL_ARENAS_ALL;
488 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
489 "Unexpected mallctlbymib() failure");
490 }
491 TEST_END
492
TEST_BEGIN(test_arena_i_decay)493 TEST_BEGIN(test_arena_i_decay) {
494 unsigned narenas;
495 size_t sz = sizeof(unsigned);
496 size_t mib[3];
497 size_t miblen = 3;
498
499 assert_d_eq(mallctl("arena.0.decay", NULL, NULL, NULL, 0), 0,
500 "Unexpected mallctl() failure");
501
502 assert_d_eq(mallctl("arenas.narenas", (void *)&narenas, &sz, NULL, 0),
503 0, "Unexpected mallctl() failure");
504 assert_d_eq(mallctlnametomib("arena.0.decay", mib, &miblen), 0,
505 "Unexpected mallctlnametomib() failure");
506 mib[1] = narenas;
507 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
508 "Unexpected mallctlbymib() failure");
509
510 mib[1] = MALLCTL_ARENAS_ALL;
511 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
512 "Unexpected mallctlbymib() failure");
513 }
514 TEST_END
515
TEST_BEGIN(test_arena_i_dss)516 TEST_BEGIN(test_arena_i_dss) {
517 const char *dss_prec_old, *dss_prec_new;
518 size_t sz = sizeof(dss_prec_old);
519 size_t mib[3];
520 size_t miblen;
521
522 miblen = sizeof(mib)/sizeof(size_t);
523 assert_d_eq(mallctlnametomib("arena.0.dss", mib, &miblen), 0,
524 "Unexpected mallctlnametomib() error");
525
526 dss_prec_new = "disabled";
527 assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz,
528 (void *)&dss_prec_new, sizeof(dss_prec_new)), 0,
529 "Unexpected mallctl() failure");
530 assert_str_ne(dss_prec_old, "primary",
531 "Unexpected default for dss precedence");
532
533 assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_new, &sz,
534 (void *)&dss_prec_old, sizeof(dss_prec_old)), 0,
535 "Unexpected mallctl() failure");
536
537 assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz, NULL,
538 0), 0, "Unexpected mallctl() failure");
539 assert_str_ne(dss_prec_old, "primary",
540 "Unexpected value for dss precedence");
541
542 mib[1] = narenas_total_get();
543 dss_prec_new = "disabled";
544 assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz,
545 (void *)&dss_prec_new, sizeof(dss_prec_new)), 0,
546 "Unexpected mallctl() failure");
547 assert_str_ne(dss_prec_old, "primary",
548 "Unexpected default for dss precedence");
549
550 assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_new, &sz,
551 (void *)&dss_prec_old, sizeof(dss_prec_new)), 0,
552 "Unexpected mallctl() failure");
553
554 assert_d_eq(mallctlbymib(mib, miblen, (void *)&dss_prec_old, &sz, NULL,
555 0), 0, "Unexpected mallctl() failure");
556 assert_str_ne(dss_prec_old, "primary",
557 "Unexpected value for dss precedence");
558 }
559 TEST_END
560
TEST_BEGIN(test_arena_i_retain_grow_limit)561 TEST_BEGIN(test_arena_i_retain_grow_limit) {
562 size_t old_limit, new_limit, default_limit;
563 size_t mib[3];
564 size_t miblen;
565
566 bool retain_enabled;
567 size_t sz = sizeof(retain_enabled);
568 assert_d_eq(mallctl("opt.retain", &retain_enabled, &sz, NULL, 0),
569 0, "Unexpected mallctl() failure");
570 test_skip_if(!retain_enabled);
571
572 sz = sizeof(default_limit);
573 miblen = sizeof(mib)/sizeof(size_t);
574 assert_d_eq(mallctlnametomib("arena.0.retain_grow_limit", mib, &miblen),
575 0, "Unexpected mallctlnametomib() error");
576
577 assert_d_eq(mallctlbymib(mib, miblen, &default_limit, &sz, NULL, 0), 0,
578 "Unexpected mallctl() failure");
579 assert_zu_eq(default_limit, sz_pind2sz(EXTENT_GROW_MAX_PIND),
580 "Unexpected default for retain_grow_limit");
581
582 new_limit = PAGE - 1;
583 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &new_limit,
584 sizeof(new_limit)), EFAULT, "Unexpected mallctl() success");
585
586 new_limit = PAGE + 1;
587 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &new_limit,
588 sizeof(new_limit)), 0, "Unexpected mallctl() failure");
589 assert_d_eq(mallctlbymib(mib, miblen, &old_limit, &sz, NULL, 0), 0,
590 "Unexpected mallctl() failure");
591 assert_zu_eq(old_limit, PAGE,
592 "Unexpected value for retain_grow_limit");
593
594 /* Expect grow less than psize class 10. */
595 new_limit = sz_pind2sz(10) - 1;
596 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &new_limit,
597 sizeof(new_limit)), 0, "Unexpected mallctl() failure");
598 assert_d_eq(mallctlbymib(mib, miblen, &old_limit, &sz, NULL, 0), 0,
599 "Unexpected mallctl() failure");
600 assert_zu_eq(old_limit, sz_pind2sz(9),
601 "Unexpected value for retain_grow_limit");
602
603 /* Restore to default. */
604 assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &default_limit,
605 sizeof(default_limit)), 0, "Unexpected mallctl() failure");
606 }
607 TEST_END
608
TEST_BEGIN(test_arenas_dirty_decay_ms)609 TEST_BEGIN(test_arenas_dirty_decay_ms) {
610 ssize_t dirty_decay_ms, orig_dirty_decay_ms, prev_dirty_decay_ms;
611 size_t sz = sizeof(ssize_t);
612
613 assert_d_eq(mallctl("arenas.dirty_decay_ms",
614 (void *)&orig_dirty_decay_ms, &sz, NULL, 0), 0,
615 "Unexpected mallctl() failure");
616
617 dirty_decay_ms = -2;
618 assert_d_eq(mallctl("arenas.dirty_decay_ms", NULL, NULL,
619 (void *)&dirty_decay_ms, sizeof(ssize_t)), EFAULT,
620 "Unexpected mallctl() success");
621
622 dirty_decay_ms = 0x7fffffff;
623 assert_d_eq(mallctl("arenas.dirty_decay_ms", NULL, NULL,
624 (void *)&dirty_decay_ms, sizeof(ssize_t)), 0,
625 "Expected mallctl() failure");
626
627 for (prev_dirty_decay_ms = dirty_decay_ms, dirty_decay_ms = -1;
628 dirty_decay_ms < 20; prev_dirty_decay_ms = dirty_decay_ms,
629 dirty_decay_ms++) {
630 ssize_t old_dirty_decay_ms;
631
632 assert_d_eq(mallctl("arenas.dirty_decay_ms",
633 (void *)&old_dirty_decay_ms, &sz, (void *)&dirty_decay_ms,
634 sizeof(ssize_t)), 0, "Unexpected mallctl() failure");
635 assert_zd_eq(old_dirty_decay_ms, prev_dirty_decay_ms,
636 "Unexpected old arenas.dirty_decay_ms");
637 }
638 }
639 TEST_END
640
TEST_BEGIN(test_arenas_muzzy_decay_ms)641 TEST_BEGIN(test_arenas_muzzy_decay_ms) {
642 ssize_t muzzy_decay_ms, orig_muzzy_decay_ms, prev_muzzy_decay_ms;
643 size_t sz = sizeof(ssize_t);
644
645 assert_d_eq(mallctl("arenas.muzzy_decay_ms",
646 (void *)&orig_muzzy_decay_ms, &sz, NULL, 0), 0,
647 "Unexpected mallctl() failure");
648
649 muzzy_decay_ms = -2;
650 assert_d_eq(mallctl("arenas.muzzy_decay_ms", NULL, NULL,
651 (void *)&muzzy_decay_ms, sizeof(ssize_t)), EFAULT,
652 "Unexpected mallctl() success");
653
654 muzzy_decay_ms = 0x7fffffff;
655 assert_d_eq(mallctl("arenas.muzzy_decay_ms", NULL, NULL,
656 (void *)&muzzy_decay_ms, sizeof(ssize_t)), 0,
657 "Expected mallctl() failure");
658
659 for (prev_muzzy_decay_ms = muzzy_decay_ms, muzzy_decay_ms = -1;
660 muzzy_decay_ms < 20; prev_muzzy_decay_ms = muzzy_decay_ms,
661 muzzy_decay_ms++) {
662 ssize_t old_muzzy_decay_ms;
663
664 assert_d_eq(mallctl("arenas.muzzy_decay_ms",
665 (void *)&old_muzzy_decay_ms, &sz, (void *)&muzzy_decay_ms,
666 sizeof(ssize_t)), 0, "Unexpected mallctl() failure");
667 assert_zd_eq(old_muzzy_decay_ms, prev_muzzy_decay_ms,
668 "Unexpected old arenas.muzzy_decay_ms");
669 }
670 }
671 TEST_END
672
TEST_BEGIN(test_arenas_constants)673 TEST_BEGIN(test_arenas_constants) {
674 #define TEST_ARENAS_CONSTANT(t, name, expected) do { \
675 t name; \
676 size_t sz = sizeof(t); \
677 assert_d_eq(mallctl("arenas."#name, (void *)&name, &sz, NULL, \
678 0), 0, "Unexpected mallctl() failure"); \
679 assert_zu_eq(name, expected, "Incorrect "#name" size"); \
680 } while (0)
681
682 TEST_ARENAS_CONSTANT(size_t, quantum, QUANTUM);
683 TEST_ARENAS_CONSTANT(size_t, page, PAGE);
684 TEST_ARENAS_CONSTANT(unsigned, nbins, NBINS);
685 TEST_ARENAS_CONSTANT(unsigned, nlextents, NSIZES - NBINS);
686
687 #undef TEST_ARENAS_CONSTANT
688 }
689 TEST_END
690
TEST_BEGIN(test_arenas_bin_constants)691 TEST_BEGIN(test_arenas_bin_constants) {
692 #define TEST_ARENAS_BIN_CONSTANT(t, name, expected) do { \
693 t name; \
694 size_t sz = sizeof(t); \
695 assert_d_eq(mallctl("arenas.bin.0."#name, (void *)&name, &sz, \
696 NULL, 0), 0, "Unexpected mallctl() failure"); \
697 assert_zu_eq(name, expected, "Incorrect "#name" size"); \
698 } while (0)
699
700 TEST_ARENAS_BIN_CONSTANT(size_t, size, bin_infos[0].reg_size);
701 TEST_ARENAS_BIN_CONSTANT(uint32_t, nregs, bin_infos[0].nregs);
702 TEST_ARENAS_BIN_CONSTANT(size_t, slab_size,
703 bin_infos[0].slab_size);
704
705 #undef TEST_ARENAS_BIN_CONSTANT
706 }
707 TEST_END
708
TEST_BEGIN(test_arenas_lextent_constants)709 TEST_BEGIN(test_arenas_lextent_constants) {
710 #define TEST_ARENAS_LEXTENT_CONSTANT(t, name, expected) do { \
711 t name; \
712 size_t sz = sizeof(t); \
713 assert_d_eq(mallctl("arenas.lextent.0."#name, (void *)&name, \
714 &sz, NULL, 0), 0, "Unexpected mallctl() failure"); \
715 assert_zu_eq(name, expected, "Incorrect "#name" size"); \
716 } while (0)
717
718 TEST_ARENAS_LEXTENT_CONSTANT(size_t, size, LARGE_MINCLASS);
719
720 #undef TEST_ARENAS_LEXTENT_CONSTANT
721 }
722 TEST_END
723
TEST_BEGIN(test_arenas_create)724 TEST_BEGIN(test_arenas_create) {
725 unsigned narenas_before, arena, narenas_after;
726 size_t sz = sizeof(unsigned);
727
728 assert_d_eq(mallctl("arenas.narenas", (void *)&narenas_before, &sz,
729 NULL, 0), 0, "Unexpected mallctl() failure");
730 assert_d_eq(mallctl("arenas.create", (void *)&arena, &sz, NULL, 0), 0,
731 "Unexpected mallctl() failure");
732 assert_d_eq(mallctl("arenas.narenas", (void *)&narenas_after, &sz, NULL,
733 0), 0, "Unexpected mallctl() failure");
734
735 assert_u_eq(narenas_before+1, narenas_after,
736 "Unexpected number of arenas before versus after extension");
737 assert_u_eq(arena, narenas_after-1, "Unexpected arena index");
738 }
739 TEST_END
740
TEST_BEGIN(test_arenas_lookup)741 TEST_BEGIN(test_arenas_lookup) {
742 unsigned arena, arena1;
743 void *ptr;
744 size_t sz = sizeof(unsigned);
745
746 assert_d_eq(mallctl("arenas.create", (void *)&arena, &sz, NULL, 0), 0,
747 "Unexpected mallctl() failure");
748 ptr = mallocx(42, MALLOCX_ARENA(arena) | MALLOCX_TCACHE_NONE);
749 assert_ptr_not_null(ptr, "Unexpected mallocx() failure");
750 assert_d_eq(mallctl("arenas.lookup", &arena1, &sz, &ptr, sizeof(ptr)),
751 0, "Unexpected mallctl() failure");
752 assert_u_eq(arena, arena1, "Unexpected arena index");
753 dallocx(ptr, 0);
754 }
755 TEST_END
756
TEST_BEGIN(test_stats_arenas)757 TEST_BEGIN(test_stats_arenas) {
758 #define TEST_STATS_ARENAS(t, name) do { \
759 t name; \
760 size_t sz = sizeof(t); \
761 assert_d_eq(mallctl("stats.arenas.0."#name, (void *)&name, &sz, \
762 NULL, 0), 0, "Unexpected mallctl() failure"); \
763 } while (0)
764
765 TEST_STATS_ARENAS(unsigned, nthreads);
766 TEST_STATS_ARENAS(const char *, dss);
767 TEST_STATS_ARENAS(ssize_t, dirty_decay_ms);
768 TEST_STATS_ARENAS(ssize_t, muzzy_decay_ms);
769 TEST_STATS_ARENAS(size_t, pactive);
770 TEST_STATS_ARENAS(size_t, pdirty);
771
772 #undef TEST_STATS_ARENAS
773 }
774 TEST_END
775
776 int
main(void)777 main(void) {
778 return test(
779 test_mallctl_errors,
780 test_mallctlnametomib_errors,
781 test_mallctlbymib_errors,
782 test_mallctl_read_write,
783 test_mallctlnametomib_short_mib,
784 test_mallctl_config,
785 test_mallctl_opt,
786 test_manpage_example,
787 test_tcache_none,
788 test_tcache,
789 test_thread_arena,
790 test_arena_i_initialized,
791 test_arena_i_dirty_decay_ms,
792 test_arena_i_muzzy_decay_ms,
793 test_arena_i_purge,
794 test_arena_i_decay,
795 test_arena_i_dss,
796 test_arena_i_retain_grow_limit,
797 test_arenas_dirty_decay_ms,
798 test_arenas_muzzy_decay_ms,
799 test_arenas_constants,
800 test_arenas_bin_constants,
801 test_arenas_lextent_constants,
802 test_arenas_create,
803 test_arenas_lookup,
804 test_stats_arenas);
805 }
806