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