xref: /freebsd/contrib/jemalloc/src/pa.c (revision c43cad87172039ccf38172129c79755ea79e6102)
1*c43cad87SWarner Losh #include "jemalloc/internal/jemalloc_preamble.h"
2*c43cad87SWarner Losh #include "jemalloc/internal/jemalloc_internal_includes.h"
3*c43cad87SWarner Losh 
4*c43cad87SWarner Losh #include "jemalloc/internal/san.h"
5*c43cad87SWarner Losh #include "jemalloc/internal/hpa.h"
6*c43cad87SWarner Losh 
7*c43cad87SWarner Losh static void
8*c43cad87SWarner Losh pa_nactive_add(pa_shard_t *shard, size_t add_pages) {
9*c43cad87SWarner Losh 	atomic_fetch_add_zu(&shard->nactive, add_pages, ATOMIC_RELAXED);
10*c43cad87SWarner Losh }
11*c43cad87SWarner Losh 
12*c43cad87SWarner Losh static void
13*c43cad87SWarner Losh pa_nactive_sub(pa_shard_t *shard, size_t sub_pages) {
14*c43cad87SWarner Losh 	assert(atomic_load_zu(&shard->nactive, ATOMIC_RELAXED) >= sub_pages);
15*c43cad87SWarner Losh 	atomic_fetch_sub_zu(&shard->nactive, sub_pages, ATOMIC_RELAXED);
16*c43cad87SWarner Losh }
17*c43cad87SWarner Losh 
18*c43cad87SWarner Losh bool
19*c43cad87SWarner Losh pa_central_init(pa_central_t *central, base_t *base, bool hpa,
20*c43cad87SWarner Losh     hpa_hooks_t *hpa_hooks) {
21*c43cad87SWarner Losh 	bool err;
22*c43cad87SWarner Losh 	if (hpa) {
23*c43cad87SWarner Losh 		err = hpa_central_init(&central->hpa, base, hpa_hooks);
24*c43cad87SWarner Losh 		if (err) {
25*c43cad87SWarner Losh 			return true;
26*c43cad87SWarner Losh 		}
27*c43cad87SWarner Losh 	}
28*c43cad87SWarner Losh 	return false;
29*c43cad87SWarner Losh }
30*c43cad87SWarner Losh 
31*c43cad87SWarner Losh bool
32*c43cad87SWarner Losh pa_shard_init(tsdn_t *tsdn, pa_shard_t *shard, pa_central_t *central,
33*c43cad87SWarner Losh     emap_t *emap, base_t *base, unsigned ind, pa_shard_stats_t *stats,
34*c43cad87SWarner Losh     malloc_mutex_t *stats_mtx, nstime_t *cur_time,
35*c43cad87SWarner Losh     size_t pac_oversize_threshold, ssize_t dirty_decay_ms,
36*c43cad87SWarner Losh     ssize_t muzzy_decay_ms) {
37*c43cad87SWarner Losh 	/* This will change eventually, but for now it should hold. */
38*c43cad87SWarner Losh 	assert(base_ind_get(base) == ind);
39*c43cad87SWarner Losh 	if (edata_cache_init(&shard->edata_cache, base)) {
40*c43cad87SWarner Losh 		return true;
41*c43cad87SWarner Losh 	}
42*c43cad87SWarner Losh 
43*c43cad87SWarner Losh 	if (pac_init(tsdn, &shard->pac, base, emap, &shard->edata_cache,
44*c43cad87SWarner Losh 	    cur_time, pac_oversize_threshold, dirty_decay_ms, muzzy_decay_ms,
45*c43cad87SWarner Losh 	    &stats->pac_stats, stats_mtx)) {
46*c43cad87SWarner Losh 		return true;
47*c43cad87SWarner Losh 	}
48*c43cad87SWarner Losh 
49*c43cad87SWarner Losh 	shard->ind = ind;
50*c43cad87SWarner Losh 
51*c43cad87SWarner Losh 	shard->ever_used_hpa = false;
52*c43cad87SWarner Losh 	atomic_store_b(&shard->use_hpa, false, ATOMIC_RELAXED);
53*c43cad87SWarner Losh 
54*c43cad87SWarner Losh 	atomic_store_zu(&shard->nactive, 0, ATOMIC_RELAXED);
55*c43cad87SWarner Losh 
56*c43cad87SWarner Losh 	shard->stats_mtx = stats_mtx;
57*c43cad87SWarner Losh 	shard->stats = stats;
58*c43cad87SWarner Losh 	memset(shard->stats, 0, sizeof(*shard->stats));
59*c43cad87SWarner Losh 
60*c43cad87SWarner Losh 	shard->central = central;
61*c43cad87SWarner Losh 	shard->emap = emap;
62*c43cad87SWarner Losh 	shard->base = base;
63*c43cad87SWarner Losh 
64*c43cad87SWarner Losh 	return false;
65*c43cad87SWarner Losh }
66*c43cad87SWarner Losh 
67*c43cad87SWarner Losh bool
68*c43cad87SWarner Losh pa_shard_enable_hpa(tsdn_t *tsdn, pa_shard_t *shard,
69*c43cad87SWarner Losh     const hpa_shard_opts_t *hpa_opts, const sec_opts_t *hpa_sec_opts) {
70*c43cad87SWarner Losh 	if (hpa_shard_init(&shard->hpa_shard, &shard->central->hpa, shard->emap,
71*c43cad87SWarner Losh 	    shard->base, &shard->edata_cache, shard->ind, hpa_opts)) {
72*c43cad87SWarner Losh 		return true;
73*c43cad87SWarner Losh 	}
74*c43cad87SWarner Losh 	if (sec_init(tsdn, &shard->hpa_sec, shard->base, &shard->hpa_shard.pai,
75*c43cad87SWarner Losh 	    hpa_sec_opts)) {
76*c43cad87SWarner Losh 		return true;
77*c43cad87SWarner Losh 	}
78*c43cad87SWarner Losh 	shard->ever_used_hpa = true;
79*c43cad87SWarner Losh 	atomic_store_b(&shard->use_hpa, true, ATOMIC_RELAXED);
80*c43cad87SWarner Losh 
81*c43cad87SWarner Losh 	return false;
82*c43cad87SWarner Losh }
83*c43cad87SWarner Losh 
84*c43cad87SWarner Losh void
85*c43cad87SWarner Losh pa_shard_disable_hpa(tsdn_t *tsdn, pa_shard_t *shard) {
86*c43cad87SWarner Losh 	atomic_store_b(&shard->use_hpa, false, ATOMIC_RELAXED);
87*c43cad87SWarner Losh 	if (shard->ever_used_hpa) {
88*c43cad87SWarner Losh 		sec_disable(tsdn, &shard->hpa_sec);
89*c43cad87SWarner Losh 		hpa_shard_disable(tsdn, &shard->hpa_shard);
90*c43cad87SWarner Losh 	}
91*c43cad87SWarner Losh }
92*c43cad87SWarner Losh 
93*c43cad87SWarner Losh void
94*c43cad87SWarner Losh pa_shard_reset(tsdn_t *tsdn, pa_shard_t *shard) {
95*c43cad87SWarner Losh 	atomic_store_zu(&shard->nactive, 0, ATOMIC_RELAXED);
96*c43cad87SWarner Losh 	if (shard->ever_used_hpa) {
97*c43cad87SWarner Losh 		sec_flush(tsdn, &shard->hpa_sec);
98*c43cad87SWarner Losh 	}
99*c43cad87SWarner Losh }
100*c43cad87SWarner Losh 
101*c43cad87SWarner Losh static bool
102*c43cad87SWarner Losh pa_shard_uses_hpa(pa_shard_t *shard) {
103*c43cad87SWarner Losh 	return atomic_load_b(&shard->use_hpa, ATOMIC_RELAXED);
104*c43cad87SWarner Losh }
105*c43cad87SWarner Losh 
106*c43cad87SWarner Losh void
107*c43cad87SWarner Losh pa_shard_destroy(tsdn_t *tsdn, pa_shard_t *shard) {
108*c43cad87SWarner Losh 	pac_destroy(tsdn, &shard->pac);
109*c43cad87SWarner Losh 	if (shard->ever_used_hpa) {
110*c43cad87SWarner Losh 		sec_flush(tsdn, &shard->hpa_sec);
111*c43cad87SWarner Losh 		hpa_shard_disable(tsdn, &shard->hpa_shard);
112*c43cad87SWarner Losh 	}
113*c43cad87SWarner Losh }
114*c43cad87SWarner Losh 
115*c43cad87SWarner Losh static pai_t *
116*c43cad87SWarner Losh pa_get_pai(pa_shard_t *shard, edata_t *edata) {
117*c43cad87SWarner Losh 	return (edata_pai_get(edata) == EXTENT_PAI_PAC
118*c43cad87SWarner Losh 	    ? &shard->pac.pai : &shard->hpa_sec.pai);
119*c43cad87SWarner Losh }
120*c43cad87SWarner Losh 
121*c43cad87SWarner Losh edata_t *
122*c43cad87SWarner Losh pa_alloc(tsdn_t *tsdn, pa_shard_t *shard, size_t size, size_t alignment,
123*c43cad87SWarner Losh     bool slab, szind_t szind, bool zero, bool guarded,
124*c43cad87SWarner Losh     bool *deferred_work_generated) {
125*c43cad87SWarner Losh 	witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
126*c43cad87SWarner Losh 	    WITNESS_RANK_CORE, 0);
127*c43cad87SWarner Losh 	assert(!guarded || alignment <= PAGE);
128*c43cad87SWarner Losh 
129*c43cad87SWarner Losh 	edata_t *edata = NULL;
130*c43cad87SWarner Losh 	if (!guarded && pa_shard_uses_hpa(shard)) {
131*c43cad87SWarner Losh 		edata = pai_alloc(tsdn, &shard->hpa_sec.pai, size, alignment,
132*c43cad87SWarner Losh 		    zero, /* guarded */ false, slab, deferred_work_generated);
133*c43cad87SWarner Losh 	}
134*c43cad87SWarner Losh 	/*
135*c43cad87SWarner Losh 	 * Fall back to the PAC if the HPA is off or couldn't serve the given
136*c43cad87SWarner Losh 	 * allocation request.
137*c43cad87SWarner Losh 	 */
138*c43cad87SWarner Losh 	if (edata == NULL) {
139*c43cad87SWarner Losh 		edata = pai_alloc(tsdn, &shard->pac.pai, size, alignment, zero,
140*c43cad87SWarner Losh 		    guarded, slab, deferred_work_generated);
141*c43cad87SWarner Losh 	}
142*c43cad87SWarner Losh 	if (edata != NULL) {
143*c43cad87SWarner Losh 		assert(edata_size_get(edata) == size);
144*c43cad87SWarner Losh 		pa_nactive_add(shard, size >> LG_PAGE);
145*c43cad87SWarner Losh 		emap_remap(tsdn, shard->emap, edata, szind, slab);
146*c43cad87SWarner Losh 		edata_szind_set(edata, szind);
147*c43cad87SWarner Losh 		edata_slab_set(edata, slab);
148*c43cad87SWarner Losh 		if (slab && (size > 2 * PAGE)) {
149*c43cad87SWarner Losh 			emap_register_interior(tsdn, shard->emap, edata, szind);
150*c43cad87SWarner Losh 		}
151*c43cad87SWarner Losh 		assert(edata_arena_ind_get(edata) == shard->ind);
152*c43cad87SWarner Losh 	}
153*c43cad87SWarner Losh 	return edata;
154*c43cad87SWarner Losh }
155*c43cad87SWarner Losh 
156*c43cad87SWarner Losh bool
157*c43cad87SWarner Losh pa_expand(tsdn_t *tsdn, pa_shard_t *shard, edata_t *edata, size_t old_size,
158*c43cad87SWarner Losh     size_t new_size, szind_t szind, bool zero, bool *deferred_work_generated) {
159*c43cad87SWarner Losh 	assert(new_size > old_size);
160*c43cad87SWarner Losh 	assert(edata_size_get(edata) == old_size);
161*c43cad87SWarner Losh 	assert((new_size & PAGE_MASK) == 0);
162*c43cad87SWarner Losh 	if (edata_guarded_get(edata)) {
163*c43cad87SWarner Losh 		return true;
164*c43cad87SWarner Losh 	}
165*c43cad87SWarner Losh 	size_t expand_amount = new_size - old_size;
166*c43cad87SWarner Losh 
167*c43cad87SWarner Losh 	pai_t *pai = pa_get_pai(shard, edata);
168*c43cad87SWarner Losh 
169*c43cad87SWarner Losh 	bool error = pai_expand(tsdn, pai, edata, old_size, new_size, zero,
170*c43cad87SWarner Losh 	    deferred_work_generated);
171*c43cad87SWarner Losh 	if (error) {
172*c43cad87SWarner Losh 		return true;
173*c43cad87SWarner Losh 	}
174*c43cad87SWarner Losh 
175*c43cad87SWarner Losh 	pa_nactive_add(shard, expand_amount >> LG_PAGE);
176*c43cad87SWarner Losh 	edata_szind_set(edata, szind);
177*c43cad87SWarner Losh 	emap_remap(tsdn, shard->emap, edata, szind, /* slab */ false);
178*c43cad87SWarner Losh 	return false;
179*c43cad87SWarner Losh }
180*c43cad87SWarner Losh 
181*c43cad87SWarner Losh bool
182*c43cad87SWarner Losh pa_shrink(tsdn_t *tsdn, pa_shard_t *shard, edata_t *edata, size_t old_size,
183*c43cad87SWarner Losh     size_t new_size, szind_t szind, bool *deferred_work_generated) {
184*c43cad87SWarner Losh 	assert(new_size < old_size);
185*c43cad87SWarner Losh 	assert(edata_size_get(edata) == old_size);
186*c43cad87SWarner Losh 	assert((new_size & PAGE_MASK) == 0);
187*c43cad87SWarner Losh 	if (edata_guarded_get(edata)) {
188*c43cad87SWarner Losh 		return true;
189*c43cad87SWarner Losh 	}
190*c43cad87SWarner Losh 	size_t shrink_amount = old_size - new_size;
191*c43cad87SWarner Losh 
192*c43cad87SWarner Losh 	pai_t *pai = pa_get_pai(shard, edata);
193*c43cad87SWarner Losh 	bool error = pai_shrink(tsdn, pai, edata, old_size, new_size,
194*c43cad87SWarner Losh 	    deferred_work_generated);
195*c43cad87SWarner Losh 	if (error) {
196*c43cad87SWarner Losh 		return true;
197*c43cad87SWarner Losh 	}
198*c43cad87SWarner Losh 	pa_nactive_sub(shard, shrink_amount >> LG_PAGE);
199*c43cad87SWarner Losh 
200*c43cad87SWarner Losh 	edata_szind_set(edata, szind);
201*c43cad87SWarner Losh 	emap_remap(tsdn, shard->emap, edata, szind, /* slab */ false);
202*c43cad87SWarner Losh 	return false;
203*c43cad87SWarner Losh }
204*c43cad87SWarner Losh 
205*c43cad87SWarner Losh void
206*c43cad87SWarner Losh pa_dalloc(tsdn_t *tsdn, pa_shard_t *shard, edata_t *edata,
207*c43cad87SWarner Losh     bool *deferred_work_generated) {
208*c43cad87SWarner Losh 	emap_remap(tsdn, shard->emap, edata, SC_NSIZES, /* slab */ false);
209*c43cad87SWarner Losh 	if (edata_slab_get(edata)) {
210*c43cad87SWarner Losh 		emap_deregister_interior(tsdn, shard->emap, edata);
211*c43cad87SWarner Losh 		/*
212*c43cad87SWarner Losh 		 * The slab state of the extent isn't cleared.  It may be used
213*c43cad87SWarner Losh 		 * by the pai implementation, e.g. to make caching decisions.
214*c43cad87SWarner Losh 		 */
215*c43cad87SWarner Losh 	}
216*c43cad87SWarner Losh 	edata_addr_set(edata, edata_base_get(edata));
217*c43cad87SWarner Losh 	edata_szind_set(edata, SC_NSIZES);
218*c43cad87SWarner Losh 	pa_nactive_sub(shard, edata_size_get(edata) >> LG_PAGE);
219*c43cad87SWarner Losh 	pai_t *pai = pa_get_pai(shard, edata);
220*c43cad87SWarner Losh 	pai_dalloc(tsdn, pai, edata, deferred_work_generated);
221*c43cad87SWarner Losh }
222*c43cad87SWarner Losh 
223*c43cad87SWarner Losh bool
224*c43cad87SWarner Losh pa_shard_retain_grow_limit_get_set(tsdn_t *tsdn, pa_shard_t *shard,
225*c43cad87SWarner Losh     size_t *old_limit, size_t *new_limit) {
226*c43cad87SWarner Losh 	return pac_retain_grow_limit_get_set(tsdn, &shard->pac, old_limit,
227*c43cad87SWarner Losh 	    new_limit);
228*c43cad87SWarner Losh }
229*c43cad87SWarner Losh 
230*c43cad87SWarner Losh bool
231*c43cad87SWarner Losh pa_decay_ms_set(tsdn_t *tsdn, pa_shard_t *shard, extent_state_t state,
232*c43cad87SWarner Losh     ssize_t decay_ms, pac_purge_eagerness_t eagerness) {
233*c43cad87SWarner Losh 	return pac_decay_ms_set(tsdn, &shard->pac, state, decay_ms, eagerness);
234*c43cad87SWarner Losh }
235*c43cad87SWarner Losh 
236*c43cad87SWarner Losh ssize_t
237*c43cad87SWarner Losh pa_decay_ms_get(pa_shard_t *shard, extent_state_t state) {
238*c43cad87SWarner Losh 	return pac_decay_ms_get(&shard->pac, state);
239*c43cad87SWarner Losh }
240*c43cad87SWarner Losh 
241*c43cad87SWarner Losh void
242*c43cad87SWarner Losh pa_shard_set_deferral_allowed(tsdn_t *tsdn, pa_shard_t *shard,
243*c43cad87SWarner Losh     bool deferral_allowed) {
244*c43cad87SWarner Losh 	if (pa_shard_uses_hpa(shard)) {
245*c43cad87SWarner Losh 		hpa_shard_set_deferral_allowed(tsdn, &shard->hpa_shard,
246*c43cad87SWarner Losh 		    deferral_allowed);
247*c43cad87SWarner Losh 	}
248*c43cad87SWarner Losh }
249*c43cad87SWarner Losh 
250*c43cad87SWarner Losh void
251*c43cad87SWarner Losh pa_shard_do_deferred_work(tsdn_t *tsdn, pa_shard_t *shard) {
252*c43cad87SWarner Losh 	if (pa_shard_uses_hpa(shard)) {
253*c43cad87SWarner Losh 		hpa_shard_do_deferred_work(tsdn, &shard->hpa_shard);
254*c43cad87SWarner Losh 	}
255*c43cad87SWarner Losh }
256*c43cad87SWarner Losh 
257*c43cad87SWarner Losh /*
258*c43cad87SWarner Losh  * Get time until next deferred work ought to happen. If there are multiple
259*c43cad87SWarner Losh  * things that have been deferred, this function calculates the time until
260*c43cad87SWarner Losh  * the soonest of those things.
261*c43cad87SWarner Losh  */
262*c43cad87SWarner Losh uint64_t
263*c43cad87SWarner Losh pa_shard_time_until_deferred_work(tsdn_t *tsdn, pa_shard_t *shard) {
264*c43cad87SWarner Losh 	uint64_t time = pai_time_until_deferred_work(tsdn, &shard->pac.pai);
265*c43cad87SWarner Losh 	if (time == BACKGROUND_THREAD_DEFERRED_MIN) {
266*c43cad87SWarner Losh 		return time;
267*c43cad87SWarner Losh 	}
268*c43cad87SWarner Losh 
269*c43cad87SWarner Losh 	if (pa_shard_uses_hpa(shard)) {
270*c43cad87SWarner Losh 		uint64_t hpa =
271*c43cad87SWarner Losh 		    pai_time_until_deferred_work(tsdn, &shard->hpa_shard.pai);
272*c43cad87SWarner Losh 		if (hpa < time) {
273*c43cad87SWarner Losh 			time = hpa;
274*c43cad87SWarner Losh 		}
275*c43cad87SWarner Losh 	}
276*c43cad87SWarner Losh 	return time;
277*c43cad87SWarner Losh }
278