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(¢ral->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