mirror of
https://github.com/jemalloc/jemalloc.git
synced 2026-07-23 21:23:06 +00:00
Move bin functions from arena.c to bin.c
This is a clean-up change that gives the bin functions implemented in the area code a prefix of bin_ and moves them into the bin code. To further decouple the bin code from the arena code, bin functions that had taken an arena_t to check arena_is_auto now take an is_auto parameter instead.
This commit is contained in:
committed by
Guangli Dai
parent
c73ab1c2ff
commit
1cc563f531
263
src/bin.c
263
src/bin.c
@@ -67,3 +67,266 @@ void
|
||||
bin_postfork_child(tsdn_t *tsdn, bin_t *bin) {
|
||||
malloc_mutex_postfork_child(tsdn, &bin->lock);
|
||||
}
|
||||
|
||||
void *
|
||||
bin_slab_reg_alloc(edata_t *slab, const bin_info_t *bin_info) {
|
||||
void *ret;
|
||||
slab_data_t *slab_data = edata_slab_data_get(slab);
|
||||
size_t regind;
|
||||
|
||||
assert(edata_nfree_get(slab) > 0);
|
||||
assert(!bitmap_full(slab_data->bitmap, &bin_info->bitmap_info));
|
||||
|
||||
regind = bitmap_sfu(slab_data->bitmap, &bin_info->bitmap_info);
|
||||
ret = (void *)((byte_t *)edata_addr_get(slab)
|
||||
+ (uintptr_t)(bin_info->reg_size * regind));
|
||||
edata_nfree_dec(slab);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
bin_slab_reg_alloc_batch(
|
||||
edata_t *slab, const bin_info_t *bin_info, unsigned cnt, void **ptrs) {
|
||||
slab_data_t *slab_data = edata_slab_data_get(slab);
|
||||
|
||||
assert(edata_nfree_get(slab) >= cnt);
|
||||
assert(!bitmap_full(slab_data->bitmap, &bin_info->bitmap_info));
|
||||
|
||||
#if (!defined JEMALLOC_INTERNAL_POPCOUNTL) || (defined BITMAP_USE_TREE)
|
||||
for (unsigned i = 0; i < cnt; i++) {
|
||||
size_t regind = bitmap_sfu(
|
||||
slab_data->bitmap, &bin_info->bitmap_info);
|
||||
*(ptrs + i) = (void *)((uintptr_t)edata_addr_get(slab)
|
||||
+ (uintptr_t)(bin_info->reg_size * regind));
|
||||
}
|
||||
#else
|
||||
unsigned group = 0;
|
||||
bitmap_t g = slab_data->bitmap[group];
|
||||
unsigned i = 0;
|
||||
while (i < cnt) {
|
||||
while (g == 0) {
|
||||
g = slab_data->bitmap[++group];
|
||||
}
|
||||
size_t shift = group << LG_BITMAP_GROUP_NBITS;
|
||||
size_t pop = popcount_lu(g);
|
||||
if (pop > (cnt - i)) {
|
||||
pop = cnt - i;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load from memory locations only once, outside the
|
||||
* hot loop below.
|
||||
*/
|
||||
uintptr_t base = (uintptr_t)edata_addr_get(slab);
|
||||
uintptr_t regsize = (uintptr_t)bin_info->reg_size;
|
||||
while (pop--) {
|
||||
size_t bit = cfs_lu(&g);
|
||||
size_t regind = shift + bit;
|
||||
/* NOLINTNEXTLINE(performance-no-int-to-ptr) */
|
||||
*(ptrs + i) = (void *)(base + regsize * regind);
|
||||
|
||||
i++;
|
||||
}
|
||||
slab_data->bitmap[group] = g;
|
||||
}
|
||||
#endif
|
||||
edata_nfree_sub(slab, cnt);
|
||||
}
|
||||
|
||||
void
|
||||
bin_slabs_nonfull_insert(bin_t *bin, edata_t *slab) {
|
||||
assert(edata_nfree_get(slab) > 0);
|
||||
edata_heap_insert(&bin->slabs_nonfull, slab);
|
||||
if (config_stats) {
|
||||
bin->stats.nonfull_slabs++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bin_slabs_nonfull_remove(bin_t *bin, edata_t *slab) {
|
||||
edata_heap_remove(&bin->slabs_nonfull, slab);
|
||||
if (config_stats) {
|
||||
bin->stats.nonfull_slabs--;
|
||||
}
|
||||
}
|
||||
|
||||
edata_t *
|
||||
bin_slabs_nonfull_tryget(bin_t *bin) {
|
||||
edata_t *slab = edata_heap_remove_first(&bin->slabs_nonfull);
|
||||
if (slab == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (config_stats) {
|
||||
bin->stats.reslabs++;
|
||||
bin->stats.nonfull_slabs--;
|
||||
}
|
||||
return slab;
|
||||
}
|
||||
|
||||
void
|
||||
bin_slabs_full_insert(bool is_auto, bin_t *bin, edata_t *slab) {
|
||||
assert(edata_nfree_get(slab) == 0);
|
||||
/*
|
||||
* Tracking extents is required by arena_reset, which is not allowed
|
||||
* for auto arenas. Bypass this step to avoid touching the edata
|
||||
* linkage (often results in cache misses) for auto arenas.
|
||||
*/
|
||||
if (is_auto) {
|
||||
return;
|
||||
}
|
||||
edata_list_active_append(&bin->slabs_full, slab);
|
||||
}
|
||||
|
||||
void
|
||||
bin_slabs_full_remove(bool is_auto, bin_t *bin, edata_t *slab) {
|
||||
if (is_auto) {
|
||||
return;
|
||||
}
|
||||
edata_list_active_remove(&bin->slabs_full, slab);
|
||||
}
|
||||
|
||||
void
|
||||
bin_dissociate_slab(bool is_auto, edata_t *slab, bin_t *bin) {
|
||||
/* Dissociate slab from bin. */
|
||||
if (slab == bin->slabcur) {
|
||||
bin->slabcur = NULL;
|
||||
} else {
|
||||
szind_t binind = edata_szind_get(slab);
|
||||
const bin_info_t *bin_info = &bin_infos[binind];
|
||||
|
||||
/*
|
||||
* The following block's conditional is necessary because if the
|
||||
* slab only contains one region, then it never gets inserted
|
||||
* into the non-full slabs heap.
|
||||
*/
|
||||
if (bin_info->nregs == 1) {
|
||||
bin_slabs_full_remove(is_auto, bin, slab);
|
||||
} else {
|
||||
bin_slabs_nonfull_remove(bin, slab);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bin_lower_slab(tsdn_t *tsdn, bool is_auto, edata_t *slab, bin_t *bin) {
|
||||
assert(edata_nfree_get(slab) > 0);
|
||||
|
||||
/*
|
||||
* Make sure that if bin->slabcur is non-NULL, it refers to the
|
||||
* oldest/lowest non-full slab. It is okay to NULL slabcur out rather
|
||||
* than proactively keeping it pointing at the oldest/lowest non-full
|
||||
* slab.
|
||||
*/
|
||||
if (bin->slabcur != NULL && edata_snad_comp(bin->slabcur, slab) > 0) {
|
||||
/* Switch slabcur. */
|
||||
if (edata_nfree_get(bin->slabcur) > 0) {
|
||||
bin_slabs_nonfull_insert(bin, bin->slabcur);
|
||||
} else {
|
||||
bin_slabs_full_insert(is_auto, bin, bin->slabcur);
|
||||
}
|
||||
bin->slabcur = slab;
|
||||
if (config_stats) {
|
||||
bin->stats.reslabs++;
|
||||
}
|
||||
} else {
|
||||
bin_slabs_nonfull_insert(bin, slab);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bin_dalloc_slab_prepare(tsdn_t *tsdn, edata_t *slab, bin_t *bin) {
|
||||
malloc_mutex_assert_owner(tsdn, &bin->lock);
|
||||
|
||||
assert(slab != bin->slabcur);
|
||||
if (config_stats) {
|
||||
bin->stats.curslabs--;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bin_dalloc_locked_handle_newly_empty(
|
||||
tsdn_t *tsdn, bool is_auto, edata_t *slab, bin_t *bin) {
|
||||
bin_dissociate_slab(is_auto, slab, bin);
|
||||
bin_dalloc_slab_prepare(tsdn, slab, bin);
|
||||
}
|
||||
|
||||
void
|
||||
bin_dalloc_locked_handle_newly_nonempty(
|
||||
tsdn_t *tsdn, bool is_auto, edata_t *slab, bin_t *bin) {
|
||||
bin_slabs_full_remove(is_auto, bin, slab);
|
||||
bin_lower_slab(tsdn, is_auto, slab, bin);
|
||||
}
|
||||
|
||||
void
|
||||
bin_refill_slabcur_with_fresh_slab(tsdn_t *tsdn, bin_t *bin,
|
||||
szind_t binind, edata_t *fresh_slab) {
|
||||
malloc_mutex_assert_owner(tsdn, &bin->lock);
|
||||
/* Only called after slabcur and nonfull both failed. */
|
||||
assert(bin->slabcur == NULL);
|
||||
assert(edata_heap_first(&bin->slabs_nonfull) == NULL);
|
||||
assert(fresh_slab != NULL);
|
||||
|
||||
/* A new slab from arena_slab_alloc() */
|
||||
assert(edata_nfree_get(fresh_slab) == bin_infos[binind].nregs);
|
||||
if (config_stats) {
|
||||
bin->stats.nslabs++;
|
||||
bin->stats.curslabs++;
|
||||
}
|
||||
bin->slabcur = fresh_slab;
|
||||
}
|
||||
|
||||
void *
|
||||
bin_malloc_with_fresh_slab(tsdn_t *tsdn, bin_t *bin,
|
||||
szind_t binind, edata_t *fresh_slab) {
|
||||
malloc_mutex_assert_owner(tsdn, &bin->lock);
|
||||
bin_refill_slabcur_with_fresh_slab(tsdn, bin, binind, fresh_slab);
|
||||
|
||||
return bin_slab_reg_alloc(bin->slabcur, &bin_infos[binind]);
|
||||
}
|
||||
|
||||
bool
|
||||
bin_refill_slabcur_no_fresh_slab(tsdn_t *tsdn, bool is_auto, bin_t *bin) {
|
||||
malloc_mutex_assert_owner(tsdn, &bin->lock);
|
||||
/* Only called after bin_slab_reg_alloc[_batch] failed. */
|
||||
assert(bin->slabcur == NULL || edata_nfree_get(bin->slabcur) == 0);
|
||||
|
||||
if (bin->slabcur != NULL) {
|
||||
bin_slabs_full_insert(is_auto, bin, bin->slabcur);
|
||||
}
|
||||
|
||||
/* Look for a usable slab. */
|
||||
bin->slabcur = bin_slabs_nonfull_tryget(bin);
|
||||
assert(bin->slabcur == NULL || edata_nfree_get(bin->slabcur) > 0);
|
||||
|
||||
return (bin->slabcur == NULL);
|
||||
}
|
||||
|
||||
void *
|
||||
bin_malloc_no_fresh_slab(tsdn_t *tsdn, bool is_auto, bin_t *bin,
|
||||
szind_t binind) {
|
||||
malloc_mutex_assert_owner(tsdn, &bin->lock);
|
||||
if (bin->slabcur == NULL || edata_nfree_get(bin->slabcur) == 0) {
|
||||
if (bin_refill_slabcur_no_fresh_slab(tsdn, is_auto, bin)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
assert(bin->slabcur != NULL && edata_nfree_get(bin->slabcur) > 0);
|
||||
return bin_slab_reg_alloc(bin->slabcur, &bin_infos[binind]);
|
||||
}
|
||||
|
||||
bin_t *
|
||||
bin_choose(tsdn_t *tsdn, arena_t *arena, szind_t binind,
|
||||
unsigned *binshard_p) {
|
||||
unsigned binshard;
|
||||
if (tsdn_null(tsdn) || tsd_arena_get(tsdn_tsd(tsdn)) == NULL) {
|
||||
binshard = 0;
|
||||
} else {
|
||||
binshard = tsd_binshardsp_get(tsdn_tsd(tsdn))->binshard[binind];
|
||||
}
|
||||
assert(binshard < bin_infos[binind].n_shards);
|
||||
if (binshard_p != NULL) {
|
||||
*binshard_p = binshard;
|
||||
}
|
||||
return arena_get_bin(arena, binind, binshard);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user