xref: /freebsd/contrib/jemalloc/src/edata_cache.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 bool
5*c43cad87SWarner Losh edata_cache_init(edata_cache_t *edata_cache, base_t *base) {
6*c43cad87SWarner Losh 	edata_avail_new(&edata_cache->avail);
7*c43cad87SWarner Losh 	/*
8*c43cad87SWarner Losh 	 * This is not strictly necessary, since the edata_cache_t is only
9*c43cad87SWarner Losh 	 * created inside an arena, which is zeroed on creation.  But this is
10*c43cad87SWarner Losh 	 * handy as a safety measure.
11*c43cad87SWarner Losh 	 */
12*c43cad87SWarner Losh 	atomic_store_zu(&edata_cache->count, 0, ATOMIC_RELAXED);
13*c43cad87SWarner Losh 	if (malloc_mutex_init(&edata_cache->mtx, "edata_cache",
14*c43cad87SWarner Losh 	    WITNESS_RANK_EDATA_CACHE, malloc_mutex_rank_exclusive)) {
15*c43cad87SWarner Losh 		return true;
16*c43cad87SWarner Losh 	}
17*c43cad87SWarner Losh 	edata_cache->base = base;
18*c43cad87SWarner Losh 	return false;
19*c43cad87SWarner Losh }
20*c43cad87SWarner Losh 
21*c43cad87SWarner Losh edata_t *
22*c43cad87SWarner Losh edata_cache_get(tsdn_t *tsdn, edata_cache_t *edata_cache) {
23*c43cad87SWarner Losh 	malloc_mutex_lock(tsdn, &edata_cache->mtx);
24*c43cad87SWarner Losh 	edata_t *edata = edata_avail_first(&edata_cache->avail);
25*c43cad87SWarner Losh 	if (edata == NULL) {
26*c43cad87SWarner Losh 		malloc_mutex_unlock(tsdn, &edata_cache->mtx);
27*c43cad87SWarner Losh 		return base_alloc_edata(tsdn, edata_cache->base);
28*c43cad87SWarner Losh 	}
29*c43cad87SWarner Losh 	edata_avail_remove(&edata_cache->avail, edata);
30*c43cad87SWarner Losh 	atomic_load_sub_store_zu(&edata_cache->count, 1);
31*c43cad87SWarner Losh 	malloc_mutex_unlock(tsdn, &edata_cache->mtx);
32*c43cad87SWarner Losh 	return edata;
33*c43cad87SWarner Losh }
34*c43cad87SWarner Losh 
35*c43cad87SWarner Losh void
36*c43cad87SWarner Losh edata_cache_put(tsdn_t *tsdn, edata_cache_t *edata_cache, edata_t *edata) {
37*c43cad87SWarner Losh 	malloc_mutex_lock(tsdn, &edata_cache->mtx);
38*c43cad87SWarner Losh 	edata_avail_insert(&edata_cache->avail, edata);
39*c43cad87SWarner Losh 	atomic_load_add_store_zu(&edata_cache->count, 1);
40*c43cad87SWarner Losh 	malloc_mutex_unlock(tsdn, &edata_cache->mtx);
41*c43cad87SWarner Losh }
42*c43cad87SWarner Losh 
43*c43cad87SWarner Losh void
44*c43cad87SWarner Losh edata_cache_prefork(tsdn_t *tsdn, edata_cache_t *edata_cache) {
45*c43cad87SWarner Losh 	malloc_mutex_prefork(tsdn, &edata_cache->mtx);
46*c43cad87SWarner Losh }
47*c43cad87SWarner Losh 
48*c43cad87SWarner Losh void
49*c43cad87SWarner Losh edata_cache_postfork_parent(tsdn_t *tsdn, edata_cache_t *edata_cache) {
50*c43cad87SWarner Losh 	malloc_mutex_postfork_parent(tsdn, &edata_cache->mtx);
51*c43cad87SWarner Losh }
52*c43cad87SWarner Losh 
53*c43cad87SWarner Losh void
54*c43cad87SWarner Losh edata_cache_postfork_child(tsdn_t *tsdn, edata_cache_t *edata_cache) {
55*c43cad87SWarner Losh 	malloc_mutex_postfork_child(tsdn, &edata_cache->mtx);
56*c43cad87SWarner Losh }
57*c43cad87SWarner Losh 
58*c43cad87SWarner Losh void
59*c43cad87SWarner Losh edata_cache_fast_init(edata_cache_fast_t *ecs, edata_cache_t *fallback) {
60*c43cad87SWarner Losh 	edata_list_inactive_init(&ecs->list);
61*c43cad87SWarner Losh 	ecs->fallback = fallback;
62*c43cad87SWarner Losh 	ecs->disabled = false;
63*c43cad87SWarner Losh }
64*c43cad87SWarner Losh 
65*c43cad87SWarner Losh static void
66*c43cad87SWarner Losh edata_cache_fast_try_fill_from_fallback(tsdn_t *tsdn,
67*c43cad87SWarner Losh     edata_cache_fast_t *ecs) {
68*c43cad87SWarner Losh 	edata_t *edata;
69*c43cad87SWarner Losh 	malloc_mutex_lock(tsdn, &ecs->fallback->mtx);
70*c43cad87SWarner Losh 	for (int i = 0; i < EDATA_CACHE_FAST_FILL; i++) {
71*c43cad87SWarner Losh 		edata = edata_avail_remove_first(&ecs->fallback->avail);
72*c43cad87SWarner Losh 		if (edata == NULL) {
73*c43cad87SWarner Losh 			break;
74*c43cad87SWarner Losh 		}
75*c43cad87SWarner Losh 		edata_list_inactive_append(&ecs->list, edata);
76*c43cad87SWarner Losh 		atomic_load_sub_store_zu(&ecs->fallback->count, 1);
77*c43cad87SWarner Losh 	}
78*c43cad87SWarner Losh 	malloc_mutex_unlock(tsdn, &ecs->fallback->mtx);
79*c43cad87SWarner Losh }
80*c43cad87SWarner Losh 
81*c43cad87SWarner Losh edata_t *
82*c43cad87SWarner Losh edata_cache_fast_get(tsdn_t *tsdn, edata_cache_fast_t *ecs) {
83*c43cad87SWarner Losh 	witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
84*c43cad87SWarner Losh 	    WITNESS_RANK_EDATA_CACHE, 0);
85*c43cad87SWarner Losh 
86*c43cad87SWarner Losh 	if (ecs->disabled) {
87*c43cad87SWarner Losh 		assert(edata_list_inactive_first(&ecs->list) == NULL);
88*c43cad87SWarner Losh 		return edata_cache_get(tsdn, ecs->fallback);
89*c43cad87SWarner Losh 	}
90*c43cad87SWarner Losh 
91*c43cad87SWarner Losh 	edata_t *edata = edata_list_inactive_first(&ecs->list);
92*c43cad87SWarner Losh 	if (edata != NULL) {
93*c43cad87SWarner Losh 		edata_list_inactive_remove(&ecs->list, edata);
94*c43cad87SWarner Losh 		return edata;
95*c43cad87SWarner Losh 	}
96*c43cad87SWarner Losh 	/* Slow path; requires synchronization. */
97*c43cad87SWarner Losh 	edata_cache_fast_try_fill_from_fallback(tsdn, ecs);
98*c43cad87SWarner Losh 	edata = edata_list_inactive_first(&ecs->list);
99*c43cad87SWarner Losh 	if (edata != NULL) {
100*c43cad87SWarner Losh 		edata_list_inactive_remove(&ecs->list, edata);
101*c43cad87SWarner Losh 	} else {
102*c43cad87SWarner Losh 		/*
103*c43cad87SWarner Losh 		 * Slowest path (fallback was also empty); allocate something
104*c43cad87SWarner Losh 		 * new.
105*c43cad87SWarner Losh 		 */
106*c43cad87SWarner Losh 		edata = base_alloc_edata(tsdn, ecs->fallback->base);
107*c43cad87SWarner Losh 	}
108*c43cad87SWarner Losh 	return edata;
109*c43cad87SWarner Losh }
110*c43cad87SWarner Losh 
111*c43cad87SWarner Losh static void
112*c43cad87SWarner Losh edata_cache_fast_flush_all(tsdn_t *tsdn, edata_cache_fast_t *ecs) {
113*c43cad87SWarner Losh 	/*
114*c43cad87SWarner Losh 	 * You could imagine smarter cache management policies (like
115*c43cad87SWarner Losh 	 * only flushing down to some threshold in anticipation of
116*c43cad87SWarner Losh 	 * future get requests).  But just flushing everything provides
117*c43cad87SWarner Losh 	 * a good opportunity to defrag too, and lets us share code between the
118*c43cad87SWarner Losh 	 * flush and disable pathways.
119*c43cad87SWarner Losh 	 */
120*c43cad87SWarner Losh 	edata_t *edata;
121*c43cad87SWarner Losh 	size_t nflushed = 0;
122*c43cad87SWarner Losh 	malloc_mutex_lock(tsdn, &ecs->fallback->mtx);
123*c43cad87SWarner Losh 	while ((edata = edata_list_inactive_first(&ecs->list)) != NULL) {
124*c43cad87SWarner Losh 		edata_list_inactive_remove(&ecs->list, edata);
125*c43cad87SWarner Losh 		edata_avail_insert(&ecs->fallback->avail, edata);
126*c43cad87SWarner Losh 		nflushed++;
127*c43cad87SWarner Losh 	}
128*c43cad87SWarner Losh 	atomic_load_add_store_zu(&ecs->fallback->count, nflushed);
129*c43cad87SWarner Losh 	malloc_mutex_unlock(tsdn, &ecs->fallback->mtx);
130*c43cad87SWarner Losh }
131*c43cad87SWarner Losh 
132*c43cad87SWarner Losh void
133*c43cad87SWarner Losh edata_cache_fast_put(tsdn_t *tsdn, edata_cache_fast_t *ecs, edata_t *edata) {
134*c43cad87SWarner Losh 	witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
135*c43cad87SWarner Losh 	    WITNESS_RANK_EDATA_CACHE, 0);
136*c43cad87SWarner Losh 
137*c43cad87SWarner Losh 	if (ecs->disabled) {
138*c43cad87SWarner Losh 		assert(edata_list_inactive_first(&ecs->list) == NULL);
139*c43cad87SWarner Losh 		edata_cache_put(tsdn, ecs->fallback, edata);
140*c43cad87SWarner Losh 		return;
141*c43cad87SWarner Losh 	}
142*c43cad87SWarner Losh 
143*c43cad87SWarner Losh 	/*
144*c43cad87SWarner Losh 	 * Prepend rather than append, to do LIFO ordering in the hopes of some
145*c43cad87SWarner Losh 	 * cache locality.
146*c43cad87SWarner Losh 	 */
147*c43cad87SWarner Losh 	edata_list_inactive_prepend(&ecs->list, edata);
148*c43cad87SWarner Losh }
149*c43cad87SWarner Losh 
150*c43cad87SWarner Losh void
151*c43cad87SWarner Losh edata_cache_fast_disable(tsdn_t *tsdn, edata_cache_fast_t *ecs) {
152*c43cad87SWarner Losh 	edata_cache_fast_flush_all(tsdn, ecs);
153*c43cad87SWarner Losh 	ecs->disabled = true;
154*c43cad87SWarner Losh }
155