1#include "test/jemalloc_test.h"
2
3TEST_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, &epoch, sizeof(epoch)-1),
16	    EINVAL, "mallctl() should return EINVAL for input size mismatch");
17	assert_d_eq(mallctl("epoch", NULL, NULL, &epoch, sizeof(epoch)+1),
18	    EINVAL, "mallctl() should return EINVAL for input size mismatch");
19
20	sz = sizeof(epoch)-1;
21	assert_d_eq(mallctl("epoch", &epoch, &sz, NULL, 0), EINVAL,
22	    "mallctl() should return EINVAL for output size mismatch");
23	sz = sizeof(epoch)+1;
24	assert_d_eq(mallctl("epoch", &epoch, &sz, NULL, 0), EINVAL,
25	    "mallctl() should return EINVAL for output size mismatch");
26}
27TEST_END
28
29TEST_BEGIN(test_mallctlnametomib_errors)
30{
31	size_t mib[1];
32	size_t miblen;
33
34	miblen = sizeof(mib)/sizeof(size_t);
35	assert_d_eq(mallctlnametomib("no_such_name", mib, &miblen), ENOENT,
36	    "mallctlnametomib() should return ENOENT for non-existent names");
37}
38TEST_END
39
40TEST_BEGIN(test_mallctlbymib_errors)
41{
42	uint64_t epoch;
43	size_t sz;
44	size_t mib[1];
45	size_t miblen;
46
47	miblen = sizeof(mib)/sizeof(size_t);
48	assert_d_eq(mallctlnametomib("version", mib, &miblen), 0,
49	    "Unexpected mallctlnametomib() failure");
50
51	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, "0.0.0",
52	    strlen("0.0.0")), EPERM, "mallctl() should return EPERM on "
53	    "attempt to write read-only value");
54
55	miblen = sizeof(mib)/sizeof(size_t);
56	assert_d_eq(mallctlnametomib("epoch", mib, &miblen), 0,
57	    "Unexpected mallctlnametomib() failure");
58
59	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &epoch,
60	    sizeof(epoch)-1), EINVAL,
61	    "mallctlbymib() should return EINVAL for input size mismatch");
62	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, &epoch,
63	    sizeof(epoch)+1), EINVAL,
64	    "mallctlbymib() should return EINVAL for input size mismatch");
65
66	sz = sizeof(epoch)-1;
67	assert_d_eq(mallctlbymib(mib, miblen, &epoch, &sz, NULL, 0), EINVAL,
68	    "mallctlbymib() should return EINVAL for output size mismatch");
69	sz = sizeof(epoch)+1;
70	assert_d_eq(mallctlbymib(mib, miblen, &epoch, &sz, NULL, 0), EINVAL,
71	    "mallctlbymib() should return EINVAL for output size mismatch");
72}
73TEST_END
74
75TEST_BEGIN(test_mallctl_read_write)
76{
77	uint64_t old_epoch, new_epoch;
78	size_t sz = sizeof(old_epoch);
79
80	/* Blind. */
81	assert_d_eq(mallctl("epoch", NULL, NULL, NULL, 0), 0,
82	    "Unexpected mallctl() failure");
83	assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
84
85	/* Read. */
86	assert_d_eq(mallctl("epoch", &old_epoch, &sz, NULL, 0), 0,
87	    "Unexpected mallctl() failure");
88	assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
89
90	/* Write. */
91	assert_d_eq(mallctl("epoch", NULL, NULL, &new_epoch, sizeof(new_epoch)),
92	    0, "Unexpected mallctl() failure");
93	assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
94
95	/* Read+write. */
96	assert_d_eq(mallctl("epoch", &old_epoch, &sz, &new_epoch,
97	    sizeof(new_epoch)), 0, "Unexpected mallctl() failure");
98	assert_zu_eq(sz, sizeof(old_epoch), "Unexpected output size");
99}
100TEST_END
101
102TEST_BEGIN(test_mallctlnametomib_short_mib)
103{
104	size_t mib[4];
105	size_t miblen;
106
107	miblen = 3;
108	mib[3] = 42;
109	assert_d_eq(mallctlnametomib("arenas.bin.0.nregs", mib, &miblen), 0,
110	    "Unexpected mallctlnametomib() failure");
111	assert_zu_eq(miblen, 3, "Unexpected mib output length");
112	assert_zu_eq(mib[3], 42,
113	    "mallctlnametomib() wrote past the end of the input mib");
114}
115TEST_END
116
117TEST_BEGIN(test_mallctl_config)
118{
119
120#define	TEST_MALLCTL_CONFIG(config) do {				\
121	bool oldval;							\
122	size_t sz = sizeof(oldval);					\
123	assert_d_eq(mallctl("config."#config, &oldval, &sz, NULL, 0),	\
124	    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(debug);
130	TEST_MALLCTL_CONFIG(fill);
131	TEST_MALLCTL_CONFIG(lazy_lock);
132	TEST_MALLCTL_CONFIG(munmap);
133	TEST_MALLCTL_CONFIG(prof);
134	TEST_MALLCTL_CONFIG(prof_libgcc);
135	TEST_MALLCTL_CONFIG(prof_libunwind);
136	TEST_MALLCTL_CONFIG(stats);
137	TEST_MALLCTL_CONFIG(tcache);
138	TEST_MALLCTL_CONFIG(tls);
139	TEST_MALLCTL_CONFIG(utrace);
140	TEST_MALLCTL_CONFIG(valgrind);
141	TEST_MALLCTL_CONFIG(xmalloc);
142
143#undef TEST_MALLCTL_CONFIG
144}
145TEST_END
146
147TEST_BEGIN(test_mallctl_opt)
148{
149	bool config_always = true;
150
151#define	TEST_MALLCTL_OPT(t, opt, config) do {				\
152	t oldval;							\
153	size_t sz = sizeof(oldval);					\
154	int expected = config_##config ? 0 : ENOENT;			\
155	int result = mallctl("opt."#opt, &oldval, &sz, NULL, 0);	\
156	assert_d_eq(result, expected,					\
157	    "Unexpected mallctl() result for opt."#opt);		\
158	assert_zu_eq(sz, sizeof(oldval), "Unexpected output size");	\
159} while (0)
160
161	TEST_MALLCTL_OPT(bool, abort, always);
162	TEST_MALLCTL_OPT(size_t, lg_chunk, always);
163	TEST_MALLCTL_OPT(const char *, dss, always);
164	TEST_MALLCTL_OPT(size_t, narenas, always);
165	TEST_MALLCTL_OPT(ssize_t, lg_dirty_mult, always);
166	TEST_MALLCTL_OPT(bool, stats_print, always);
167	TEST_MALLCTL_OPT(bool, junk, fill);
168	TEST_MALLCTL_OPT(size_t, quarantine, fill);
169	TEST_MALLCTL_OPT(bool, redzone, fill);
170	TEST_MALLCTL_OPT(bool, zero, fill);
171	TEST_MALLCTL_OPT(bool, utrace, utrace);
172	TEST_MALLCTL_OPT(bool, xmalloc, xmalloc);
173	TEST_MALLCTL_OPT(bool, tcache, tcache);
174	TEST_MALLCTL_OPT(size_t, lg_tcache_max, tcache);
175	TEST_MALLCTL_OPT(bool, prof, prof);
176	TEST_MALLCTL_OPT(const char *, prof_prefix, prof);
177	TEST_MALLCTL_OPT(bool, prof_active, prof);
178	TEST_MALLCTL_OPT(ssize_t, lg_prof_sample, prof);
179	TEST_MALLCTL_OPT(bool, prof_accum, prof);
180	TEST_MALLCTL_OPT(ssize_t, lg_prof_interval, prof);
181	TEST_MALLCTL_OPT(bool, prof_gdump, prof);
182	TEST_MALLCTL_OPT(bool, prof_final, prof);
183	TEST_MALLCTL_OPT(bool, prof_leak, prof);
184
185#undef TEST_MALLCTL_OPT
186}
187TEST_END
188
189TEST_BEGIN(test_manpage_example)
190{
191	unsigned nbins, i;
192	size_t mib[4];
193	size_t len, miblen;
194
195	len = sizeof(nbins);
196	assert_d_eq(mallctl("arenas.nbins", &nbins, &len, NULL, 0), 0,
197	    "Unexpected mallctl() failure");
198
199	miblen = 4;
200	assert_d_eq(mallctlnametomib("arenas.bin.0.size", mib, &miblen), 0,
201	    "Unexpected mallctlnametomib() failure");
202	for (i = 0; i < nbins; i++) {
203		size_t bin_size;
204
205		mib[2] = i;
206		len = sizeof(bin_size);
207		assert_d_eq(mallctlbymib(mib, miblen, &bin_size, &len, NULL, 0),
208		    0, "Unexpected mallctlbymib() failure");
209		/* Do something with bin_size... */
210	}
211}
212TEST_END
213
214TEST_BEGIN(test_thread_arena)
215{
216	unsigned arena_old, arena_new, narenas;
217	size_t sz = sizeof(unsigned);
218
219	assert_d_eq(mallctl("arenas.narenas", &narenas, &sz, NULL, 0), 0,
220	    "Unexpected mallctl() failure");
221	assert_u_eq(narenas, opt_narenas, "Number of arenas incorrect");
222	arena_new = narenas - 1;
223	assert_d_eq(mallctl("thread.arena", &arena_old, &sz, &arena_new,
224	    sizeof(unsigned)), 0, "Unexpected mallctl() failure");
225	arena_new = 0;
226	assert_d_eq(mallctl("thread.arena", &arena_old, &sz, &arena_new,
227	    sizeof(unsigned)), 0, "Unexpected mallctl() failure");
228}
229TEST_END
230
231TEST_BEGIN(test_arena_i_purge)
232{
233	unsigned narenas;
234	size_t sz = sizeof(unsigned);
235	size_t mib[3];
236	size_t miblen = 3;
237
238	assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
239	    "Unexpected mallctl() failure");
240
241	assert_d_eq(mallctl("arenas.narenas", &narenas, &sz, NULL, 0), 0,
242	    "Unexpected mallctl() failure");
243	assert_d_eq(mallctlnametomib("arena.0.purge", mib, &miblen), 0,
244	    "Unexpected mallctlnametomib() failure");
245	mib[1] = narenas;
246	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
247	    "Unexpected mallctlbymib() failure");
248}
249TEST_END
250
251TEST_BEGIN(test_arena_i_dss)
252{
253	const char *dss_prec_old, *dss_prec_new;
254	size_t sz = sizeof(dss_prec_old);
255	size_t mib[3];
256	size_t miblen;
257
258	miblen = sizeof(mib)/sizeof(size_t);
259	assert_d_eq(mallctlnametomib("arena.0.dss", mib, &miblen), 0,
260	    "Unexpected mallctlnametomib() error");
261
262	dss_prec_new = "disabled";
263	assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_old, &sz, &dss_prec_new,
264	    sizeof(dss_prec_new)), 0, "Unexpected mallctl() failure");
265	assert_str_ne(dss_prec_old, "primary",
266	    "Unexpected default for dss precedence");
267
268	assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_new, &sz, &dss_prec_old,
269	    sizeof(dss_prec_old)), 0, "Unexpected mallctl() failure");
270
271	mib[1] = narenas_total_get();
272	dss_prec_new = "disabled";
273	assert_d_eq(mallctlbymib(mib, miblen, &dss_prec_old, &sz, &dss_prec_new,
274	    sizeof(dss_prec_new)), 0, "Unexpected mallctl() failure");
275	assert_str_ne(dss_prec_old, "primary",
276	    "Unexpected default for dss precedence");
277}
278TEST_END
279
280TEST_BEGIN(test_arenas_initialized)
281{
282	unsigned narenas;
283	size_t sz = sizeof(narenas);
284
285	assert_d_eq(mallctl("arenas.narenas", &narenas, &sz, NULL, 0), 0,
286	    "Unexpected mallctl() failure");
287	{
288		VARIABLE_ARRAY(bool, initialized, narenas);
289
290		sz = narenas * sizeof(bool);
291		assert_d_eq(mallctl("arenas.initialized", initialized, &sz,
292		    NULL, 0), 0, "Unexpected mallctl() failure");
293	}
294}
295TEST_END
296
297TEST_BEGIN(test_arenas_constants)
298{
299
300#define	TEST_ARENAS_CONSTANT(t, name, expected) do {			\
301	t name;								\
302	size_t sz = sizeof(t);						\
303	assert_d_eq(mallctl("arenas."#name, &name, &sz, NULL, 0), 0,	\
304	    "Unexpected mallctl() failure");				\
305	assert_zu_eq(name, expected, "Incorrect "#name" size");		\
306} while (0)
307
308	TEST_ARENAS_CONSTANT(size_t, quantum, QUANTUM);
309	TEST_ARENAS_CONSTANT(size_t, page, PAGE);
310	TEST_ARENAS_CONSTANT(unsigned, nbins, NBINS);
311	TEST_ARENAS_CONSTANT(size_t, nlruns, nlclasses);
312
313#undef TEST_ARENAS_CONSTANT
314}
315TEST_END
316
317TEST_BEGIN(test_arenas_bin_constants)
318{
319
320#define	TEST_ARENAS_BIN_CONSTANT(t, name, expected) do {		\
321	t name;								\
322	size_t sz = sizeof(t);						\
323	assert_d_eq(mallctl("arenas.bin.0."#name, &name, &sz, NULL, 0),	\
324	    0, "Unexpected mallctl() failure");				\
325	assert_zu_eq(name, expected, "Incorrect "#name" size");		\
326} while (0)
327
328	TEST_ARENAS_BIN_CONSTANT(size_t, size, arena_bin_info[0].reg_size);
329	TEST_ARENAS_BIN_CONSTANT(uint32_t, nregs, arena_bin_info[0].nregs);
330	TEST_ARENAS_BIN_CONSTANT(size_t, run_size, arena_bin_info[0].run_size);
331
332#undef TEST_ARENAS_BIN_CONSTANT
333}
334TEST_END
335
336TEST_BEGIN(test_arenas_lrun_constants)
337{
338
339#define	TEST_ARENAS_LRUN_CONSTANT(t, name, expected) do {		\
340	t name;								\
341	size_t sz = sizeof(t);						\
342	assert_d_eq(mallctl("arenas.lrun.0."#name, &name, &sz, NULL,	\
343	    0), 0, "Unexpected mallctl() failure");			\
344	assert_zu_eq(name, expected, "Incorrect "#name" size");		\
345} while (0)
346
347	TEST_ARENAS_LRUN_CONSTANT(size_t, size, (1 << LG_PAGE));
348
349#undef TEST_ARENAS_LRUN_CONSTANT
350}
351TEST_END
352
353TEST_BEGIN(test_arenas_extend)
354{
355	unsigned narenas_before, arena, narenas_after;
356	size_t sz = sizeof(unsigned);
357
358	assert_d_eq(mallctl("arenas.narenas", &narenas_before, &sz, NULL, 0), 0,
359	    "Unexpected mallctl() failure");
360	assert_d_eq(mallctl("arenas.extend", &arena, &sz, NULL, 0), 0,
361	    "Unexpected mallctl() failure");
362	assert_d_eq(mallctl("arenas.narenas", &narenas_after, &sz, NULL, 0), 0,
363	    "Unexpected mallctl() failure");
364
365	assert_u_eq(narenas_before+1, narenas_after,
366	    "Unexpected number of arenas before versus after extension");
367	assert_u_eq(arena, narenas_after-1, "Unexpected arena index");
368}
369TEST_END
370
371TEST_BEGIN(test_stats_arenas)
372{
373
374#define	TEST_STATS_ARENAS(t, name) do {					\
375	t name;								\
376	size_t sz = sizeof(t);						\
377	assert_d_eq(mallctl("stats.arenas.0."#name, &name, &sz, NULL,	\
378	    0), 0, "Unexpected mallctl() failure");			\
379} while (0)
380
381	TEST_STATS_ARENAS(const char *, dss);
382	TEST_STATS_ARENAS(unsigned, nthreads);
383	TEST_STATS_ARENAS(size_t, pactive);
384	TEST_STATS_ARENAS(size_t, pdirty);
385
386#undef TEST_STATS_ARENAS
387}
388TEST_END
389
390int
391main(void)
392{
393
394	return (test(
395	    test_mallctl_errors,
396	    test_mallctlnametomib_errors,
397	    test_mallctlbymib_errors,
398	    test_mallctl_read_write,
399	    test_mallctlnametomib_short_mib,
400	    test_mallctl_config,
401	    test_mallctl_opt,
402	    test_manpage_example,
403	    test_thread_arena,
404	    test_arena_i_purge,
405	    test_arena_i_dss,
406	    test_arenas_initialized,
407	    test_arenas_constants,
408	    test_arenas_bin_constants,
409	    test_arenas_lrun_constants,
410	    test_arenas_extend,
411	    test_stats_arenas));
412}
413