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