1#include "test/jemalloc_test.h"
2
3TEST_BEGIN(test_stats_summary) {
4	size_t sz, allocated, active, resident, mapped;
5	int expected = config_stats ? 0 : ENOENT;
6
7	sz = sizeof(size_t);
8	assert_d_eq(mallctl("stats.allocated", (void *)&allocated, &sz, NULL,
9	    0), expected, "Unexpected mallctl() result");
10	assert_d_eq(mallctl("stats.active", (void *)&active, &sz, NULL, 0),
11	    expected, "Unexpected mallctl() result");
12	assert_d_eq(mallctl("stats.resident", (void *)&resident, &sz, NULL, 0),
13	    expected, "Unexpected mallctl() result");
14	assert_d_eq(mallctl("stats.mapped", (void *)&mapped, &sz, NULL, 0),
15	    expected, "Unexpected mallctl() result");
16
17	if (config_stats) {
18		assert_zu_le(allocated, active,
19		    "allocated should be no larger than active");
20		assert_zu_lt(active, resident,
21		    "active should be less than resident");
22		assert_zu_lt(active, mapped,
23		    "active should be less than mapped");
24	}
25}
26TEST_END
27
28TEST_BEGIN(test_stats_large) {
29	void *p;
30	uint64_t epoch;
31	size_t allocated;
32	uint64_t nmalloc, ndalloc, nrequests;
33	size_t sz;
34	int expected = config_stats ? 0 : ENOENT;
35
36	p = mallocx(SMALL_MAXCLASS+1, MALLOCX_ARENA(0));
37	assert_ptr_not_null(p, "Unexpected mallocx() failure");
38
39	assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)),
40	    0, "Unexpected mallctl() failure");
41
42	sz = sizeof(size_t);
43	assert_d_eq(mallctl("stats.arenas.0.large.allocated",
44	    (void *)&allocated, &sz, NULL, 0), expected,
45	    "Unexpected mallctl() result");
46	sz = sizeof(uint64_t);
47	assert_d_eq(mallctl("stats.arenas.0.large.nmalloc", (void *)&nmalloc,
48	    &sz, NULL, 0), expected, "Unexpected mallctl() result");
49	assert_d_eq(mallctl("stats.arenas.0.large.ndalloc", (void *)&ndalloc,
50	    &sz, NULL, 0), expected, "Unexpected mallctl() result");
51	assert_d_eq(mallctl("stats.arenas.0.large.nrequests",
52	    (void *)&nrequests, &sz, NULL, 0), expected,
53	    "Unexpected mallctl() result");
54
55	if (config_stats) {
56		assert_zu_gt(allocated, 0,
57		    "allocated should be greater than zero");
58		assert_u64_ge(nmalloc, ndalloc,
59		    "nmalloc should be at least as large as ndalloc");
60		assert_u64_le(nmalloc, nrequests,
61		    "nmalloc should no larger than nrequests");
62	}
63
64	dallocx(p, 0);
65}
66TEST_END
67
68TEST_BEGIN(test_stats_arenas_summary) {
69	void *little, *large;
70	uint64_t epoch;
71	size_t sz;
72	int expected = config_stats ? 0 : ENOENT;
73	size_t mapped;
74	uint64_t dirty_npurge, dirty_nmadvise, dirty_purged;
75	uint64_t muzzy_npurge, muzzy_nmadvise, muzzy_purged;
76
77	little = mallocx(SMALL_MAXCLASS, MALLOCX_ARENA(0));
78	assert_ptr_not_null(little, "Unexpected mallocx() failure");
79	large = mallocx((1U << LG_LARGE_MINCLASS), MALLOCX_ARENA(0));
80	assert_ptr_not_null(large, "Unexpected mallocx() failure");
81
82	dallocx(little, 0);
83	dallocx(large, 0);
84
85	assert_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0),
86	    opt_tcache ? 0 : EFAULT, "Unexpected mallctl() result");
87	assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
88	    "Unexpected mallctl() failure");
89
90	assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)),
91	    0, "Unexpected mallctl() failure");
92
93	sz = sizeof(size_t);
94	assert_d_eq(mallctl("stats.arenas.0.mapped", (void *)&mapped, &sz, NULL,
95	    0), expected, "Unexepected mallctl() result");
96
97	sz = sizeof(uint64_t);
98	assert_d_eq(mallctl("stats.arenas.0.dirty_npurge",
99	    (void *)&dirty_npurge, &sz, NULL, 0), expected,
100	    "Unexepected mallctl() result");
101	assert_d_eq(mallctl("stats.arenas.0.dirty_nmadvise",
102	    (void *)&dirty_nmadvise, &sz, NULL, 0), expected,
103	    "Unexepected mallctl() result");
104	assert_d_eq(mallctl("stats.arenas.0.dirty_purged",
105	    (void *)&dirty_purged, &sz, NULL, 0), expected,
106	    "Unexepected mallctl() result");
107	assert_d_eq(mallctl("stats.arenas.0.muzzy_npurge",
108	    (void *)&muzzy_npurge, &sz, NULL, 0), expected,
109	    "Unexepected mallctl() result");
110	assert_d_eq(mallctl("stats.arenas.0.muzzy_nmadvise",
111	    (void *)&muzzy_nmadvise, &sz, NULL, 0), expected,
112	    "Unexepected mallctl() result");
113	assert_d_eq(mallctl("stats.arenas.0.muzzy_purged",
114	    (void *)&muzzy_purged, &sz, NULL, 0), expected,
115	    "Unexepected mallctl() result");
116
117	if (config_stats) {
118		if (!background_thread_enabled()) {
119			assert_u64_gt(dirty_npurge + muzzy_npurge, 0,
120			    "At least one purge should have occurred");
121		}
122		assert_u64_le(dirty_nmadvise, dirty_purged,
123		    "dirty_nmadvise should be no greater than dirty_purged");
124		assert_u64_le(muzzy_nmadvise, muzzy_purged,
125		    "muzzy_nmadvise should be no greater than muzzy_purged");
126	}
127}
128TEST_END
129
130void *
131thd_start(void *arg) {
132	return NULL;
133}
134
135static void
136no_lazy_lock(void) {
137	thd_t thd;
138
139	thd_create(&thd, thd_start, NULL);
140	thd_join(thd, NULL);
141}
142
143TEST_BEGIN(test_stats_arenas_small) {
144	void *p;
145	size_t sz, allocated;
146	uint64_t epoch, nmalloc, ndalloc, nrequests;
147	int expected = config_stats ? 0 : ENOENT;
148
149	no_lazy_lock(); /* Lazy locking would dodge tcache testing. */
150
151	p = mallocx(SMALL_MAXCLASS, MALLOCX_ARENA(0));
152	assert_ptr_not_null(p, "Unexpected mallocx() failure");
153
154	assert_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0),
155	    opt_tcache ? 0 : EFAULT, "Unexpected mallctl() result");
156
157	assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)),
158	    0, "Unexpected mallctl() failure");
159
160	sz = sizeof(size_t);
161	assert_d_eq(mallctl("stats.arenas.0.small.allocated",
162	    (void *)&allocated, &sz, NULL, 0), expected,
163	    "Unexpected mallctl() result");
164	sz = sizeof(uint64_t);
165	assert_d_eq(mallctl("stats.arenas.0.small.nmalloc", (void *)&nmalloc,
166	    &sz, NULL, 0), expected, "Unexpected mallctl() result");
167	assert_d_eq(mallctl("stats.arenas.0.small.ndalloc", (void *)&ndalloc,
168	    &sz, NULL, 0), expected, "Unexpected mallctl() result");
169	assert_d_eq(mallctl("stats.arenas.0.small.nrequests",
170	    (void *)&nrequests, &sz, NULL, 0), expected,
171	    "Unexpected mallctl() result");
172
173	if (config_stats) {
174		assert_zu_gt(allocated, 0,
175		    "allocated should be greater than zero");
176		assert_u64_gt(nmalloc, 0,
177		    "nmalloc should be no greater than zero");
178		assert_u64_ge(nmalloc, ndalloc,
179		    "nmalloc should be at least as large as ndalloc");
180		assert_u64_gt(nrequests, 0,
181		    "nrequests should be greater than zero");
182	}
183
184	dallocx(p, 0);
185}
186TEST_END
187
188TEST_BEGIN(test_stats_arenas_large) {
189	void *p;
190	size_t sz, allocated;
191	uint64_t epoch, nmalloc, ndalloc;
192	int expected = config_stats ? 0 : ENOENT;
193
194	p = mallocx((1U << LG_LARGE_MINCLASS), MALLOCX_ARENA(0));
195	assert_ptr_not_null(p, "Unexpected mallocx() failure");
196
197	assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)),
198	    0, "Unexpected mallctl() failure");
199
200	sz = sizeof(size_t);
201	assert_d_eq(mallctl("stats.arenas.0.large.allocated",
202	    (void *)&allocated, &sz, NULL, 0), expected,
203	    "Unexpected mallctl() result");
204	sz = sizeof(uint64_t);
205	assert_d_eq(mallctl("stats.arenas.0.large.nmalloc", (void *)&nmalloc,
206	    &sz, NULL, 0), expected, "Unexpected mallctl() result");
207	assert_d_eq(mallctl("stats.arenas.0.large.ndalloc", (void *)&ndalloc,
208	    &sz, NULL, 0), expected, "Unexpected mallctl() result");
209
210	if (config_stats) {
211		assert_zu_gt(allocated, 0,
212		    "allocated should be greater than zero");
213		assert_u64_gt(nmalloc, 0,
214		    "nmalloc should be greater than zero");
215		assert_u64_ge(nmalloc, ndalloc,
216		    "nmalloc should be at least as large as ndalloc");
217	}
218
219	dallocx(p, 0);
220}
221TEST_END
222
223static void
224gen_mallctl_str(char *cmd, char *name, unsigned arena_ind) {
225	sprintf(cmd, "stats.arenas.%u.bins.0.%s", arena_ind, name);
226}
227
228TEST_BEGIN(test_stats_arenas_bins) {
229	void *p;
230	size_t sz, curslabs, curregs;
231	uint64_t epoch, nmalloc, ndalloc, nrequests, nfills, nflushes;
232	uint64_t nslabs, nreslabs;
233	int expected = config_stats ? 0 : ENOENT;
234
235	/* Make sure allocation below isn't satisfied by tcache. */
236	assert_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0),
237	    opt_tcache ? 0 : EFAULT, "Unexpected mallctl() result");
238
239	unsigned arena_ind, old_arena_ind;
240	sz = sizeof(unsigned);
241	assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0),
242	    0, "Arena creation failure");
243	sz = sizeof(arena_ind);
244	assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind, &sz,
245	    (void *)&arena_ind, sizeof(arena_ind)), 0,
246	    "Unexpected mallctl() failure");
247
248	p = malloc(bin_infos[0].reg_size);
249	assert_ptr_not_null(p, "Unexpected malloc() failure");
250
251	assert_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0),
252	    opt_tcache ? 0 : EFAULT, "Unexpected mallctl() result");
253
254	assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)),
255	    0, "Unexpected mallctl() failure");
256
257	char cmd[128];
258	sz = sizeof(uint64_t);
259	gen_mallctl_str(cmd, "nmalloc", arena_ind);
260	assert_d_eq(mallctl(cmd, (void *)&nmalloc, &sz, NULL, 0), expected,
261	    "Unexpected mallctl() result");
262	gen_mallctl_str(cmd, "ndalloc", arena_ind);
263	assert_d_eq(mallctl(cmd, (void *)&ndalloc, &sz, NULL, 0), expected,
264	    "Unexpected mallctl() result");
265	gen_mallctl_str(cmd, "nrequests", arena_ind);
266	assert_d_eq(mallctl(cmd, (void *)&nrequests, &sz, NULL, 0), expected,
267	    "Unexpected mallctl() result");
268	sz = sizeof(size_t);
269	gen_mallctl_str(cmd, "curregs", arena_ind);
270	assert_d_eq(mallctl(cmd, (void *)&curregs, &sz, NULL, 0), expected,
271	    "Unexpected mallctl() result");
272
273	sz = sizeof(uint64_t);
274	gen_mallctl_str(cmd, "nfills", arena_ind);
275	assert_d_eq(mallctl(cmd, (void *)&nfills, &sz, NULL, 0), expected,
276	    "Unexpected mallctl() result");
277	gen_mallctl_str(cmd, "nflushes", arena_ind);
278	assert_d_eq(mallctl(cmd, (void *)&nflushes, &sz, NULL, 0), expected,
279	    "Unexpected mallctl() result");
280
281	gen_mallctl_str(cmd, "nslabs", arena_ind);
282	assert_d_eq(mallctl(cmd, (void *)&nslabs, &sz, NULL, 0), expected,
283	    "Unexpected mallctl() result");
284	gen_mallctl_str(cmd, "nreslabs", arena_ind);
285	assert_d_eq(mallctl(cmd, (void *)&nreslabs, &sz, NULL, 0), expected,
286	    "Unexpected mallctl() result");
287	sz = sizeof(size_t);
288	gen_mallctl_str(cmd, "curslabs", arena_ind);
289	assert_d_eq(mallctl(cmd, (void *)&curslabs, &sz, NULL, 0), expected,
290	    "Unexpected mallctl() result");
291
292	if (config_stats) {
293		assert_u64_gt(nmalloc, 0,
294		    "nmalloc should be greater than zero");
295		assert_u64_ge(nmalloc, ndalloc,
296		    "nmalloc should be at least as large as ndalloc");
297		assert_u64_gt(nrequests, 0,
298		    "nrequests should be greater than zero");
299		assert_zu_gt(curregs, 0,
300		    "allocated should be greater than zero");
301		if (opt_tcache) {
302			assert_u64_gt(nfills, 0,
303			    "At least one fill should have occurred");
304			assert_u64_gt(nflushes, 0,
305			    "At least one flush should have occurred");
306		}
307		assert_u64_gt(nslabs, 0,
308		    "At least one slab should have been allocated");
309		assert_zu_gt(curslabs, 0,
310		    "At least one slab should be currently allocated");
311	}
312
313	dallocx(p, 0);
314}
315TEST_END
316
317TEST_BEGIN(test_stats_arenas_lextents) {
318	void *p;
319	uint64_t epoch, nmalloc, ndalloc;
320	size_t curlextents, sz, hsize;
321	int expected = config_stats ? 0 : ENOENT;
322
323	sz = sizeof(size_t);
324	assert_d_eq(mallctl("arenas.lextent.0.size", (void *)&hsize, &sz, NULL,
325	    0), 0, "Unexpected mallctl() failure");
326
327	p = mallocx(hsize, MALLOCX_ARENA(0));
328	assert_ptr_not_null(p, "Unexpected mallocx() failure");
329
330	assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)),
331	    0, "Unexpected mallctl() failure");
332
333	sz = sizeof(uint64_t);
334	assert_d_eq(mallctl("stats.arenas.0.lextents.0.nmalloc",
335	    (void *)&nmalloc, &sz, NULL, 0), expected,
336	    "Unexpected mallctl() result");
337	assert_d_eq(mallctl("stats.arenas.0.lextents.0.ndalloc",
338	    (void *)&ndalloc, &sz, NULL, 0), expected,
339	    "Unexpected mallctl() result");
340	sz = sizeof(size_t);
341	assert_d_eq(mallctl("stats.arenas.0.lextents.0.curlextents",
342	    (void *)&curlextents, &sz, NULL, 0), expected,
343	    "Unexpected mallctl() result");
344
345	if (config_stats) {
346		assert_u64_gt(nmalloc, 0,
347		    "nmalloc should be greater than zero");
348		assert_u64_ge(nmalloc, ndalloc,
349		    "nmalloc should be at least as large as ndalloc");
350		assert_u64_gt(curlextents, 0,
351		    "At least one extent should be currently allocated");
352	}
353
354	dallocx(p, 0);
355}
356TEST_END
357
358int
359main(void) {
360	return test_no_reentrancy(
361	    test_stats_summary,
362	    test_stats_large,
363	    test_stats_arenas_summary,
364	    test_stats_arenas_small,
365	    test_stats_arenas_large,
366	    test_stats_arenas_bins,
367	    test_stats_arenas_lextents);
368}
369