xref: /aosp_15_r20/external/jemalloc_new/test/unit/decay.c (revision 1208bc7e437ced7eb82efac44ba17e3beba411da)
1*1208bc7eSAndroid Build Coastguard Worker #include "test/jemalloc_test.h"
2*1208bc7eSAndroid Build Coastguard Worker 
3*1208bc7eSAndroid Build Coastguard Worker #include "jemalloc/internal/ticker.h"
4*1208bc7eSAndroid Build Coastguard Worker 
5*1208bc7eSAndroid Build Coastguard Worker static nstime_monotonic_t *nstime_monotonic_orig;
6*1208bc7eSAndroid Build Coastguard Worker static nstime_update_t *nstime_update_orig;
7*1208bc7eSAndroid Build Coastguard Worker 
8*1208bc7eSAndroid Build Coastguard Worker static unsigned nupdates_mock;
9*1208bc7eSAndroid Build Coastguard Worker static nstime_t time_mock;
10*1208bc7eSAndroid Build Coastguard Worker static bool monotonic_mock;
11*1208bc7eSAndroid Build Coastguard Worker 
12*1208bc7eSAndroid Build Coastguard Worker static bool
check_background_thread_enabled(void)13*1208bc7eSAndroid Build Coastguard Worker check_background_thread_enabled(void) {
14*1208bc7eSAndroid Build Coastguard Worker 	bool enabled;
15*1208bc7eSAndroid Build Coastguard Worker 	size_t sz = sizeof(bool);
16*1208bc7eSAndroid Build Coastguard Worker 	int ret = mallctl("background_thread", (void *)&enabled, &sz, NULL,0);
17*1208bc7eSAndroid Build Coastguard Worker 	if (ret == ENOENT) {
18*1208bc7eSAndroid Build Coastguard Worker 		return false;
19*1208bc7eSAndroid Build Coastguard Worker 	}
20*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(ret, 0, "Unexpected mallctl error");
21*1208bc7eSAndroid Build Coastguard Worker 	return enabled;
22*1208bc7eSAndroid Build Coastguard Worker }
23*1208bc7eSAndroid Build Coastguard Worker 
24*1208bc7eSAndroid Build Coastguard Worker static bool
nstime_monotonic_mock(void)25*1208bc7eSAndroid Build Coastguard Worker nstime_monotonic_mock(void) {
26*1208bc7eSAndroid Build Coastguard Worker 	return monotonic_mock;
27*1208bc7eSAndroid Build Coastguard Worker }
28*1208bc7eSAndroid Build Coastguard Worker 
29*1208bc7eSAndroid Build Coastguard Worker static bool
nstime_update_mock(nstime_t * time)30*1208bc7eSAndroid Build Coastguard Worker nstime_update_mock(nstime_t *time) {
31*1208bc7eSAndroid Build Coastguard Worker 	nupdates_mock++;
32*1208bc7eSAndroid Build Coastguard Worker 	if (monotonic_mock) {
33*1208bc7eSAndroid Build Coastguard Worker 		nstime_copy(time, &time_mock);
34*1208bc7eSAndroid Build Coastguard Worker 	}
35*1208bc7eSAndroid Build Coastguard Worker 	return !monotonic_mock;
36*1208bc7eSAndroid Build Coastguard Worker }
37*1208bc7eSAndroid Build Coastguard Worker 
38*1208bc7eSAndroid Build Coastguard Worker static unsigned
do_arena_create(ssize_t dirty_decay_ms,ssize_t muzzy_decay_ms)39*1208bc7eSAndroid Build Coastguard Worker do_arena_create(ssize_t dirty_decay_ms, ssize_t muzzy_decay_ms) {
40*1208bc7eSAndroid Build Coastguard Worker 	unsigned arena_ind;
41*1208bc7eSAndroid Build Coastguard Worker 	size_t sz = sizeof(unsigned);
42*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctl("arenas.create", (void *)&arena_ind, &sz, NULL, 0),
43*1208bc7eSAndroid Build Coastguard Worker 	    0, "Unexpected mallctl() failure");
44*1208bc7eSAndroid Build Coastguard Worker 	size_t mib[3];
45*1208bc7eSAndroid Build Coastguard Worker 	size_t miblen = sizeof(mib)/sizeof(size_t);
46*1208bc7eSAndroid Build Coastguard Worker 
47*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctlnametomib("arena.0.dirty_decay_ms", mib, &miblen),
48*1208bc7eSAndroid Build Coastguard Worker 	    0, "Unexpected mallctlnametomib() failure");
49*1208bc7eSAndroid Build Coastguard Worker 	mib[1] = (size_t)arena_ind;
50*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL,
51*1208bc7eSAndroid Build Coastguard Worker 	    (void *)&dirty_decay_ms, sizeof(dirty_decay_ms)), 0,
52*1208bc7eSAndroid Build Coastguard Worker 	    "Unexpected mallctlbymib() failure");
53*1208bc7eSAndroid Build Coastguard Worker 
54*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctlnametomib("arena.0.muzzy_decay_ms", mib, &miblen),
55*1208bc7eSAndroid Build Coastguard Worker 	    0, "Unexpected mallctlnametomib() failure");
56*1208bc7eSAndroid Build Coastguard Worker 	mib[1] = (size_t)arena_ind;
57*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL,
58*1208bc7eSAndroid Build Coastguard Worker 	    (void *)&muzzy_decay_ms, sizeof(muzzy_decay_ms)), 0,
59*1208bc7eSAndroid Build Coastguard Worker 	    "Unexpected mallctlbymib() failure");
60*1208bc7eSAndroid Build Coastguard Worker 
61*1208bc7eSAndroid Build Coastguard Worker 	return arena_ind;
62*1208bc7eSAndroid Build Coastguard Worker }
63*1208bc7eSAndroid Build Coastguard Worker 
64*1208bc7eSAndroid Build Coastguard Worker static void
do_arena_destroy(unsigned arena_ind)65*1208bc7eSAndroid Build Coastguard Worker do_arena_destroy(unsigned arena_ind) {
66*1208bc7eSAndroid Build Coastguard Worker 	size_t mib[3];
67*1208bc7eSAndroid Build Coastguard Worker 	size_t miblen = sizeof(mib)/sizeof(size_t);
68*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctlnametomib("arena.0.destroy", mib, &miblen), 0,
69*1208bc7eSAndroid Build Coastguard Worker 	    "Unexpected mallctlnametomib() failure");
70*1208bc7eSAndroid Build Coastguard Worker 	mib[1] = (size_t)arena_ind;
71*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
72*1208bc7eSAndroid Build Coastguard Worker 	    "Unexpected mallctlbymib() failure");
73*1208bc7eSAndroid Build Coastguard Worker }
74*1208bc7eSAndroid Build Coastguard Worker 
75*1208bc7eSAndroid Build Coastguard Worker void
do_epoch(void)76*1208bc7eSAndroid Build Coastguard Worker do_epoch(void) {
77*1208bc7eSAndroid Build Coastguard Worker 	uint64_t epoch = 1;
78*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctl("epoch", NULL, NULL, (void *)&epoch, sizeof(epoch)),
79*1208bc7eSAndroid Build Coastguard Worker 	    0, "Unexpected mallctl() failure");
80*1208bc7eSAndroid Build Coastguard Worker }
81*1208bc7eSAndroid Build Coastguard Worker 
82*1208bc7eSAndroid Build Coastguard Worker void
do_purge(unsigned arena_ind)83*1208bc7eSAndroid Build Coastguard Worker do_purge(unsigned arena_ind) {
84*1208bc7eSAndroid Build Coastguard Worker 	size_t mib[3];
85*1208bc7eSAndroid Build Coastguard Worker 	size_t miblen = sizeof(mib)/sizeof(size_t);
86*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctlnametomib("arena.0.purge", mib, &miblen), 0,
87*1208bc7eSAndroid Build Coastguard Worker 	    "Unexpected mallctlnametomib() failure");
88*1208bc7eSAndroid Build Coastguard Worker 	mib[1] = (size_t)arena_ind;
89*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
90*1208bc7eSAndroid Build Coastguard Worker 	    "Unexpected mallctlbymib() failure");
91*1208bc7eSAndroid Build Coastguard Worker }
92*1208bc7eSAndroid Build Coastguard Worker 
93*1208bc7eSAndroid Build Coastguard Worker void
do_decay(unsigned arena_ind)94*1208bc7eSAndroid Build Coastguard Worker do_decay(unsigned arena_ind) {
95*1208bc7eSAndroid Build Coastguard Worker 	size_t mib[3];
96*1208bc7eSAndroid Build Coastguard Worker 	size_t miblen = sizeof(mib)/sizeof(size_t);
97*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctlnametomib("arena.0.decay", mib, &miblen), 0,
98*1208bc7eSAndroid Build Coastguard Worker 	    "Unexpected mallctlnametomib() failure");
99*1208bc7eSAndroid Build Coastguard Worker 	mib[1] = (size_t)arena_ind;
100*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctlbymib(mib, miblen, NULL, NULL, NULL, 0), 0,
101*1208bc7eSAndroid Build Coastguard Worker 	    "Unexpected mallctlbymib() failure");
102*1208bc7eSAndroid Build Coastguard Worker }
103*1208bc7eSAndroid Build Coastguard Worker 
104*1208bc7eSAndroid Build Coastguard Worker static uint64_t
get_arena_npurge_impl(const char * mibname,unsigned arena_ind)105*1208bc7eSAndroid Build Coastguard Worker get_arena_npurge_impl(const char *mibname, unsigned arena_ind) {
106*1208bc7eSAndroid Build Coastguard Worker 	size_t mib[4];
107*1208bc7eSAndroid Build Coastguard Worker 	size_t miblen = sizeof(mib)/sizeof(size_t);
108*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctlnametomib(mibname, mib, &miblen), 0,
109*1208bc7eSAndroid Build Coastguard Worker 	    "Unexpected mallctlnametomib() failure");
110*1208bc7eSAndroid Build Coastguard Worker 	mib[2] = (size_t)arena_ind;
111*1208bc7eSAndroid Build Coastguard Worker 	uint64_t npurge = 0;
112*1208bc7eSAndroid Build Coastguard Worker 	size_t sz = sizeof(npurge);
113*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctlbymib(mib, miblen, (void *)&npurge, &sz, NULL, 0),
114*1208bc7eSAndroid Build Coastguard Worker 	    config_stats ? 0 : ENOENT, "Unexpected mallctlbymib() failure");
115*1208bc7eSAndroid Build Coastguard Worker 	return npurge;
116*1208bc7eSAndroid Build Coastguard Worker }
117*1208bc7eSAndroid Build Coastguard Worker 
118*1208bc7eSAndroid Build Coastguard Worker static uint64_t
get_arena_dirty_npurge(unsigned arena_ind)119*1208bc7eSAndroid Build Coastguard Worker get_arena_dirty_npurge(unsigned arena_ind) {
120*1208bc7eSAndroid Build Coastguard Worker 	do_epoch();
121*1208bc7eSAndroid Build Coastguard Worker 	return get_arena_npurge_impl("stats.arenas.0.dirty_npurge", arena_ind);
122*1208bc7eSAndroid Build Coastguard Worker }
123*1208bc7eSAndroid Build Coastguard Worker 
124*1208bc7eSAndroid Build Coastguard Worker static uint64_t
get_arena_muzzy_npurge(unsigned arena_ind)125*1208bc7eSAndroid Build Coastguard Worker get_arena_muzzy_npurge(unsigned arena_ind) {
126*1208bc7eSAndroid Build Coastguard Worker 	do_epoch();
127*1208bc7eSAndroid Build Coastguard Worker 	return get_arena_npurge_impl("stats.arenas.0.muzzy_npurge", arena_ind);
128*1208bc7eSAndroid Build Coastguard Worker }
129*1208bc7eSAndroid Build Coastguard Worker 
130*1208bc7eSAndroid Build Coastguard Worker static uint64_t
get_arena_npurge(unsigned arena_ind)131*1208bc7eSAndroid Build Coastguard Worker get_arena_npurge(unsigned arena_ind) {
132*1208bc7eSAndroid Build Coastguard Worker 	do_epoch();
133*1208bc7eSAndroid Build Coastguard Worker 	return get_arena_npurge_impl("stats.arenas.0.dirty_npurge", arena_ind) +
134*1208bc7eSAndroid Build Coastguard Worker 	    get_arena_npurge_impl("stats.arenas.0.muzzy_npurge", arena_ind);
135*1208bc7eSAndroid Build Coastguard Worker }
136*1208bc7eSAndroid Build Coastguard Worker 
137*1208bc7eSAndroid Build Coastguard Worker static size_t
get_arena_pdirty(unsigned arena_ind)138*1208bc7eSAndroid Build Coastguard Worker get_arena_pdirty(unsigned arena_ind) {
139*1208bc7eSAndroid Build Coastguard Worker 	do_epoch();
140*1208bc7eSAndroid Build Coastguard Worker 	size_t mib[4];
141*1208bc7eSAndroid Build Coastguard Worker 	size_t miblen = sizeof(mib)/sizeof(size_t);
142*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctlnametomib("stats.arenas.0.pdirty", mib, &miblen), 0,
143*1208bc7eSAndroid Build Coastguard Worker 	    "Unexpected mallctlnametomib() failure");
144*1208bc7eSAndroid Build Coastguard Worker 	mib[2] = (size_t)arena_ind;
145*1208bc7eSAndroid Build Coastguard Worker 	size_t pdirty;
146*1208bc7eSAndroid Build Coastguard Worker 	size_t sz = sizeof(pdirty);
147*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctlbymib(mib, miblen, (void *)&pdirty, &sz, NULL, 0), 0,
148*1208bc7eSAndroid Build Coastguard Worker 	    "Unexpected mallctlbymib() failure");
149*1208bc7eSAndroid Build Coastguard Worker 	return pdirty;
150*1208bc7eSAndroid Build Coastguard Worker }
151*1208bc7eSAndroid Build Coastguard Worker 
152*1208bc7eSAndroid Build Coastguard Worker static size_t
get_arena_pmuzzy(unsigned arena_ind)153*1208bc7eSAndroid Build Coastguard Worker get_arena_pmuzzy(unsigned arena_ind) {
154*1208bc7eSAndroid Build Coastguard Worker 	do_epoch();
155*1208bc7eSAndroid Build Coastguard Worker 	size_t mib[4];
156*1208bc7eSAndroid Build Coastguard Worker 	size_t miblen = sizeof(mib)/sizeof(size_t);
157*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctlnametomib("stats.arenas.0.pmuzzy", mib, &miblen), 0,
158*1208bc7eSAndroid Build Coastguard Worker 	    "Unexpected mallctlnametomib() failure");
159*1208bc7eSAndroid Build Coastguard Worker 	mib[2] = (size_t)arena_ind;
160*1208bc7eSAndroid Build Coastguard Worker 	size_t pmuzzy;
161*1208bc7eSAndroid Build Coastguard Worker 	size_t sz = sizeof(pmuzzy);
162*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctlbymib(mib, miblen, (void *)&pmuzzy, &sz, NULL, 0), 0,
163*1208bc7eSAndroid Build Coastguard Worker 	    "Unexpected mallctlbymib() failure");
164*1208bc7eSAndroid Build Coastguard Worker 	return pmuzzy;
165*1208bc7eSAndroid Build Coastguard Worker }
166*1208bc7eSAndroid Build Coastguard Worker 
167*1208bc7eSAndroid Build Coastguard Worker static void *
do_mallocx(size_t size,int flags)168*1208bc7eSAndroid Build Coastguard Worker do_mallocx(size_t size, int flags) {
169*1208bc7eSAndroid Build Coastguard Worker 	void *p = mallocx(size, flags);
170*1208bc7eSAndroid Build Coastguard Worker 	assert_ptr_not_null(p, "Unexpected mallocx() failure");
171*1208bc7eSAndroid Build Coastguard Worker 	return p;
172*1208bc7eSAndroid Build Coastguard Worker }
173*1208bc7eSAndroid Build Coastguard Worker 
174*1208bc7eSAndroid Build Coastguard Worker static void
generate_dirty(unsigned arena_ind,size_t size)175*1208bc7eSAndroid Build Coastguard Worker generate_dirty(unsigned arena_ind, size_t size) {
176*1208bc7eSAndroid Build Coastguard Worker 	int flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE;
177*1208bc7eSAndroid Build Coastguard Worker 	void *p = do_mallocx(size, flags);
178*1208bc7eSAndroid Build Coastguard Worker 	dallocx(p, flags);
179*1208bc7eSAndroid Build Coastguard Worker }
180*1208bc7eSAndroid Build Coastguard Worker 
TEST_BEGIN(test_decay_ticks)181*1208bc7eSAndroid Build Coastguard Worker TEST_BEGIN(test_decay_ticks) {
182*1208bc7eSAndroid Build Coastguard Worker 	test_skip_if(check_background_thread_enabled());
183*1208bc7eSAndroid Build Coastguard Worker 	test_skip_if(known_failure_on_android);
184*1208bc7eSAndroid Build Coastguard Worker 
185*1208bc7eSAndroid Build Coastguard Worker 	ticker_t *decay_ticker;
186*1208bc7eSAndroid Build Coastguard Worker 	unsigned tick0, tick1, arena_ind;
187*1208bc7eSAndroid Build Coastguard Worker 	size_t sz, large0;
188*1208bc7eSAndroid Build Coastguard Worker 	void *p;
189*1208bc7eSAndroid Build Coastguard Worker 
190*1208bc7eSAndroid Build Coastguard Worker 	sz = sizeof(size_t);
191*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctl("arenas.lextent.0.size", (void *)&large0, &sz, NULL,
192*1208bc7eSAndroid Build Coastguard Worker 	    0), 0, "Unexpected mallctl failure");
193*1208bc7eSAndroid Build Coastguard Worker 
194*1208bc7eSAndroid Build Coastguard Worker 	/* Set up a manually managed arena for test. */
195*1208bc7eSAndroid Build Coastguard Worker 	arena_ind = do_arena_create(0, 0);
196*1208bc7eSAndroid Build Coastguard Worker 
197*1208bc7eSAndroid Build Coastguard Worker 	/* Migrate to the new arena, and get the ticker. */
198*1208bc7eSAndroid Build Coastguard Worker 	unsigned old_arena_ind;
199*1208bc7eSAndroid Build Coastguard Worker 	size_t sz_arena_ind = sizeof(old_arena_ind);
200*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctl("thread.arena", (void *)&old_arena_ind,
201*1208bc7eSAndroid Build Coastguard Worker 	    &sz_arena_ind, (void *)&arena_ind, sizeof(arena_ind)), 0,
202*1208bc7eSAndroid Build Coastguard Worker 	    "Unexpected mallctl() failure");
203*1208bc7eSAndroid Build Coastguard Worker 	decay_ticker = decay_ticker_get(tsd_fetch(), arena_ind);
204*1208bc7eSAndroid Build Coastguard Worker 	assert_ptr_not_null(decay_ticker,
205*1208bc7eSAndroid Build Coastguard Worker 	    "Unexpected failure getting decay ticker");
206*1208bc7eSAndroid Build Coastguard Worker 
207*1208bc7eSAndroid Build Coastguard Worker 	/*
208*1208bc7eSAndroid Build Coastguard Worker 	 * Test the standard APIs using a large size class, since we can't
209*1208bc7eSAndroid Build Coastguard Worker 	 * control tcache interactions for small size classes (except by
210*1208bc7eSAndroid Build Coastguard Worker 	 * completely disabling tcache for the entire test program).
211*1208bc7eSAndroid Build Coastguard Worker 	 */
212*1208bc7eSAndroid Build Coastguard Worker 
213*1208bc7eSAndroid Build Coastguard Worker 	/* malloc(). */
214*1208bc7eSAndroid Build Coastguard Worker 	tick0 = ticker_read(decay_ticker);
215*1208bc7eSAndroid Build Coastguard Worker 	p = malloc(large0);
216*1208bc7eSAndroid Build Coastguard Worker 	assert_ptr_not_null(p, "Unexpected malloc() failure");
217*1208bc7eSAndroid Build Coastguard Worker 	tick1 = ticker_read(decay_ticker);
218*1208bc7eSAndroid Build Coastguard Worker 	assert_u32_ne(tick1, tick0, "Expected ticker to tick during malloc()");
219*1208bc7eSAndroid Build Coastguard Worker 	/* free(). */
220*1208bc7eSAndroid Build Coastguard Worker 	tick0 = ticker_read(decay_ticker);
221*1208bc7eSAndroid Build Coastguard Worker 	free(p);
222*1208bc7eSAndroid Build Coastguard Worker 	tick1 = ticker_read(decay_ticker);
223*1208bc7eSAndroid Build Coastguard Worker 	assert_u32_ne(tick1, tick0, "Expected ticker to tick during free()");
224*1208bc7eSAndroid Build Coastguard Worker 
225*1208bc7eSAndroid Build Coastguard Worker 	/* calloc(). */
226*1208bc7eSAndroid Build Coastguard Worker 	tick0 = ticker_read(decay_ticker);
227*1208bc7eSAndroid Build Coastguard Worker 	p = calloc(1, large0);
228*1208bc7eSAndroid Build Coastguard Worker 	assert_ptr_not_null(p, "Unexpected calloc() failure");
229*1208bc7eSAndroid Build Coastguard Worker 	tick1 = ticker_read(decay_ticker);
230*1208bc7eSAndroid Build Coastguard Worker 	assert_u32_ne(tick1, tick0, "Expected ticker to tick during calloc()");
231*1208bc7eSAndroid Build Coastguard Worker 	free(p);
232*1208bc7eSAndroid Build Coastguard Worker 
233*1208bc7eSAndroid Build Coastguard Worker 	/* posix_memalign(). */
234*1208bc7eSAndroid Build Coastguard Worker 	tick0 = ticker_read(decay_ticker);
235*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(posix_memalign(&p, sizeof(size_t), large0), 0,
236*1208bc7eSAndroid Build Coastguard Worker 	    "Unexpected posix_memalign() failure");
237*1208bc7eSAndroid Build Coastguard Worker 	tick1 = ticker_read(decay_ticker);
238*1208bc7eSAndroid Build Coastguard Worker 	assert_u32_ne(tick1, tick0,
239*1208bc7eSAndroid Build Coastguard Worker 	    "Expected ticker to tick during posix_memalign()");
240*1208bc7eSAndroid Build Coastguard Worker 	free(p);
241*1208bc7eSAndroid Build Coastguard Worker 
242*1208bc7eSAndroid Build Coastguard Worker 	/* aligned_alloc(). */
243*1208bc7eSAndroid Build Coastguard Worker 	tick0 = ticker_read(decay_ticker);
244*1208bc7eSAndroid Build Coastguard Worker 	p = aligned_alloc(sizeof(size_t), large0);
245*1208bc7eSAndroid Build Coastguard Worker 	assert_ptr_not_null(p, "Unexpected aligned_alloc() failure");
246*1208bc7eSAndroid Build Coastguard Worker 	tick1 = ticker_read(decay_ticker);
247*1208bc7eSAndroid Build Coastguard Worker 	assert_u32_ne(tick1, tick0,
248*1208bc7eSAndroid Build Coastguard Worker 	    "Expected ticker to tick during aligned_alloc()");
249*1208bc7eSAndroid Build Coastguard Worker 	free(p);
250*1208bc7eSAndroid Build Coastguard Worker 
251*1208bc7eSAndroid Build Coastguard Worker 	/* realloc(). */
252*1208bc7eSAndroid Build Coastguard Worker 	/* Allocate. */
253*1208bc7eSAndroid Build Coastguard Worker 	tick0 = ticker_read(decay_ticker);
254*1208bc7eSAndroid Build Coastguard Worker 	p = realloc(NULL, large0);
255*1208bc7eSAndroid Build Coastguard Worker 	assert_ptr_not_null(p, "Unexpected realloc() failure");
256*1208bc7eSAndroid Build Coastguard Worker 	tick1 = ticker_read(decay_ticker);
257*1208bc7eSAndroid Build Coastguard Worker 	assert_u32_ne(tick1, tick0, "Expected ticker to tick during realloc()");
258*1208bc7eSAndroid Build Coastguard Worker 	/* Reallocate. */
259*1208bc7eSAndroid Build Coastguard Worker 	tick0 = ticker_read(decay_ticker);
260*1208bc7eSAndroid Build Coastguard Worker 	p = realloc(p, large0);
261*1208bc7eSAndroid Build Coastguard Worker 	assert_ptr_not_null(p, "Unexpected realloc() failure");
262*1208bc7eSAndroid Build Coastguard Worker 	tick1 = ticker_read(decay_ticker);
263*1208bc7eSAndroid Build Coastguard Worker 	assert_u32_ne(tick1, tick0, "Expected ticker to tick during realloc()");
264*1208bc7eSAndroid Build Coastguard Worker 	/* Deallocate. */
265*1208bc7eSAndroid Build Coastguard Worker 	tick0 = ticker_read(decay_ticker);
266*1208bc7eSAndroid Build Coastguard Worker 	realloc(p, 0);
267*1208bc7eSAndroid Build Coastguard Worker 	tick1 = ticker_read(decay_ticker);
268*1208bc7eSAndroid Build Coastguard Worker 	assert_u32_ne(tick1, tick0, "Expected ticker to tick during realloc()");
269*1208bc7eSAndroid Build Coastguard Worker 
270*1208bc7eSAndroid Build Coastguard Worker 	/*
271*1208bc7eSAndroid Build Coastguard Worker 	 * Test the *allocx() APIs using large and small size classes, with
272*1208bc7eSAndroid Build Coastguard Worker 	 * tcache explicitly disabled.
273*1208bc7eSAndroid Build Coastguard Worker 	 */
274*1208bc7eSAndroid Build Coastguard Worker 	{
275*1208bc7eSAndroid Build Coastguard Worker 		unsigned i;
276*1208bc7eSAndroid Build Coastguard Worker 		size_t allocx_sizes[2];
277*1208bc7eSAndroid Build Coastguard Worker 		allocx_sizes[0] = large0;
278*1208bc7eSAndroid Build Coastguard Worker 		allocx_sizes[1] = 1;
279*1208bc7eSAndroid Build Coastguard Worker 
280*1208bc7eSAndroid Build Coastguard Worker 		for (i = 0; i < sizeof(allocx_sizes) / sizeof(size_t); i++) {
281*1208bc7eSAndroid Build Coastguard Worker 			sz = allocx_sizes[i];
282*1208bc7eSAndroid Build Coastguard Worker 
283*1208bc7eSAndroid Build Coastguard Worker 			/* mallocx(). */
284*1208bc7eSAndroid Build Coastguard Worker 			tick0 = ticker_read(decay_ticker);
285*1208bc7eSAndroid Build Coastguard Worker 			p = mallocx(sz, MALLOCX_TCACHE_NONE);
286*1208bc7eSAndroid Build Coastguard Worker 			assert_ptr_not_null(p, "Unexpected mallocx() failure");
287*1208bc7eSAndroid Build Coastguard Worker 			tick1 = ticker_read(decay_ticker);
288*1208bc7eSAndroid Build Coastguard Worker 			assert_u32_ne(tick1, tick0,
289*1208bc7eSAndroid Build Coastguard Worker 			    "Expected ticker to tick during mallocx() (sz=%zu)",
290*1208bc7eSAndroid Build Coastguard Worker 			    sz);
291*1208bc7eSAndroid Build Coastguard Worker 			/* rallocx(). */
292*1208bc7eSAndroid Build Coastguard Worker 			tick0 = ticker_read(decay_ticker);
293*1208bc7eSAndroid Build Coastguard Worker 			p = rallocx(p, sz, MALLOCX_TCACHE_NONE);
294*1208bc7eSAndroid Build Coastguard Worker 			assert_ptr_not_null(p, "Unexpected rallocx() failure");
295*1208bc7eSAndroid Build Coastguard Worker 			tick1 = ticker_read(decay_ticker);
296*1208bc7eSAndroid Build Coastguard Worker 			assert_u32_ne(tick1, tick0,
297*1208bc7eSAndroid Build Coastguard Worker 			    "Expected ticker to tick during rallocx() (sz=%zu)",
298*1208bc7eSAndroid Build Coastguard Worker 			    sz);
299*1208bc7eSAndroid Build Coastguard Worker 			/* xallocx(). */
300*1208bc7eSAndroid Build Coastguard Worker 			tick0 = ticker_read(decay_ticker);
301*1208bc7eSAndroid Build Coastguard Worker 			xallocx(p, sz, 0, MALLOCX_TCACHE_NONE);
302*1208bc7eSAndroid Build Coastguard Worker 			tick1 = ticker_read(decay_ticker);
303*1208bc7eSAndroid Build Coastguard Worker 			assert_u32_ne(tick1, tick0,
304*1208bc7eSAndroid Build Coastguard Worker 			    "Expected ticker to tick during xallocx() (sz=%zu)",
305*1208bc7eSAndroid Build Coastguard Worker 			    sz);
306*1208bc7eSAndroid Build Coastguard Worker 			/* dallocx(). */
307*1208bc7eSAndroid Build Coastguard Worker 			tick0 = ticker_read(decay_ticker);
308*1208bc7eSAndroid Build Coastguard Worker 			dallocx(p, MALLOCX_TCACHE_NONE);
309*1208bc7eSAndroid Build Coastguard Worker 			tick1 = ticker_read(decay_ticker);
310*1208bc7eSAndroid Build Coastguard Worker 			assert_u32_ne(tick1, tick0,
311*1208bc7eSAndroid Build Coastguard Worker 			    "Expected ticker to tick during dallocx() (sz=%zu)",
312*1208bc7eSAndroid Build Coastguard Worker 			    sz);
313*1208bc7eSAndroid Build Coastguard Worker 			/* sdallocx(). */
314*1208bc7eSAndroid Build Coastguard Worker 			p = mallocx(sz, MALLOCX_TCACHE_NONE);
315*1208bc7eSAndroid Build Coastguard Worker 			assert_ptr_not_null(p, "Unexpected mallocx() failure");
316*1208bc7eSAndroid Build Coastguard Worker 			tick0 = ticker_read(decay_ticker);
317*1208bc7eSAndroid Build Coastguard Worker 			sdallocx(p, sz, MALLOCX_TCACHE_NONE);
318*1208bc7eSAndroid Build Coastguard Worker 			tick1 = ticker_read(decay_ticker);
319*1208bc7eSAndroid Build Coastguard Worker 			assert_u32_ne(tick1, tick0,
320*1208bc7eSAndroid Build Coastguard Worker 			    "Expected ticker to tick during sdallocx() "
321*1208bc7eSAndroid Build Coastguard Worker 			    "(sz=%zu)", sz);
322*1208bc7eSAndroid Build Coastguard Worker 		}
323*1208bc7eSAndroid Build Coastguard Worker 	}
324*1208bc7eSAndroid Build Coastguard Worker 
325*1208bc7eSAndroid Build Coastguard Worker 	/*
326*1208bc7eSAndroid Build Coastguard Worker 	 * Test tcache fill/flush interactions for large and small size classes,
327*1208bc7eSAndroid Build Coastguard Worker 	 * using an explicit tcache.
328*1208bc7eSAndroid Build Coastguard Worker 	 */
329*1208bc7eSAndroid Build Coastguard Worker 	unsigned tcache_ind, i;
330*1208bc7eSAndroid Build Coastguard Worker 	size_t tcache_sizes[2];
331*1208bc7eSAndroid Build Coastguard Worker 	tcache_sizes[0] = large0;
332*1208bc7eSAndroid Build Coastguard Worker 	tcache_sizes[1] = 1;
333*1208bc7eSAndroid Build Coastguard Worker 
334*1208bc7eSAndroid Build Coastguard Worker 	size_t tcache_max, sz_tcache_max;
335*1208bc7eSAndroid Build Coastguard Worker 	sz_tcache_max = sizeof(tcache_max);
336*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctl("arenas.tcache_max", (void *)&tcache_max,
337*1208bc7eSAndroid Build Coastguard Worker 	    &sz_tcache_max, NULL, 0), 0, "Unexpected mallctl() failure");
338*1208bc7eSAndroid Build Coastguard Worker 
339*1208bc7eSAndroid Build Coastguard Worker 	sz = sizeof(unsigned);
340*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctl("tcache.create", (void *)&tcache_ind, &sz,
341*1208bc7eSAndroid Build Coastguard Worker 	    NULL, 0), 0, "Unexpected mallctl failure");
342*1208bc7eSAndroid Build Coastguard Worker 
343*1208bc7eSAndroid Build Coastguard Worker 	for (i = 0; i < sizeof(tcache_sizes) / sizeof(size_t); i++) {
344*1208bc7eSAndroid Build Coastguard Worker 		sz = tcache_sizes[i];
345*1208bc7eSAndroid Build Coastguard Worker 
346*1208bc7eSAndroid Build Coastguard Worker 		/* tcache fill. */
347*1208bc7eSAndroid Build Coastguard Worker 		tick0 = ticker_read(decay_ticker);
348*1208bc7eSAndroid Build Coastguard Worker 		p = mallocx(sz, MALLOCX_TCACHE(tcache_ind));
349*1208bc7eSAndroid Build Coastguard Worker 		assert_ptr_not_null(p, "Unexpected mallocx() failure");
350*1208bc7eSAndroid Build Coastguard Worker 		tick1 = ticker_read(decay_ticker);
351*1208bc7eSAndroid Build Coastguard Worker 		assert_u32_ne(tick1, tick0,
352*1208bc7eSAndroid Build Coastguard Worker 		    "Expected ticker to tick during tcache fill "
353*1208bc7eSAndroid Build Coastguard Worker 		    "(sz=%zu)", sz);
354*1208bc7eSAndroid Build Coastguard Worker 		/* tcache flush. */
355*1208bc7eSAndroid Build Coastguard Worker 		dallocx(p, MALLOCX_TCACHE(tcache_ind));
356*1208bc7eSAndroid Build Coastguard Worker 		tick0 = ticker_read(decay_ticker);
357*1208bc7eSAndroid Build Coastguard Worker 		assert_d_eq(mallctl("tcache.flush", NULL, NULL,
358*1208bc7eSAndroid Build Coastguard Worker 		    (void *)&tcache_ind, sizeof(unsigned)), 0,
359*1208bc7eSAndroid Build Coastguard Worker 		    "Unexpected mallctl failure");
360*1208bc7eSAndroid Build Coastguard Worker 		tick1 = ticker_read(decay_ticker);
361*1208bc7eSAndroid Build Coastguard Worker 
362*1208bc7eSAndroid Build Coastguard Worker 		/* Will only tick if it's in tcache. */
363*1208bc7eSAndroid Build Coastguard Worker 		if (sz <= tcache_max) {
364*1208bc7eSAndroid Build Coastguard Worker 			assert_u32_ne(tick1, tick0,
365*1208bc7eSAndroid Build Coastguard Worker 			    "Expected ticker to tick during tcache "
366*1208bc7eSAndroid Build Coastguard Worker 			    "flush (sz=%zu)", sz);
367*1208bc7eSAndroid Build Coastguard Worker 		} else {
368*1208bc7eSAndroid Build Coastguard Worker 			assert_u32_eq(tick1, tick0,
369*1208bc7eSAndroid Build Coastguard Worker 			    "Unexpected ticker tick during tcache "
370*1208bc7eSAndroid Build Coastguard Worker 			    "flush (sz=%zu)", sz);
371*1208bc7eSAndroid Build Coastguard Worker 		}
372*1208bc7eSAndroid Build Coastguard Worker 	}
373*1208bc7eSAndroid Build Coastguard Worker }
374*1208bc7eSAndroid Build Coastguard Worker TEST_END
375*1208bc7eSAndroid Build Coastguard Worker 
376*1208bc7eSAndroid Build Coastguard Worker static void
decay_ticker_helper(unsigned arena_ind,int flags,bool dirty,ssize_t dt,uint64_t dirty_npurge0,uint64_t muzzy_npurge0,bool terminate_asap)377*1208bc7eSAndroid Build Coastguard Worker decay_ticker_helper(unsigned arena_ind, int flags, bool dirty, ssize_t dt,
378*1208bc7eSAndroid Build Coastguard Worker     uint64_t dirty_npurge0, uint64_t muzzy_npurge0, bool terminate_asap) {
379*1208bc7eSAndroid Build Coastguard Worker #define NINTERVALS 101
380*1208bc7eSAndroid Build Coastguard Worker 	nstime_t time, update_interval, decay_ms, deadline;
381*1208bc7eSAndroid Build Coastguard Worker 
382*1208bc7eSAndroid Build Coastguard Worker 	nstime_init(&time, 0);
383*1208bc7eSAndroid Build Coastguard Worker 	nstime_update(&time);
384*1208bc7eSAndroid Build Coastguard Worker 
385*1208bc7eSAndroid Build Coastguard Worker 	nstime_init2(&decay_ms, dt, 0);
386*1208bc7eSAndroid Build Coastguard Worker 	nstime_copy(&deadline, &time);
387*1208bc7eSAndroid Build Coastguard Worker 	nstime_add(&deadline, &decay_ms);
388*1208bc7eSAndroid Build Coastguard Worker 
389*1208bc7eSAndroid Build Coastguard Worker 	nstime_init2(&update_interval, dt, 0);
390*1208bc7eSAndroid Build Coastguard Worker 	nstime_idivide(&update_interval, NINTERVALS);
391*1208bc7eSAndroid Build Coastguard Worker 
392*1208bc7eSAndroid Build Coastguard Worker 	/*
393*1208bc7eSAndroid Build Coastguard Worker 	 * Keep q's slab from being deallocated during the looping below.  If a
394*1208bc7eSAndroid Build Coastguard Worker 	 * cached slab were to repeatedly come and go during looping, it could
395*1208bc7eSAndroid Build Coastguard Worker 	 * prevent the decay backlog ever becoming empty.
396*1208bc7eSAndroid Build Coastguard Worker 	 */
397*1208bc7eSAndroid Build Coastguard Worker 	void *p = do_mallocx(1, flags);
398*1208bc7eSAndroid Build Coastguard Worker 	uint64_t dirty_npurge1, muzzy_npurge1;
399*1208bc7eSAndroid Build Coastguard Worker 	do {
400*1208bc7eSAndroid Build Coastguard Worker 		for (unsigned i = 0; i < DECAY_NTICKS_PER_UPDATE / 2;
401*1208bc7eSAndroid Build Coastguard Worker 		    i++) {
402*1208bc7eSAndroid Build Coastguard Worker 			void *q = do_mallocx(1, flags);
403*1208bc7eSAndroid Build Coastguard Worker 			dallocx(q, flags);
404*1208bc7eSAndroid Build Coastguard Worker 		}
405*1208bc7eSAndroid Build Coastguard Worker 		dirty_npurge1 = get_arena_dirty_npurge(arena_ind);
406*1208bc7eSAndroid Build Coastguard Worker 		muzzy_npurge1 = get_arena_muzzy_npurge(arena_ind);
407*1208bc7eSAndroid Build Coastguard Worker 
408*1208bc7eSAndroid Build Coastguard Worker 		nstime_add(&time_mock, &update_interval);
409*1208bc7eSAndroid Build Coastguard Worker 		nstime_update(&time);
410*1208bc7eSAndroid Build Coastguard Worker 	} while (nstime_compare(&time, &deadline) <= 0 && ((dirty_npurge1 ==
411*1208bc7eSAndroid Build Coastguard Worker 	    dirty_npurge0 && muzzy_npurge1 == muzzy_npurge0) ||
412*1208bc7eSAndroid Build Coastguard Worker 	    !terminate_asap));
413*1208bc7eSAndroid Build Coastguard Worker 	dallocx(p, flags);
414*1208bc7eSAndroid Build Coastguard Worker 
415*1208bc7eSAndroid Build Coastguard Worker 	if (config_stats) {
416*1208bc7eSAndroid Build Coastguard Worker 		assert_u64_gt(dirty_npurge1 + muzzy_npurge1, dirty_npurge0 +
417*1208bc7eSAndroid Build Coastguard Worker 		    muzzy_npurge0, "Expected purging to occur");
418*1208bc7eSAndroid Build Coastguard Worker 	}
419*1208bc7eSAndroid Build Coastguard Worker #undef NINTERVALS
420*1208bc7eSAndroid Build Coastguard Worker }
421*1208bc7eSAndroid Build Coastguard Worker 
TEST_BEGIN(test_decay_ticker)422*1208bc7eSAndroid Build Coastguard Worker TEST_BEGIN(test_decay_ticker) {
423*1208bc7eSAndroid Build Coastguard Worker 	test_skip_if(check_background_thread_enabled());
424*1208bc7eSAndroid Build Coastguard Worker #define NPS 2048
425*1208bc7eSAndroid Build Coastguard Worker 	ssize_t ddt = opt_dirty_decay_ms;
426*1208bc7eSAndroid Build Coastguard Worker 	ssize_t mdt = opt_muzzy_decay_ms;
427*1208bc7eSAndroid Build Coastguard Worker 	unsigned arena_ind = do_arena_create(ddt, mdt);
428*1208bc7eSAndroid Build Coastguard Worker 	int flags = (MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE);
429*1208bc7eSAndroid Build Coastguard Worker 	void *ps[NPS];
430*1208bc7eSAndroid Build Coastguard Worker 	size_t large;
431*1208bc7eSAndroid Build Coastguard Worker 
432*1208bc7eSAndroid Build Coastguard Worker 	/*
433*1208bc7eSAndroid Build Coastguard Worker 	 * Allocate a bunch of large objects, pause the clock, deallocate every
434*1208bc7eSAndroid Build Coastguard Worker 	 * other object (to fragment virtual memory), restore the clock, then
435*1208bc7eSAndroid Build Coastguard Worker 	 * [md]allocx() in a tight loop while advancing time rapidly to verify
436*1208bc7eSAndroid Build Coastguard Worker 	 * the ticker triggers purging.
437*1208bc7eSAndroid Build Coastguard Worker 	 */
438*1208bc7eSAndroid Build Coastguard Worker 
439*1208bc7eSAndroid Build Coastguard Worker 	size_t tcache_max;
440*1208bc7eSAndroid Build Coastguard Worker 	size_t sz = sizeof(size_t);
441*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctl("arenas.tcache_max", (void *)&tcache_max, &sz, NULL,
442*1208bc7eSAndroid Build Coastguard Worker 	    0), 0, "Unexpected mallctl failure");
443*1208bc7eSAndroid Build Coastguard Worker 	large = nallocx(tcache_max + 1, flags);
444*1208bc7eSAndroid Build Coastguard Worker 
445*1208bc7eSAndroid Build Coastguard Worker 	do_purge(arena_ind);
446*1208bc7eSAndroid Build Coastguard Worker 	uint64_t dirty_npurge0 = get_arena_dirty_npurge(arena_ind);
447*1208bc7eSAndroid Build Coastguard Worker 	uint64_t muzzy_npurge0 = get_arena_muzzy_npurge(arena_ind);
448*1208bc7eSAndroid Build Coastguard Worker 
449*1208bc7eSAndroid Build Coastguard Worker 	for (unsigned i = 0; i < NPS; i++) {
450*1208bc7eSAndroid Build Coastguard Worker 		ps[i] = do_mallocx(large, flags);
451*1208bc7eSAndroid Build Coastguard Worker 	}
452*1208bc7eSAndroid Build Coastguard Worker 
453*1208bc7eSAndroid Build Coastguard Worker 	nupdates_mock = 0;
454*1208bc7eSAndroid Build Coastguard Worker 	nstime_init(&time_mock, 0);
455*1208bc7eSAndroid Build Coastguard Worker 	nstime_update(&time_mock);
456*1208bc7eSAndroid Build Coastguard Worker 	monotonic_mock = true;
457*1208bc7eSAndroid Build Coastguard Worker 
458*1208bc7eSAndroid Build Coastguard Worker 	nstime_monotonic_orig = nstime_monotonic;
459*1208bc7eSAndroid Build Coastguard Worker 	nstime_update_orig = nstime_update;
460*1208bc7eSAndroid Build Coastguard Worker 	nstime_monotonic = nstime_monotonic_mock;
461*1208bc7eSAndroid Build Coastguard Worker 	nstime_update = nstime_update_mock;
462*1208bc7eSAndroid Build Coastguard Worker 
463*1208bc7eSAndroid Build Coastguard Worker 	for (unsigned i = 0; i < NPS; i += 2) {
464*1208bc7eSAndroid Build Coastguard Worker 		dallocx(ps[i], flags);
465*1208bc7eSAndroid Build Coastguard Worker 		unsigned nupdates0 = nupdates_mock;
466*1208bc7eSAndroid Build Coastguard Worker 		do_decay(arena_ind);
467*1208bc7eSAndroid Build Coastguard Worker 		assert_u_gt(nupdates_mock, nupdates0,
468*1208bc7eSAndroid Build Coastguard Worker 		    "Expected nstime_update() to be called");
469*1208bc7eSAndroid Build Coastguard Worker 	}
470*1208bc7eSAndroid Build Coastguard Worker 
471*1208bc7eSAndroid Build Coastguard Worker 	decay_ticker_helper(arena_ind, flags, true, ddt, dirty_npurge0,
472*1208bc7eSAndroid Build Coastguard Worker 	    muzzy_npurge0, true);
473*1208bc7eSAndroid Build Coastguard Worker 	decay_ticker_helper(arena_ind, flags, false, ddt+mdt, dirty_npurge0,
474*1208bc7eSAndroid Build Coastguard Worker 	    muzzy_npurge0, false);
475*1208bc7eSAndroid Build Coastguard Worker 
476*1208bc7eSAndroid Build Coastguard Worker 	do_arena_destroy(arena_ind);
477*1208bc7eSAndroid Build Coastguard Worker 
478*1208bc7eSAndroid Build Coastguard Worker 	nstime_monotonic = nstime_monotonic_orig;
479*1208bc7eSAndroid Build Coastguard Worker 	nstime_update = nstime_update_orig;
480*1208bc7eSAndroid Build Coastguard Worker #undef NPS
481*1208bc7eSAndroid Build Coastguard Worker }
482*1208bc7eSAndroid Build Coastguard Worker TEST_END
483*1208bc7eSAndroid Build Coastguard Worker 
TEST_BEGIN(test_decay_nonmonotonic)484*1208bc7eSAndroid Build Coastguard Worker TEST_BEGIN(test_decay_nonmonotonic) {
485*1208bc7eSAndroid Build Coastguard Worker 	test_skip_if(check_background_thread_enabled());
486*1208bc7eSAndroid Build Coastguard Worker #define NPS (SMOOTHSTEP_NSTEPS + 1)
487*1208bc7eSAndroid Build Coastguard Worker 	int flags = (MALLOCX_ARENA(0) | MALLOCX_TCACHE_NONE);
488*1208bc7eSAndroid Build Coastguard Worker 	void *ps[NPS];
489*1208bc7eSAndroid Build Coastguard Worker 	uint64_t npurge0 = 0;
490*1208bc7eSAndroid Build Coastguard Worker 	uint64_t npurge1 = 0;
491*1208bc7eSAndroid Build Coastguard Worker 	size_t sz, large0;
492*1208bc7eSAndroid Build Coastguard Worker 	unsigned i, nupdates0;
493*1208bc7eSAndroid Build Coastguard Worker 
494*1208bc7eSAndroid Build Coastguard Worker 	sz = sizeof(size_t);
495*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctl("arenas.lextent.0.size", (void *)&large0, &sz, NULL,
496*1208bc7eSAndroid Build Coastguard Worker 	    0), 0, "Unexpected mallctl failure");
497*1208bc7eSAndroid Build Coastguard Worker 
498*1208bc7eSAndroid Build Coastguard Worker 	assert_d_eq(mallctl("arena.0.purge", NULL, NULL, NULL, 0), 0,
499*1208bc7eSAndroid Build Coastguard Worker 	    "Unexpected mallctl failure");
500*1208bc7eSAndroid Build Coastguard Worker 	do_epoch();
501*1208bc7eSAndroid Build Coastguard Worker 	sz = sizeof(uint64_t);
502*1208bc7eSAndroid Build Coastguard Worker 	npurge0 = get_arena_npurge(0);
503*1208bc7eSAndroid Build Coastguard Worker 
504*1208bc7eSAndroid Build Coastguard Worker 	nupdates_mock = 0;
505*1208bc7eSAndroid Build Coastguard Worker 	nstime_init(&time_mock, 0);
506*1208bc7eSAndroid Build Coastguard Worker 	nstime_update(&time_mock);
507*1208bc7eSAndroid Build Coastguard Worker 	monotonic_mock = false;
508*1208bc7eSAndroid Build Coastguard Worker 
509*1208bc7eSAndroid Build Coastguard Worker 	nstime_monotonic_orig = nstime_monotonic;
510*1208bc7eSAndroid Build Coastguard Worker 	nstime_update_orig = nstime_update;
511*1208bc7eSAndroid Build Coastguard Worker 	nstime_monotonic = nstime_monotonic_mock;
512*1208bc7eSAndroid Build Coastguard Worker 	nstime_update = nstime_update_mock;
513*1208bc7eSAndroid Build Coastguard Worker 
514*1208bc7eSAndroid Build Coastguard Worker 	for (i = 0; i < NPS; i++) {
515*1208bc7eSAndroid Build Coastguard Worker 		ps[i] = mallocx(large0, flags);
516*1208bc7eSAndroid Build Coastguard Worker 		assert_ptr_not_null(ps[i], "Unexpected mallocx() failure");
517*1208bc7eSAndroid Build Coastguard Worker 	}
518*1208bc7eSAndroid Build Coastguard Worker 
519*1208bc7eSAndroid Build Coastguard Worker 	for (i = 0; i < NPS; i++) {
520*1208bc7eSAndroid Build Coastguard Worker 		dallocx(ps[i], flags);
521*1208bc7eSAndroid Build Coastguard Worker 		nupdates0 = nupdates_mock;
522*1208bc7eSAndroid Build Coastguard Worker 		assert_d_eq(mallctl("arena.0.decay", NULL, NULL, NULL, 0), 0,
523*1208bc7eSAndroid Build Coastguard Worker 		    "Unexpected arena.0.decay failure");
524*1208bc7eSAndroid Build Coastguard Worker 		assert_u_gt(nupdates_mock, nupdates0,
525*1208bc7eSAndroid Build Coastguard Worker 		    "Expected nstime_update() to be called");
526*1208bc7eSAndroid Build Coastguard Worker 	}
527*1208bc7eSAndroid Build Coastguard Worker 
528*1208bc7eSAndroid Build Coastguard Worker 	do_epoch();
529*1208bc7eSAndroid Build Coastguard Worker 	sz = sizeof(uint64_t);
530*1208bc7eSAndroid Build Coastguard Worker 	npurge1 = get_arena_npurge(0);
531*1208bc7eSAndroid Build Coastguard Worker 
532*1208bc7eSAndroid Build Coastguard Worker 	if (config_stats) {
533*1208bc7eSAndroid Build Coastguard Worker 		assert_u64_eq(npurge0, npurge1, "Unexpected purging occurred");
534*1208bc7eSAndroid Build Coastguard Worker 	}
535*1208bc7eSAndroid Build Coastguard Worker 
536*1208bc7eSAndroid Build Coastguard Worker 	nstime_monotonic = nstime_monotonic_orig;
537*1208bc7eSAndroid Build Coastguard Worker 	nstime_update = nstime_update_orig;
538*1208bc7eSAndroid Build Coastguard Worker #undef NPS
539*1208bc7eSAndroid Build Coastguard Worker }
540*1208bc7eSAndroid Build Coastguard Worker TEST_END
541*1208bc7eSAndroid Build Coastguard Worker 
TEST_BEGIN(test_decay_now)542*1208bc7eSAndroid Build Coastguard Worker TEST_BEGIN(test_decay_now) {
543*1208bc7eSAndroid Build Coastguard Worker 	test_skip_if(check_background_thread_enabled());
544*1208bc7eSAndroid Build Coastguard Worker 
545*1208bc7eSAndroid Build Coastguard Worker 	unsigned arena_ind = do_arena_create(0, 0);
546*1208bc7eSAndroid Build Coastguard Worker 	assert_zu_eq(get_arena_pdirty(arena_ind), 0, "Unexpected dirty pages");
547*1208bc7eSAndroid Build Coastguard Worker 	assert_zu_eq(get_arena_pmuzzy(arena_ind), 0, "Unexpected muzzy pages");
548*1208bc7eSAndroid Build Coastguard Worker 	size_t sizes[] = {16, PAGE<<2, HUGEPAGE<<2};
549*1208bc7eSAndroid Build Coastguard Worker 	/* Verify that dirty/muzzy pages never linger after deallocation. */
550*1208bc7eSAndroid Build Coastguard Worker 	for (unsigned i = 0; i < sizeof(sizes)/sizeof(size_t); i++) {
551*1208bc7eSAndroid Build Coastguard Worker 		size_t size = sizes[i];
552*1208bc7eSAndroid Build Coastguard Worker 		generate_dirty(arena_ind, size);
553*1208bc7eSAndroid Build Coastguard Worker 		assert_zu_eq(get_arena_pdirty(arena_ind), 0,
554*1208bc7eSAndroid Build Coastguard Worker 		    "Unexpected dirty pages");
555*1208bc7eSAndroid Build Coastguard Worker 		assert_zu_eq(get_arena_pmuzzy(arena_ind), 0,
556*1208bc7eSAndroid Build Coastguard Worker 		    "Unexpected muzzy pages");
557*1208bc7eSAndroid Build Coastguard Worker 	}
558*1208bc7eSAndroid Build Coastguard Worker 	do_arena_destroy(arena_ind);
559*1208bc7eSAndroid Build Coastguard Worker }
560*1208bc7eSAndroid Build Coastguard Worker TEST_END
561*1208bc7eSAndroid Build Coastguard Worker 
TEST_BEGIN(test_decay_never)562*1208bc7eSAndroid Build Coastguard Worker TEST_BEGIN(test_decay_never) {
563*1208bc7eSAndroid Build Coastguard Worker 	test_skip_if(check_background_thread_enabled());
564*1208bc7eSAndroid Build Coastguard Worker 
565*1208bc7eSAndroid Build Coastguard Worker 	unsigned arena_ind = do_arena_create(-1, -1);
566*1208bc7eSAndroid Build Coastguard Worker 	int flags = MALLOCX_ARENA(arena_ind) | MALLOCX_TCACHE_NONE;
567*1208bc7eSAndroid Build Coastguard Worker 	assert_zu_eq(get_arena_pdirty(arena_ind), 0, "Unexpected dirty pages");
568*1208bc7eSAndroid Build Coastguard Worker 	assert_zu_eq(get_arena_pmuzzy(arena_ind), 0, "Unexpected muzzy pages");
569*1208bc7eSAndroid Build Coastguard Worker 	size_t sizes[] = {16, PAGE<<2, HUGEPAGE<<2};
570*1208bc7eSAndroid Build Coastguard Worker 	void *ptrs[sizeof(sizes)/sizeof(size_t)];
571*1208bc7eSAndroid Build Coastguard Worker 	for (unsigned i = 0; i < sizeof(sizes)/sizeof(size_t); i++) {
572*1208bc7eSAndroid Build Coastguard Worker 		ptrs[i] = do_mallocx(sizes[i], flags);
573*1208bc7eSAndroid Build Coastguard Worker 	}
574*1208bc7eSAndroid Build Coastguard Worker 	/* Verify that each deallocation generates additional dirty pages. */
575*1208bc7eSAndroid Build Coastguard Worker 	size_t pdirty_prev = get_arena_pdirty(arena_ind);
576*1208bc7eSAndroid Build Coastguard Worker 	size_t pmuzzy_prev = get_arena_pmuzzy(arena_ind);
577*1208bc7eSAndroid Build Coastguard Worker 	assert_zu_eq(pdirty_prev, 0, "Unexpected dirty pages");
578*1208bc7eSAndroid Build Coastguard Worker 	assert_zu_eq(pmuzzy_prev, 0, "Unexpected muzzy pages");
579*1208bc7eSAndroid Build Coastguard Worker 	for (unsigned i = 0; i < sizeof(sizes)/sizeof(size_t); i++) {
580*1208bc7eSAndroid Build Coastguard Worker 		dallocx(ptrs[i], flags);
581*1208bc7eSAndroid Build Coastguard Worker 		size_t pdirty = get_arena_pdirty(arena_ind);
582*1208bc7eSAndroid Build Coastguard Worker 		size_t pmuzzy = get_arena_pmuzzy(arena_ind);
583*1208bc7eSAndroid Build Coastguard Worker 		assert_zu_gt(pdirty, pdirty_prev,
584*1208bc7eSAndroid Build Coastguard Worker 		    "Expected dirty pages to increase.");
585*1208bc7eSAndroid Build Coastguard Worker 		assert_zu_eq(pmuzzy, 0, "Unexpected muzzy pages");
586*1208bc7eSAndroid Build Coastguard Worker 		pdirty_prev = pdirty;
587*1208bc7eSAndroid Build Coastguard Worker 	}
588*1208bc7eSAndroid Build Coastguard Worker 	do_arena_destroy(arena_ind);
589*1208bc7eSAndroid Build Coastguard Worker }
590*1208bc7eSAndroid Build Coastguard Worker TEST_END
591*1208bc7eSAndroid Build Coastguard Worker 
592*1208bc7eSAndroid Build Coastguard Worker int
main(void)593*1208bc7eSAndroid Build Coastguard Worker main(void) {
594*1208bc7eSAndroid Build Coastguard Worker 	return test(
595*1208bc7eSAndroid Build Coastguard Worker 	    test_decay_ticks,
596*1208bc7eSAndroid Build Coastguard Worker 	    test_decay_ticker,
597*1208bc7eSAndroid Build Coastguard Worker 	    test_decay_nonmonotonic,
598*1208bc7eSAndroid Build Coastguard Worker 	    test_decay_now,
599*1208bc7eSAndroid Build Coastguard Worker 	    test_decay_never);
600*1208bc7eSAndroid Build Coastguard Worker }
601