mirror of
https://github.com/jemalloc/jemalloc.git
synced 2026-07-25 14:23:12 +00:00
Reformat the codebase with the clang-format 18.
This commit is contained in:
@@ -13,9 +13,10 @@
|
|||||||
*
|
*
|
||||||
* The calls to this thunk get driven by the peak_event module.
|
* The calls to this thunk get driven by the peak_event module.
|
||||||
*/
|
*/
|
||||||
#define ACTIVITY_CALLBACK_THUNK_INITIALIZER {NULL, NULL}
|
#define ACTIVITY_CALLBACK_THUNK_INITIALIZER \
|
||||||
typedef void (*activity_callback_t)(void *uctx, uint64_t allocated,
|
{ NULL, NULL }
|
||||||
uint64_t deallocated);
|
typedef void (*activity_callback_t)(
|
||||||
|
void *uctx, uint64_t allocated, uint64_t deallocated);
|
||||||
typedef struct activity_callback_thunk_s activity_callback_thunk_t;
|
typedef struct activity_callback_thunk_s activity_callback_thunk_t;
|
||||||
struct activity_callback_thunk_s {
|
struct activity_callback_thunk_s {
|
||||||
activity_callback_t callback;
|
activity_callback_t callback;
|
||||||
|
|||||||
@@ -39,28 +39,28 @@ extern pac_thp_t huge_arena_pac_thp;
|
|||||||
*/
|
*/
|
||||||
extern uint32_t arena_bin_offsets[SC_NBINS];
|
extern uint32_t arena_bin_offsets[SC_NBINS];
|
||||||
|
|
||||||
void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena,
|
void arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
||||||
unsigned *nthreads, const char **dss, ssize_t *dirty_decay_ms,
|
const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms,
|
||||||
ssize_t *muzzy_decay_ms, size_t *nactive, size_t *ndirty, size_t *nmuzzy);
|
size_t *nactive, size_t *ndirty, size_t *nmuzzy);
|
||||||
void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
void arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
||||||
const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms,
|
const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms,
|
||||||
size_t *nactive, size_t *ndirty, size_t *nmuzzy, arena_stats_t *astats,
|
size_t *nactive, size_t *ndirty, size_t *nmuzzy, arena_stats_t *astats,
|
||||||
bin_stats_data_t *bstats, arena_stats_large_t *lstats,
|
bin_stats_data_t *bstats, arena_stats_large_t *lstats, pac_estats_t *estats,
|
||||||
pac_estats_t *estats, hpa_shard_stats_t *hpastats, sec_stats_t *secstats);
|
hpa_shard_stats_t *hpastats, sec_stats_t *secstats);
|
||||||
void arena_handle_deferred_work(tsdn_t *tsdn, arena_t *arena);
|
void arena_handle_deferred_work(tsdn_t *tsdn, arena_t *arena);
|
||||||
edata_t *arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena,
|
edata_t *arena_extent_alloc_large(
|
||||||
size_t usize, size_t alignment, bool zero);
|
tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool zero);
|
||||||
void arena_extent_dalloc_large_prep(tsdn_t *tsdn, arena_t *arena,
|
void arena_extent_dalloc_large_prep(
|
||||||
edata_t *edata);
|
tsdn_t *tsdn, arena_t *arena, edata_t *edata);
|
||||||
void arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena,
|
void arena_extent_ralloc_large_shrink(
|
||||||
edata_t *edata, size_t oldusize);
|
tsdn_t *tsdn, arena_t *arena, edata_t *edata, size_t oldusize);
|
||||||
void arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena,
|
void arena_extent_ralloc_large_expand(
|
||||||
edata_t *edata, size_t oldusize);
|
tsdn_t *tsdn, arena_t *arena, edata_t *edata, size_t oldusize);
|
||||||
bool arena_decay_ms_set(tsdn_t *tsdn, arena_t *arena, extent_state_t state,
|
bool arena_decay_ms_set(
|
||||||
ssize_t decay_ms);
|
tsdn_t *tsdn, arena_t *arena, extent_state_t state, ssize_t decay_ms);
|
||||||
ssize_t arena_decay_ms_get(arena_t *arena, extent_state_t state);
|
ssize_t arena_decay_ms_get(arena_t *arena, extent_state_t state);
|
||||||
void arena_decay(tsdn_t *tsdn, arena_t *arena, bool is_background_thread,
|
void arena_decay(
|
||||||
bool all);
|
tsdn_t *tsdn, arena_t *arena, bool is_background_thread, bool all);
|
||||||
uint64_t arena_time_until_deferred(tsdn_t *tsdn, arena_t *arena);
|
uint64_t arena_time_until_deferred(tsdn_t *tsdn, arena_t *arena);
|
||||||
void arena_do_deferred_work(tsdn_t *tsdn, arena_t *arena);
|
void arena_do_deferred_work(tsdn_t *tsdn, arena_t *arena);
|
||||||
void arena_reset(tsd_t *tsd, arena_t *arena);
|
void arena_reset(tsd_t *tsd, arena_t *arena);
|
||||||
@@ -69,20 +69,20 @@ void arena_cache_bin_fill_small(tsdn_t *tsdn, arena_t *arena,
|
|||||||
cache_bin_t *cache_bin, szind_t binind, const cache_bin_sz_t nfill_min,
|
cache_bin_t *cache_bin, szind_t binind, const cache_bin_sz_t nfill_min,
|
||||||
const cache_bin_sz_t nfill_max);
|
const cache_bin_sz_t nfill_max);
|
||||||
|
|
||||||
void *arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size,
|
void *arena_malloc_hard(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind,
|
||||||
szind_t ind, bool zero, bool slab);
|
bool zero, bool slab);
|
||||||
void *arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize,
|
void *arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment,
|
||||||
size_t alignment, bool zero, bool slab, tcache_t *tcache);
|
bool zero, bool slab, tcache_t *tcache);
|
||||||
void arena_prof_promote(tsdn_t *tsdn, void *ptr, size_t usize,
|
void arena_prof_promote(
|
||||||
size_t bumped_usize);
|
tsdn_t *tsdn, void *ptr, size_t usize, size_t bumped_usize);
|
||||||
void arena_dalloc_promoted(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
|
void arena_dalloc_promoted(
|
||||||
bool slow_path);
|
tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool slow_path);
|
||||||
void arena_slab_dalloc(tsdn_t *tsdn, arena_t *arena, edata_t *slab);
|
void arena_slab_dalloc(tsdn_t *tsdn, arena_t *arena, edata_t *slab);
|
||||||
|
|
||||||
void arena_dalloc_bin_locked_handle_newly_empty(tsdn_t *tsdn, arena_t *arena,
|
void arena_dalloc_bin_locked_handle_newly_empty(
|
||||||
edata_t *slab, bin_t *bin);
|
tsdn_t *tsdn, arena_t *arena, edata_t *slab, bin_t *bin);
|
||||||
void arena_dalloc_bin_locked_handle_newly_nonempty(tsdn_t *tsdn, arena_t *arena,
|
void arena_dalloc_bin_locked_handle_newly_nonempty(
|
||||||
edata_t *slab, bin_t *bin);
|
tsdn_t *tsdn, arena_t *arena, edata_t *slab, bin_t *bin);
|
||||||
void arena_dalloc_small(tsdn_t *tsdn, void *ptr);
|
void arena_dalloc_small(tsdn_t *tsdn, void *ptr);
|
||||||
bool arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
bool arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
||||||
size_t extra, bool zero, size_t *newsize);
|
size_t extra, bool zero, size_t *newsize);
|
||||||
@@ -91,8 +91,8 @@ void *arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize,
|
|||||||
hook_ralloc_args_t *hook_args);
|
hook_ralloc_args_t *hook_args);
|
||||||
dss_prec_t arena_dss_prec_get(arena_t *arena);
|
dss_prec_t arena_dss_prec_get(arena_t *arena);
|
||||||
ehooks_t *arena_get_ehooks(arena_t *arena);
|
ehooks_t *arena_get_ehooks(arena_t *arena);
|
||||||
extent_hooks_t *arena_set_extent_hooks(tsd_t *tsd, arena_t *arena,
|
extent_hooks_t *arena_set_extent_hooks(
|
||||||
extent_hooks_t *extent_hooks);
|
tsd_t *tsd, arena_t *arena, extent_hooks_t *extent_hooks);
|
||||||
bool arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec);
|
bool arena_dss_prec_set(arena_t *arena, dss_prec_t dss_prec);
|
||||||
void arena_name_get(arena_t *arena, char *name);
|
void arena_name_get(arena_t *arena, char *name);
|
||||||
void arena_name_set(arena_t *arena, const char *name);
|
void arena_name_set(arena_t *arena, const char *name);
|
||||||
@@ -100,16 +100,16 @@ ssize_t arena_dirty_decay_ms_default_get(void);
|
|||||||
bool arena_dirty_decay_ms_default_set(ssize_t decay_ms);
|
bool arena_dirty_decay_ms_default_set(ssize_t decay_ms);
|
||||||
ssize_t arena_muzzy_decay_ms_default_get(void);
|
ssize_t arena_muzzy_decay_ms_default_get(void);
|
||||||
bool arena_muzzy_decay_ms_default_set(ssize_t decay_ms);
|
bool arena_muzzy_decay_ms_default_set(ssize_t decay_ms);
|
||||||
bool arena_retain_grow_limit_get_set(tsd_t *tsd, arena_t *arena,
|
bool arena_retain_grow_limit_get_set(
|
||||||
size_t *old_limit, size_t *new_limit);
|
tsd_t *tsd, arena_t *arena, size_t *old_limit, size_t *new_limit);
|
||||||
unsigned arena_nthreads_get(arena_t *arena, bool internal);
|
unsigned arena_nthreads_get(arena_t *arena, bool internal);
|
||||||
void arena_nthreads_inc(arena_t *arena, bool internal);
|
void arena_nthreads_inc(arena_t *arena, bool internal);
|
||||||
void arena_nthreads_dec(arena_t *arena, bool internal);
|
void arena_nthreads_dec(arena_t *arena, bool internal);
|
||||||
arena_t *arena_new(tsdn_t *tsdn, unsigned ind, const arena_config_t *config);
|
arena_t *arena_new(tsdn_t *tsdn, unsigned ind, const arena_config_t *config);
|
||||||
bool arena_init_huge(tsdn_t *tsdn, arena_t *a0);
|
bool arena_init_huge(tsdn_t *tsdn, arena_t *a0);
|
||||||
arena_t *arena_choose_huge(tsd_t *tsd);
|
arena_t *arena_choose_huge(tsd_t *tsd);
|
||||||
bin_t *arena_bin_choose(tsdn_t *tsdn, arena_t *arena, szind_t binind,
|
bin_t *arena_bin_choose(
|
||||||
unsigned *binshard);
|
tsdn_t *tsdn, arena_t *arena, szind_t binind, unsigned *binshard);
|
||||||
size_t arena_fill_small_fresh(tsdn_t *tsdn, arena_t *arena, szind_t binind,
|
size_t arena_fill_small_fresh(tsdn_t *tsdn, arena_t *arena, szind_t binind,
|
||||||
void **ptrs, size_t nfill, bool zero);
|
void **ptrs, size_t nfill, bool zero);
|
||||||
bool arena_boot(sc_data_t *sc_data, base_t *base, bool hpa);
|
bool arena_boot(sc_data_t *sc_data, base_t *base, bool hpa);
|
||||||
|
|||||||
@@ -21,8 +21,8 @@
|
|||||||
|
|
||||||
static inline arena_t *
|
static inline arena_t *
|
||||||
arena_get_from_edata(edata_t *edata) {
|
arena_get_from_edata(edata_t *edata) {
|
||||||
return (arena_t *)atomic_load_p(&arenas[edata_arena_ind_get(edata)],
|
return (arena_t *)atomic_load_p(
|
||||||
ATOMIC_RELAXED);
|
&arenas[edata_arena_ind_get(edata)], ATOMIC_RELAXED);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE arena_t *
|
JEMALLOC_ALWAYS_INLINE arena_t *
|
||||||
@@ -61,15 +61,17 @@ large_dalloc_safety_checks(edata_t *edata, const void *ptr, size_t input_size) {
|
|||||||
* The cost is low enough (as edata will be accessed anyway) to be
|
* The cost is low enough (as edata will be accessed anyway) to be
|
||||||
* enabled all the time.
|
* enabled all the time.
|
||||||
*/
|
*/
|
||||||
if (unlikely(edata == NULL ||
|
if (unlikely(edata == NULL
|
||||||
edata_state_get(edata) != extent_state_active)) {
|
|| edata_state_get(edata) != extent_state_active)) {
|
||||||
safety_check_fail("Invalid deallocation detected: "
|
safety_check_fail(
|
||||||
|
"Invalid deallocation detected: "
|
||||||
"pages being freed (%p) not currently active, "
|
"pages being freed (%p) not currently active, "
|
||||||
"possibly caused by double free bugs.", ptr);
|
"possibly caused by double free bugs.",
|
||||||
|
ptr);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (unlikely(input_size != edata_usize_get(edata) ||
|
if (unlikely(input_size != edata_usize_get(edata)
|
||||||
input_size > SC_LARGE_MAXCLASS)) {
|
|| input_size > SC_LARGE_MAXCLASS)) {
|
||||||
safety_check_fail_sized_dealloc(/* current_dealloc */ true, ptr,
|
safety_check_fail_sized_dealloc(/* current_dealloc */ true, ptr,
|
||||||
/* true_size */ edata_usize_get(edata), input_size);
|
/* true_size */ edata_usize_get(edata), input_size);
|
||||||
return true;
|
return true;
|
||||||
@@ -90,21 +92,22 @@ arena_prof_info_get(tsd_t *tsd, const void *ptr, emap_alloc_ctx_t *alloc_ctx,
|
|||||||
|
|
||||||
/* Static check. */
|
/* Static check. */
|
||||||
if (alloc_ctx == NULL) {
|
if (alloc_ctx == NULL) {
|
||||||
edata = emap_edata_lookup(tsd_tsdn(tsd), &arena_emap_global,
|
edata = emap_edata_lookup(
|
||||||
ptr);
|
tsd_tsdn(tsd), &arena_emap_global, ptr);
|
||||||
is_slab = edata_slab_get(edata);
|
is_slab = edata_slab_get(edata);
|
||||||
} else if (unlikely(!(is_slab = alloc_ctx->slab))) {
|
} else if (unlikely(!(is_slab = alloc_ctx->slab))) {
|
||||||
edata = emap_edata_lookup(tsd_tsdn(tsd), &arena_emap_global,
|
edata = emap_edata_lookup(
|
||||||
ptr);
|
tsd_tsdn(tsd), &arena_emap_global, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(!is_slab)) {
|
if (unlikely(!is_slab)) {
|
||||||
/* edata must have been initialized at this point. */
|
/* edata must have been initialized at this point. */
|
||||||
assert(edata != NULL);
|
assert(edata != NULL);
|
||||||
size_t usize = (alloc_ctx == NULL)? edata_usize_get(edata):
|
size_t usize = (alloc_ctx == NULL)
|
||||||
emap_alloc_ctx_usize_get(alloc_ctx);
|
? edata_usize_get(edata)
|
||||||
if (reset_recent &&
|
: emap_alloc_ctx_usize_get(alloc_ctx);
|
||||||
large_dalloc_safety_checks(edata, ptr, usize)) {
|
if (reset_recent
|
||||||
|
&& large_dalloc_safety_checks(edata, ptr, usize)) {
|
||||||
prof_info->alloc_tctx = PROF_TCTX_SENTINEL;
|
prof_info->alloc_tctx = PROF_TCTX_SENTINEL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -119,22 +122,22 @@ arena_prof_info_get(tsd_t *tsd, const void *ptr, emap_alloc_ctx_t *alloc_ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
arena_prof_tctx_reset(tsd_t *tsd, const void *ptr,
|
arena_prof_tctx_reset(
|
||||||
emap_alloc_ctx_t *alloc_ctx) {
|
tsd_t *tsd, const void *ptr, emap_alloc_ctx_t *alloc_ctx) {
|
||||||
cassert(config_prof);
|
cassert(config_prof);
|
||||||
assert(ptr != NULL);
|
assert(ptr != NULL);
|
||||||
|
|
||||||
/* Static check. */
|
/* Static check. */
|
||||||
if (alloc_ctx == NULL) {
|
if (alloc_ctx == NULL) {
|
||||||
edata_t *edata = emap_edata_lookup(tsd_tsdn(tsd),
|
edata_t *edata = emap_edata_lookup(
|
||||||
&arena_emap_global, ptr);
|
tsd_tsdn(tsd), &arena_emap_global, ptr);
|
||||||
if (unlikely(!edata_slab_get(edata))) {
|
if (unlikely(!edata_slab_get(edata))) {
|
||||||
large_prof_tctx_reset(edata);
|
large_prof_tctx_reset(edata);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (unlikely(!alloc_ctx->slab)) {
|
if (unlikely(!alloc_ctx->slab)) {
|
||||||
edata_t *edata = emap_edata_lookup(tsd_tsdn(tsd),
|
edata_t *edata = emap_edata_lookup(
|
||||||
&arena_emap_global, ptr);
|
tsd_tsdn(tsd), &arena_emap_global, ptr);
|
||||||
large_prof_tctx_reset(edata);
|
large_prof_tctx_reset(edata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,16 +148,16 @@ arena_prof_tctx_reset_sampled(tsd_t *tsd, const void *ptr) {
|
|||||||
cassert(config_prof);
|
cassert(config_prof);
|
||||||
assert(ptr != NULL);
|
assert(ptr != NULL);
|
||||||
|
|
||||||
edata_t *edata = emap_edata_lookup(tsd_tsdn(tsd), &arena_emap_global,
|
edata_t *edata = emap_edata_lookup(
|
||||||
ptr);
|
tsd_tsdn(tsd), &arena_emap_global, ptr);
|
||||||
assert(!edata_slab_get(edata));
|
assert(!edata_slab_get(edata));
|
||||||
|
|
||||||
large_prof_tctx_reset(edata);
|
large_prof_tctx_reset(edata);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
arena_prof_info_set(tsd_t *tsd, edata_t *edata, prof_tctx_t *tctx,
|
arena_prof_info_set(
|
||||||
size_t size) {
|
tsd_t *tsd, edata_t *edata, prof_tctx_t *tctx, size_t size) {
|
||||||
cassert(config_prof);
|
cassert(config_prof);
|
||||||
|
|
||||||
assert(!edata_slab_get(edata));
|
assert(!edata_slab_get(edata));
|
||||||
@@ -197,14 +200,13 @@ arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind, bool zero,
|
|||||||
if (likely(tcache != NULL)) {
|
if (likely(tcache != NULL)) {
|
||||||
if (likely(slab)) {
|
if (likely(slab)) {
|
||||||
assert(sz_can_use_slab(size));
|
assert(sz_can_use_slab(size));
|
||||||
return tcache_alloc_small(tsdn_tsd(tsdn), arena,
|
return tcache_alloc_small(tsdn_tsd(tsdn), arena, tcache,
|
||||||
tcache, size, ind, zero, slow_path);
|
size, ind, zero, slow_path);
|
||||||
} else if (likely(
|
} else if (likely(ind < tcache_nbins_get(tcache->tcache_slow)
|
||||||
ind < tcache_nbins_get(tcache->tcache_slow) &&
|
&& !tcache_bin_disabled(ind, &tcache->bins[ind],
|
||||||
!tcache_bin_disabled(ind, &tcache->bins[ind],
|
|
||||||
tcache->tcache_slow))) {
|
tcache->tcache_slow))) {
|
||||||
return tcache_alloc_large(tsdn_tsd(tsdn), arena,
|
return tcache_alloc_large(tsdn_tsd(tsdn), arena, tcache,
|
||||||
tcache, size, ind, zero, slow_path);
|
size, ind, zero, slow_path);
|
||||||
}
|
}
|
||||||
/* (size > tcache_max) case falls through. */
|
/* (size > tcache_max) case falls through. */
|
||||||
}
|
}
|
||||||
@@ -241,8 +243,8 @@ arena_vsalloc(tsdn_t *tsdn, const void *ptr) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
emap_full_alloc_ctx_t full_alloc_ctx;
|
emap_full_alloc_ctx_t full_alloc_ctx;
|
||||||
bool missing = emap_full_alloc_ctx_try_lookup(tsdn, &arena_emap_global,
|
bool missing = emap_full_alloc_ctx_try_lookup(
|
||||||
ptr, &full_alloc_ctx);
|
tsdn, &arena_emap_global, ptr, &full_alloc_ctx);
|
||||||
if (missing) {
|
if (missing) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -261,8 +263,8 @@ arena_vsalloc(tsdn_t *tsdn, const void *ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
arena_dalloc_large_no_tcache(tsdn_t *tsdn, void *ptr, szind_t szind,
|
arena_dalloc_large_no_tcache(
|
||||||
size_t usize) {
|
tsdn_t *tsdn, void *ptr, szind_t szind, size_t usize) {
|
||||||
/*
|
/*
|
||||||
* szind is still needed in this function mainly becuase
|
* szind is still needed in this function mainly becuase
|
||||||
* szind < SC_NBINS determines not only if this is a small alloc,
|
* szind < SC_NBINS determines not only if this is a small alloc,
|
||||||
@@ -272,8 +274,8 @@ arena_dalloc_large_no_tcache(tsdn_t *tsdn, void *ptr, szind_t szind,
|
|||||||
if (config_prof && unlikely(szind < SC_NBINS)) {
|
if (config_prof && unlikely(szind < SC_NBINS)) {
|
||||||
arena_dalloc_promoted(tsdn, ptr, NULL, true);
|
arena_dalloc_promoted(tsdn, ptr, NULL, true);
|
||||||
} else {
|
} else {
|
||||||
edata_t *edata = emap_edata_lookup(tsdn, &arena_emap_global,
|
edata_t *edata = emap_edata_lookup(
|
||||||
ptr);
|
tsdn, &arena_emap_global, ptr);
|
||||||
if (large_dalloc_safety_checks(edata, ptr, usize)) {
|
if (large_dalloc_safety_checks(edata, ptr, usize)) {
|
||||||
/* See the comment in isfree. */
|
/* See the comment in isfree. */
|
||||||
return;
|
return;
|
||||||
@@ -290,13 +292,13 @@ arena_dalloc_no_tcache(tsdn_t *tsdn, void *ptr) {
|
|||||||
emap_alloc_ctx_lookup(tsdn, &arena_emap_global, ptr, &alloc_ctx);
|
emap_alloc_ctx_lookup(tsdn, &arena_emap_global, ptr, &alloc_ctx);
|
||||||
|
|
||||||
if (config_debug) {
|
if (config_debug) {
|
||||||
edata_t *edata = emap_edata_lookup(tsdn, &arena_emap_global,
|
edata_t *edata = emap_edata_lookup(
|
||||||
ptr);
|
tsdn, &arena_emap_global, ptr);
|
||||||
assert(alloc_ctx.szind == edata_szind_get(edata));
|
assert(alloc_ctx.szind == edata_szind_get(edata));
|
||||||
assert(alloc_ctx.szind < SC_NSIZES);
|
assert(alloc_ctx.szind < SC_NSIZES);
|
||||||
assert(alloc_ctx.slab == edata_slab_get(edata));
|
assert(alloc_ctx.slab == edata_slab_get(edata));
|
||||||
assert(emap_alloc_ctx_usize_get(&alloc_ctx) ==
|
assert(emap_alloc_ctx_usize_get(&alloc_ctx)
|
||||||
edata_usize_get(edata));
|
== edata_usize_get(edata));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (likely(alloc_ctx.slab)) {
|
if (likely(alloc_ctx.slab)) {
|
||||||
@@ -316,14 +318,14 @@ arena_dalloc_large(tsdn_t *tsdn, void *ptr, tcache_t *tcache, szind_t szind,
|
|||||||
if (unlikely(is_sample_promoted)) {
|
if (unlikely(is_sample_promoted)) {
|
||||||
arena_dalloc_promoted(tsdn, ptr, tcache, slow_path);
|
arena_dalloc_promoted(tsdn, ptr, tcache, slow_path);
|
||||||
} else {
|
} else {
|
||||||
if (szind < tcache_nbins_get(tcache->tcache_slow) &&
|
if (szind < tcache_nbins_get(tcache->tcache_slow)
|
||||||
!tcache_bin_disabled(szind, &tcache->bins[szind],
|
&& !tcache_bin_disabled(
|
||||||
tcache->tcache_slow)) {
|
szind, &tcache->bins[szind], tcache->tcache_slow)) {
|
||||||
tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, szind,
|
tcache_dalloc_large(
|
||||||
slow_path);
|
tsdn_tsd(tsdn), tcache, ptr, szind, slow_path);
|
||||||
} else {
|
} else {
|
||||||
edata_t *edata = emap_edata_lookup(tsdn,
|
edata_t *edata = emap_edata_lookup(
|
||||||
&arena_emap_global, ptr);
|
tsdn, &arena_emap_global, ptr);
|
||||||
if (large_dalloc_safety_checks(edata, ptr, usize)) {
|
if (large_dalloc_safety_checks(edata, ptr, usize)) {
|
||||||
/* See the comment in isfree. */
|
/* See the comment in isfree. */
|
||||||
return;
|
return;
|
||||||
@@ -335,16 +337,17 @@ arena_dalloc_large(tsdn_t *tsdn, void *ptr, tcache_t *tcache, szind_t szind,
|
|||||||
|
|
||||||
/* Find the region index of a pointer. */
|
/* Find the region index of a pointer. */
|
||||||
JEMALLOC_ALWAYS_INLINE size_t
|
JEMALLOC_ALWAYS_INLINE size_t
|
||||||
arena_slab_regind_impl(div_info_t* div_info, szind_t binind,
|
arena_slab_regind_impl(
|
||||||
edata_t *slab, const void *ptr) {
|
div_info_t *div_info, szind_t binind, edata_t *slab, const void *ptr) {
|
||||||
size_t diff, regind;
|
size_t diff, regind;
|
||||||
|
|
||||||
/* Freeing a pointer outside the slab can cause assertion failure. */
|
/* Freeing a pointer outside the slab can cause assertion failure. */
|
||||||
assert((uintptr_t)ptr >= (uintptr_t)edata_addr_get(slab));
|
assert((uintptr_t)ptr >= (uintptr_t)edata_addr_get(slab));
|
||||||
assert((uintptr_t)ptr < (uintptr_t)edata_past_get(slab));
|
assert((uintptr_t)ptr < (uintptr_t)edata_past_get(slab));
|
||||||
/* Freeing an interior pointer can cause assertion failure. */
|
/* Freeing an interior pointer can cause assertion failure. */
|
||||||
assert(((uintptr_t)ptr - (uintptr_t)edata_addr_get(slab)) %
|
assert(((uintptr_t)ptr - (uintptr_t)edata_addr_get(slab))
|
||||||
(uintptr_t)bin_infos[binind].reg_size == 0);
|
% (uintptr_t)bin_infos[binind].reg_size
|
||||||
|
== 0);
|
||||||
|
|
||||||
diff = (size_t)((uintptr_t)ptr - (uintptr_t)edata_addr_get(slab));
|
diff = (size_t)((uintptr_t)ptr - (uintptr_t)edata_addr_get(slab));
|
||||||
|
|
||||||
@@ -371,11 +374,12 @@ arena_tcache_dalloc_small_safety_check(tsdn_t *tsdn, void *ptr) {
|
|||||||
slab_data_t *slab_data = edata_slab_data_get(edata);
|
slab_data_t *slab_data = edata_slab_data_get(edata);
|
||||||
const bin_info_t *bin_info = &bin_infos[binind];
|
const bin_info_t *bin_info = &bin_infos[binind];
|
||||||
assert(edata_nfree_get(edata) < bin_info->nregs);
|
assert(edata_nfree_get(edata) < bin_info->nregs);
|
||||||
if (unlikely(!bitmap_get(slab_data->bitmap, &bin_info->bitmap_info,
|
if (unlikely(!bitmap_get(
|
||||||
regind))) {
|
slab_data->bitmap, &bin_info->bitmap_info, regind))) {
|
||||||
safety_check_fail(
|
safety_check_fail(
|
||||||
"Invalid deallocation detected: the pointer being freed (%p) not "
|
"Invalid deallocation detected: the pointer being freed (%p) not "
|
||||||
"currently active, possibly caused by double free bugs.\n", ptr);
|
"currently active, possibly caused by double free bugs.\n",
|
||||||
|
ptr);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -397,18 +401,18 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
|
|||||||
alloc_ctx = *caller_alloc_ctx;
|
alloc_ctx = *caller_alloc_ctx;
|
||||||
} else {
|
} else {
|
||||||
util_assume(tsdn != NULL);
|
util_assume(tsdn != NULL);
|
||||||
emap_alloc_ctx_lookup(tsdn, &arena_emap_global, ptr,
|
emap_alloc_ctx_lookup(
|
||||||
&alloc_ctx);
|
tsdn, &arena_emap_global, ptr, &alloc_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config_debug) {
|
if (config_debug) {
|
||||||
edata_t *edata = emap_edata_lookup(tsdn, &arena_emap_global,
|
edata_t *edata = emap_edata_lookup(
|
||||||
ptr);
|
tsdn, &arena_emap_global, ptr);
|
||||||
assert(alloc_ctx.szind == edata_szind_get(edata));
|
assert(alloc_ctx.szind == edata_szind_get(edata));
|
||||||
assert(alloc_ctx.szind < SC_NSIZES);
|
assert(alloc_ctx.szind < SC_NSIZES);
|
||||||
assert(alloc_ctx.slab == edata_slab_get(edata));
|
assert(alloc_ctx.slab == edata_slab_get(edata));
|
||||||
assert(emap_alloc_ctx_usize_get(&alloc_ctx) ==
|
assert(emap_alloc_ctx_usize_get(&alloc_ctx)
|
||||||
edata_usize_get(edata));
|
== edata_usize_get(edata));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (likely(alloc_ctx.slab)) {
|
if (likely(alloc_ctx.slab)) {
|
||||||
@@ -416,8 +420,8 @@ arena_dalloc(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
|
|||||||
if (arena_tcache_dalloc_small_safety_check(tsdn, ptr)) {
|
if (arena_tcache_dalloc_small_safety_check(tsdn, ptr)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr,
|
tcache_dalloc_small(
|
||||||
alloc_ctx.szind, slow_path);
|
tsdn_tsd(tsdn), tcache, ptr, alloc_ctx.szind, slow_path);
|
||||||
} else {
|
} else {
|
||||||
arena_dalloc_large(tsdn, ptr, tcache, alloc_ctx.szind,
|
arena_dalloc_large(tsdn, ptr, tcache, alloc_ctx.szind,
|
||||||
emap_alloc_ctx_usize_get(&alloc_ctx), slow_path);
|
emap_alloc_ctx_usize_get(&alloc_ctx), slow_path);
|
||||||
@@ -436,21 +440,21 @@ arena_sdalloc_no_tcache(tsdn_t *tsdn, void *ptr, size_t size) {
|
|||||||
* object, so base szind and slab on the given size.
|
* object, so base szind and slab on the given size.
|
||||||
*/
|
*/
|
||||||
szind_t szind = sz_size2index(size);
|
szind_t szind = sz_size2index(size);
|
||||||
emap_alloc_ctx_init(&alloc_ctx, szind, (szind < SC_NBINS),
|
emap_alloc_ctx_init(
|
||||||
size);
|
&alloc_ctx, szind, (szind < SC_NBINS), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((config_prof && opt_prof) || config_debug) {
|
if ((config_prof && opt_prof) || config_debug) {
|
||||||
emap_alloc_ctx_lookup(tsdn, &arena_emap_global, ptr,
|
emap_alloc_ctx_lookup(
|
||||||
&alloc_ctx);
|
tsdn, &arena_emap_global, ptr, &alloc_ctx);
|
||||||
|
|
||||||
assert(alloc_ctx.szind == sz_size2index(size));
|
assert(alloc_ctx.szind == sz_size2index(size));
|
||||||
assert((config_prof && opt_prof)
|
assert((config_prof && opt_prof)
|
||||||
|| alloc_ctx.slab == (alloc_ctx.szind < SC_NBINS));
|
|| alloc_ctx.slab == (alloc_ctx.szind < SC_NBINS));
|
||||||
|
|
||||||
if (config_debug) {
|
if (config_debug) {
|
||||||
edata_t *edata = emap_edata_lookup(tsdn,
|
edata_t *edata = emap_edata_lookup(
|
||||||
&arena_emap_global, ptr);
|
tsdn, &arena_emap_global, ptr);
|
||||||
assert(alloc_ctx.szind == edata_szind_get(edata));
|
assert(alloc_ctx.szind == edata_szind_get(edata));
|
||||||
assert(alloc_ctx.slab == edata_slab_get(edata));
|
assert(alloc_ctx.slab == edata_slab_get(edata));
|
||||||
}
|
}
|
||||||
@@ -481,8 +485,8 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
|
|||||||
if (config_prof && opt_prof) {
|
if (config_prof && opt_prof) {
|
||||||
if (caller_alloc_ctx == NULL) {
|
if (caller_alloc_ctx == NULL) {
|
||||||
/* Uncommon case and should be a static check. */
|
/* Uncommon case and should be a static check. */
|
||||||
emap_alloc_ctx_lookup(tsdn, &arena_emap_global, ptr,
|
emap_alloc_ctx_lookup(
|
||||||
&alloc_ctx);
|
tsdn, &arena_emap_global, ptr, &alloc_ctx);
|
||||||
assert(alloc_ctx.szind == sz_size2index(size));
|
assert(alloc_ctx.szind == sz_size2index(size));
|
||||||
assert(emap_alloc_ctx_usize_get(&alloc_ctx) == size);
|
assert(emap_alloc_ctx_usize_get(&alloc_ctx) == size);
|
||||||
} else {
|
} else {
|
||||||
@@ -498,14 +502,14 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (config_debug) {
|
if (config_debug) {
|
||||||
edata_t *edata = emap_edata_lookup(tsdn, &arena_emap_global,
|
edata_t *edata = emap_edata_lookup(
|
||||||
ptr);
|
tsdn, &arena_emap_global, ptr);
|
||||||
assert(alloc_ctx.szind == edata_szind_get(edata));
|
assert(alloc_ctx.szind == edata_szind_get(edata));
|
||||||
assert(alloc_ctx.slab == edata_slab_get(edata));
|
assert(alloc_ctx.slab == edata_slab_get(edata));
|
||||||
emap_alloc_ctx_init(&alloc_ctx, alloc_ctx.szind, alloc_ctx.slab,
|
emap_alloc_ctx_init(
|
||||||
sz_s2u(size));
|
&alloc_ctx, alloc_ctx.szind, alloc_ctx.slab, sz_s2u(size));
|
||||||
assert(emap_alloc_ctx_usize_get(&alloc_ctx) ==
|
assert(emap_alloc_ctx_usize_get(&alloc_ctx)
|
||||||
edata_usize_get(edata));
|
== edata_usize_get(edata));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (likely(alloc_ctx.slab)) {
|
if (likely(alloc_ctx.slab)) {
|
||||||
@@ -513,8 +517,8 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
|
|||||||
if (arena_tcache_dalloc_small_safety_check(tsdn, ptr)) {
|
if (arena_tcache_dalloc_small_safety_check(tsdn, ptr)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tcache_dalloc_small(tsdn_tsd(tsdn), tcache, ptr,
|
tcache_dalloc_small(
|
||||||
alloc_ctx.szind, slow_path);
|
tsdn_tsd(tsdn), tcache, ptr, alloc_ctx.szind, slow_path);
|
||||||
} else {
|
} else {
|
||||||
arena_dalloc_large(tsdn, ptr, tcache, alloc_ctx.szind,
|
arena_dalloc_large(tsdn, ptr, tcache, alloc_ctx.szind,
|
||||||
sz_s2u(size), slow_path);
|
sz_s2u(size), slow_path);
|
||||||
@@ -522,13 +526,13 @@ arena_sdalloc(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
arena_cache_oblivious_randomize(tsdn_t *tsdn, arena_t *arena, edata_t *edata,
|
arena_cache_oblivious_randomize(
|
||||||
size_t alignment) {
|
tsdn_t *tsdn, arena_t *arena, edata_t *edata, size_t alignment) {
|
||||||
assert(edata_base_get(edata) == edata_addr_get(edata));
|
assert(edata_base_get(edata) == edata_addr_get(edata));
|
||||||
|
|
||||||
if (alignment < PAGE) {
|
if (alignment < PAGE) {
|
||||||
unsigned lg_range = LG_PAGE -
|
unsigned lg_range = LG_PAGE
|
||||||
lg_floor(CACHELINE_CEILING(alignment));
|
- lg_floor(CACHELINE_CEILING(alignment));
|
||||||
size_t r;
|
size_t r;
|
||||||
if (!tsdn_null(tsdn)) {
|
if (!tsdn_null(tsdn)) {
|
||||||
tsd_t *tsd = tsdn_tsd(tsdn);
|
tsd_t *tsd = tsdn_tsd(tsdn);
|
||||||
@@ -538,12 +542,12 @@ arena_cache_oblivious_randomize(tsdn_t *tsdn, arena_t *arena, edata_t *edata,
|
|||||||
uint64_t stack_value = (uint64_t)(uintptr_t)&r;
|
uint64_t stack_value = (uint64_t)(uintptr_t)&r;
|
||||||
r = (size_t)prng_lg_range_u64(&stack_value, lg_range);
|
r = (size_t)prng_lg_range_u64(&stack_value, lg_range);
|
||||||
}
|
}
|
||||||
uintptr_t random_offset = ((uintptr_t)r) << (LG_PAGE -
|
uintptr_t random_offset = ((uintptr_t)r)
|
||||||
lg_range);
|
<< (LG_PAGE - lg_range);
|
||||||
edata->e_addr = (void *)((byte_t *)edata->e_addr +
|
edata->e_addr = (void *)((byte_t *)edata->e_addr
|
||||||
random_offset);
|
+ random_offset);
|
||||||
assert(ALIGNMENT_ADDR2BASE(edata->e_addr, alignment) ==
|
assert(ALIGNMENT_ADDR2BASE(edata->e_addr, alignment)
|
||||||
edata->e_addr);
|
== edata->e_addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -563,13 +567,14 @@ struct arena_dalloc_bin_locked_info_s {
|
|||||||
JEMALLOC_ALWAYS_INLINE size_t
|
JEMALLOC_ALWAYS_INLINE size_t
|
||||||
arena_slab_regind(arena_dalloc_bin_locked_info_t *info, szind_t binind,
|
arena_slab_regind(arena_dalloc_bin_locked_info_t *info, szind_t binind,
|
||||||
edata_t *slab, const void *ptr) {
|
edata_t *slab, const void *ptr) {
|
||||||
size_t regind = arena_slab_regind_impl(&info->div_info, binind, slab, ptr);
|
size_t regind = arena_slab_regind_impl(
|
||||||
|
&info->div_info, binind, slab, ptr);
|
||||||
return regind;
|
return regind;
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
arena_dalloc_bin_locked_begin(arena_dalloc_bin_locked_info_t *info,
|
arena_dalloc_bin_locked_begin(
|
||||||
szind_t binind) {
|
arena_dalloc_bin_locked_info_t *info, szind_t binind) {
|
||||||
info->div_info = arena_binind_div_info[binind];
|
info->div_info = arena_binind_div_info[binind];
|
||||||
info->nregs = bin_infos[binind].nregs;
|
info->nregs = bin_infos[binind].nregs;
|
||||||
info->ndalloc = 0;
|
info->ndalloc = 0;
|
||||||
@@ -605,8 +610,8 @@ arena_dalloc_bin_locked_step(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
|
|||||||
|
|
||||||
unsigned nfree = edata_nfree_get(slab);
|
unsigned nfree = edata_nfree_get(slab);
|
||||||
if (nfree == bin_info->nregs) {
|
if (nfree == bin_info->nregs) {
|
||||||
arena_dalloc_bin_locked_handle_newly_empty(tsdn, arena, slab,
|
arena_dalloc_bin_locked_handle_newly_empty(
|
||||||
bin);
|
tsdn, arena, slab, bin);
|
||||||
|
|
||||||
if (*dalloc_slabs_count < ndalloc_slabs) {
|
if (*dalloc_slabs_count < ndalloc_slabs) {
|
||||||
dalloc_slabs[*dalloc_slabs_count] = slab;
|
dalloc_slabs[*dalloc_slabs_count] = slab;
|
||||||
@@ -615,8 +620,8 @@ arena_dalloc_bin_locked_step(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
|
|||||||
edata_list_active_append(dalloc_slabs_extra, slab);
|
edata_list_active_append(dalloc_slabs_extra, slab);
|
||||||
}
|
}
|
||||||
} else if (nfree == 1 && slab != bin->slabcur) {
|
} else if (nfree == 1 && slab != bin->slabcur) {
|
||||||
arena_dalloc_bin_locked_handle_newly_nonempty(tsdn, arena, slab,
|
arena_dalloc_bin_locked_handle_newly_nonempty(
|
||||||
bin);
|
tsdn, arena, slab, bin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -637,21 +642,20 @@ arena_bin_flush_batch_impl(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
|
|||||||
edata_list_active_t *dalloc_slabs_extra) {
|
edata_list_active_t *dalloc_slabs_extra) {
|
||||||
assert(binind < bin_info_nbatched_sizes);
|
assert(binind < bin_info_nbatched_sizes);
|
||||||
bin_with_batch_t *batched_bin = (bin_with_batch_t *)bin;
|
bin_with_batch_t *batched_bin = (bin_with_batch_t *)bin;
|
||||||
size_t nelems_to_pop = batcher_pop_begin(tsdn,
|
size_t nelems_to_pop = batcher_pop_begin(
|
||||||
&batched_bin->remote_frees);
|
tsdn, &batched_bin->remote_frees);
|
||||||
|
|
||||||
bin_batching_test_mid_pop(nelems_to_pop);
|
bin_batching_test_mid_pop(nelems_to_pop);
|
||||||
if (nelems_to_pop == BATCHER_NO_IDX) {
|
if (nelems_to_pop == BATCHER_NO_IDX) {
|
||||||
malloc_mutex_assert_not_owner(tsdn,
|
malloc_mutex_assert_not_owner(
|
||||||
&batched_bin->remote_frees.mtx);
|
tsdn, &batched_bin->remote_frees.mtx);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
malloc_mutex_assert_owner(tsdn,
|
malloc_mutex_assert_owner(tsdn, &batched_bin->remote_frees.mtx);
|
||||||
&batched_bin->remote_frees.mtx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t npushes = batcher_pop_get_pushes(tsdn,
|
size_t npushes = batcher_pop_get_pushes(
|
||||||
&batched_bin->remote_frees);
|
tsdn, &batched_bin->remote_frees);
|
||||||
bin_remote_free_data_t remote_free_data[BIN_REMOTE_FREE_ELEMS_MAX];
|
bin_remote_free_data_t remote_free_data[BIN_REMOTE_FREE_ELEMS_MAX];
|
||||||
for (size_t i = 0; i < nelems_to_pop; i++) {
|
for (size_t i = 0; i < nelems_to_pop; i++) {
|
||||||
remote_free_data[i] = batched_bin->remote_free_data[i];
|
remote_free_data[i] = batched_bin->remote_free_data[i];
|
||||||
@@ -712,8 +716,8 @@ arena_bin_flush_batch_after_lock(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
|
|||||||
preallocated_slabs);
|
preallocated_slabs);
|
||||||
|
|
||||||
arena_bin_flush_batch_impl(tsdn, arena, bin, &state->info, binind,
|
arena_bin_flush_batch_impl(tsdn, arena, bin, &state->info, binind,
|
||||||
state->dalloc_slabs, ndalloc_slabs,
|
state->dalloc_slabs, ndalloc_slabs, &state->dalloc_slab_count,
|
||||||
&state->dalloc_slab_count, &state->dalloc_slabs_extra);
|
&state->dalloc_slabs_extra);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
@@ -769,8 +773,8 @@ arena_get_bin(arena_t *arena, szind_t binind, unsigned binshard) {
|
|||||||
ret = shard0 + binshard;
|
ret = shard0 + binshard;
|
||||||
}
|
}
|
||||||
assert(binind >= SC_NBINS - 1
|
assert(binind >= SC_NBINS - 1
|
||||||
|| (uintptr_t)ret < (uintptr_t)arena
|
|| (uintptr_t)ret
|
||||||
+ arena_bin_offsets[binind + 1]);
|
< (uintptr_t)arena + arena_bin_offsets[binind + 1]);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,8 +115,8 @@ arena_stats_large_flush_nrequests_add(tsdn_t *tsdn, arena_stats_t *arena_stats,
|
|||||||
arena_stats_large_t *lstats = &arena_stats->lstats[szind - SC_NBINS];
|
arena_stats_large_t *lstats = &arena_stats->lstats[szind - SC_NBINS];
|
||||||
locked_inc_u64(tsdn, LOCKEDINT_MTX(arena_stats->mtx),
|
locked_inc_u64(tsdn, LOCKEDINT_MTX(arena_stats->mtx),
|
||||||
&lstats->nrequests, nrequests);
|
&lstats->nrequests, nrequests);
|
||||||
locked_inc_u64(tsdn, LOCKEDINT_MTX(arena_stats->mtx),
|
locked_inc_u64(
|
||||||
&lstats->nflushes, 1);
|
tsdn, LOCKEDINT_MTX(arena_stats->mtx), &lstats->nflushes, 1);
|
||||||
LOCKEDINT_MTX_UNLOCK(tsdn, arena_stats->mtx);
|
LOCKEDINT_MTX_UNLOCK(tsdn, arena_stats->mtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -101,7 +101,8 @@ struct arena_s {
|
|||||||
* Enforcing cacheline-alignment to minimize the number of cachelines
|
* Enforcing cacheline-alignment to minimize the number of cachelines
|
||||||
* touched on the hot paths.
|
* touched on the hot paths.
|
||||||
*/
|
*/
|
||||||
JEMALLOC_WARN_ON_USAGE("Do not use this field directly. "
|
JEMALLOC_WARN_ON_USAGE(
|
||||||
|
"Do not use this field directly. "
|
||||||
"Use `arena_get_bin` instead.")
|
"Use `arena_get_bin` instead.")
|
||||||
JEMALLOC_ALIGNED(CACHELINE)
|
JEMALLOC_ALIGNED(CACHELINE)
|
||||||
bin_with_batch_t all_bins[0];
|
bin_with_batch_t all_bins[0];
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
* assertion failure.
|
* assertion failure.
|
||||||
*/
|
*/
|
||||||
#ifndef assert
|
#ifndef assert
|
||||||
#define assert(e) do { \
|
# define assert(e) \
|
||||||
|
do { \
|
||||||
if (unlikely(config_debug && !(e))) { \
|
if (unlikely(config_debug && !(e))) { \
|
||||||
malloc_printf( \
|
malloc_printf( \
|
||||||
"<jemalloc>: %s:%d: Failed assertion: \"%s\"\n", \
|
"<jemalloc>: %s:%d: Failed assertion: \"%s\"\n", \
|
||||||
@@ -18,7 +19,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef not_reached
|
#ifndef not_reached
|
||||||
#define not_reached() do { \
|
# define not_reached() \
|
||||||
|
do { \
|
||||||
if (config_debug) { \
|
if (config_debug) { \
|
||||||
malloc_printf( \
|
malloc_printf( \
|
||||||
"<jemalloc>: %s:%d: Unreachable code reached\n", \
|
"<jemalloc>: %s:%d: Unreachable code reached\n", \
|
||||||
@@ -30,9 +32,11 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef not_implemented
|
#ifndef not_implemented
|
||||||
#define not_implemented() do { \
|
# define not_implemented() \
|
||||||
|
do { \
|
||||||
if (config_debug) { \
|
if (config_debug) { \
|
||||||
malloc_printf("<jemalloc>: %s:%d: Not implemented\n", \
|
malloc_printf( \
|
||||||
|
"<jemalloc>: %s:%d: Not implemented\n", \
|
||||||
__FILE__, __LINE__); \
|
__FILE__, __LINE__); \
|
||||||
abort(); \
|
abort(); \
|
||||||
} \
|
} \
|
||||||
@@ -40,7 +44,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef assert_not_implemented
|
#ifndef assert_not_implemented
|
||||||
#define assert_not_implemented(e) do { \
|
# define assert_not_implemented(e) \
|
||||||
|
do { \
|
||||||
if (unlikely(config_debug && !(e))) { \
|
if (unlikely(config_debug && !(e))) { \
|
||||||
not_implemented(); \
|
not_implemented(); \
|
||||||
} \
|
} \
|
||||||
@@ -49,7 +54,8 @@
|
|||||||
|
|
||||||
/* Use to assert a particular configuration, e.g., cassert(config_debug). */
|
/* Use to assert a particular configuration, e.g., cassert(config_debug). */
|
||||||
#ifndef cassert
|
#ifndef cassert
|
||||||
#define cassert(c) do { \
|
# define cassert(c) \
|
||||||
|
do { \
|
||||||
if (unlikely(!(c))) { \
|
if (unlikely(!(c))) { \
|
||||||
not_reached(); \
|
not_reached(); \
|
||||||
} \
|
} \
|
||||||
|
|||||||
@@ -56,19 +56,16 @@
|
|||||||
/*
|
/*
|
||||||
* Another convenience -- simple atomic helper functions.
|
* Another convenience -- simple atomic helper functions.
|
||||||
*/
|
*/
|
||||||
#define JEMALLOC_GENERATE_EXPANDED_INT_ATOMICS(type, short_type, \
|
#define JEMALLOC_GENERATE_EXPANDED_INT_ATOMICS(type, short_type, lg_size) \
|
||||||
lg_size) \
|
|
||||||
JEMALLOC_GENERATE_INT_ATOMICS(type, short_type, lg_size) \
|
JEMALLOC_GENERATE_INT_ATOMICS(type, short_type, lg_size) \
|
||||||
ATOMIC_INLINE void \
|
ATOMIC_INLINE void atomic_load_add_store_##short_type( \
|
||||||
atomic_load_add_store_##short_type(atomic_##short_type##_t *a, \
|
atomic_##short_type##_t *a, type inc) { \
|
||||||
type inc) { \
|
|
||||||
type oldval = atomic_load_##short_type(a, ATOMIC_RELAXED); \
|
type oldval = atomic_load_##short_type(a, ATOMIC_RELAXED); \
|
||||||
type newval = oldval + inc; \
|
type newval = oldval + inc; \
|
||||||
atomic_store_##short_type(a, newval, ATOMIC_RELAXED); \
|
atomic_store_##short_type(a, newval, ATOMIC_RELAXED); \
|
||||||
} \
|
} \
|
||||||
ATOMIC_INLINE void \
|
ATOMIC_INLINE void atomic_load_sub_store_##short_type( \
|
||||||
atomic_load_sub_store_##short_type(atomic_##short_type##_t *a, \
|
atomic_##short_type##_t *a, type inc) { \
|
||||||
type inc) { \
|
|
||||||
type oldval = atomic_load_##short_type(a, ATOMIC_RELAXED); \
|
type oldval = atomic_load_##short_type(a, ATOMIC_RELAXED); \
|
||||||
type newval = oldval - inc; \
|
type newval = oldval - inc; \
|
||||||
atomic_store_##short_type(a, newval, ATOMIC_RELAXED); \
|
atomic_store_##short_type(a, newval, ATOMIC_RELAXED); \
|
||||||
|
|||||||
@@ -66,34 +66,28 @@ atomic_compare_exchange_strong_##short_type(atomic_##short_type##_t *a, \
|
|||||||
* Integral types have some special operations available that non-integral ones
|
* Integral types have some special operations available that non-integral ones
|
||||||
* lack.
|
* lack.
|
||||||
*/
|
*/
|
||||||
#define JEMALLOC_GENERATE_INT_ATOMICS(type, short_type, \
|
#define JEMALLOC_GENERATE_INT_ATOMICS(type, short_type, /* unused */ lg_size) \
|
||||||
/* unused */ lg_size) \
|
|
||||||
JEMALLOC_GENERATE_ATOMICS(type, short_type, /* unused */ lg_size) \
|
JEMALLOC_GENERATE_ATOMICS(type, short_type, /* unused */ lg_size) \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE type \
|
ATOMIC_INLINE type atomic_fetch_add_##short_type( \
|
||||||
atomic_fetch_add_##short_type(atomic_##short_type##_t *a, \
|
atomic_##short_type##_t *a, type val, atomic_memory_order_t mo) { \
|
||||||
type val, atomic_memory_order_t mo) { \
|
|
||||||
return atomic_fetch_add_explicit(a, val, mo); \
|
return atomic_fetch_add_explicit(a, val, mo); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE type \
|
ATOMIC_INLINE type atomic_fetch_sub_##short_type( \
|
||||||
atomic_fetch_sub_##short_type(atomic_##short_type##_t *a, \
|
atomic_##short_type##_t *a, type val, atomic_memory_order_t mo) { \
|
||||||
type val, atomic_memory_order_t mo) { \
|
|
||||||
return atomic_fetch_sub_explicit(a, val, mo); \
|
return atomic_fetch_sub_explicit(a, val, mo); \
|
||||||
} \
|
} \
|
||||||
ATOMIC_INLINE type \
|
ATOMIC_INLINE type atomic_fetch_and_##short_type( \
|
||||||
atomic_fetch_and_##short_type(atomic_##short_type##_t *a, \
|
atomic_##short_type##_t *a, type val, atomic_memory_order_t mo) { \
|
||||||
type val, atomic_memory_order_t mo) { \
|
|
||||||
return atomic_fetch_and_explicit(a, val, mo); \
|
return atomic_fetch_and_explicit(a, val, mo); \
|
||||||
} \
|
} \
|
||||||
ATOMIC_INLINE type \
|
ATOMIC_INLINE type atomic_fetch_or_##short_type( \
|
||||||
atomic_fetch_or_##short_type(atomic_##short_type##_t *a, \
|
atomic_##short_type##_t *a, type val, atomic_memory_order_t mo) { \
|
||||||
type val, atomic_memory_order_t mo) { \
|
|
||||||
return atomic_fetch_or_explicit(a, val, mo); \
|
return atomic_fetch_or_explicit(a, val, mo); \
|
||||||
} \
|
} \
|
||||||
ATOMIC_INLINE type \
|
ATOMIC_INLINE type atomic_fetch_xor_##short_type( \
|
||||||
atomic_fetch_xor_##short_type(atomic_##short_type##_t *a, \
|
atomic_##short_type##_t *a, type val, atomic_memory_order_t mo) { \
|
||||||
type val, atomic_memory_order_t mo) { \
|
|
||||||
return atomic_fetch_xor_explicit(a, val, mo); \
|
return atomic_fetch_xor_explicit(a, val, mo); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
|
|
||||||
#define ATOMIC_INLINE JEMALLOC_ALWAYS_INLINE
|
#define ATOMIC_INLINE JEMALLOC_ALWAYS_INLINE
|
||||||
|
|
||||||
#define ATOMIC_INIT(...) {__VA_ARGS__}
|
#define ATOMIC_INIT(...) \
|
||||||
|
{ __VA_ARGS__ }
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
atomic_memory_order_relaxed,
|
atomic_memory_order_relaxed,
|
||||||
@@ -39,38 +40,33 @@ atomic_fence(atomic_memory_order_t mo) {
|
|||||||
__atomic_thread_fence(atomic_enum_to_builtin(mo));
|
__atomic_thread_fence(atomic_enum_to_builtin(mo));
|
||||||
}
|
}
|
||||||
|
|
||||||
#define JEMALLOC_GENERATE_ATOMICS(type, short_type, \
|
#define JEMALLOC_GENERATE_ATOMICS(type, short_type, /* unused */ lg_size) \
|
||||||
/* unused */ lg_size) \
|
|
||||||
typedef struct { \
|
typedef struct { \
|
||||||
type repr; \
|
type repr; \
|
||||||
} atomic_##short_type##_t; \
|
} atomic_##short_type##_t; \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE type \
|
ATOMIC_INLINE type atomic_load_##short_type( \
|
||||||
atomic_load_##short_type(const atomic_##short_type##_t *a, \
|
const atomic_##short_type##_t *a, atomic_memory_order_t mo) { \
|
||||||
atomic_memory_order_t mo) { \
|
|
||||||
type result; \
|
type result; \
|
||||||
__atomic_load(&a->repr, &result, atomic_enum_to_builtin(mo)); \
|
__atomic_load(&a->repr, &result, atomic_enum_to_builtin(mo)); \
|
||||||
return result; \
|
return result; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE void \
|
ATOMIC_INLINE void atomic_store_##short_type( \
|
||||||
atomic_store_##short_type(atomic_##short_type##_t *a, type val, \
|
atomic_##short_type##_t *a, type val, atomic_memory_order_t mo) { \
|
||||||
atomic_memory_order_t mo) { \
|
|
||||||
__atomic_store(&a->repr, &val, atomic_enum_to_builtin(mo)); \
|
__atomic_store(&a->repr, &val, atomic_enum_to_builtin(mo)); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE type \
|
ATOMIC_INLINE type atomic_exchange_##short_type( \
|
||||||
atomic_exchange_##short_type(atomic_##short_type##_t *a, type val, \
|
atomic_##short_type##_t *a, type val, atomic_memory_order_t mo) { \
|
||||||
atomic_memory_order_t mo) { \
|
|
||||||
type result; \
|
type result; \
|
||||||
__atomic_exchange(&a->repr, &val, &result, \
|
__atomic_exchange( \
|
||||||
atomic_enum_to_builtin(mo)); \
|
&a->repr, &val, &result, atomic_enum_to_builtin(mo)); \
|
||||||
return result; \
|
return result; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE bool \
|
ATOMIC_INLINE bool atomic_compare_exchange_weak_##short_type( \
|
||||||
atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
|
atomic_##short_type##_t *a, UNUSED type *expected, type desired, \
|
||||||
UNUSED type *expected, type desired, \
|
|
||||||
atomic_memory_order_t success_mo, \
|
atomic_memory_order_t success_mo, \
|
||||||
atomic_memory_order_t failure_mo) { \
|
atomic_memory_order_t failure_mo) { \
|
||||||
return __atomic_compare_exchange(&a->repr, expected, &desired, \
|
return __atomic_compare_exchange(&a->repr, expected, &desired, \
|
||||||
@@ -78,55 +74,46 @@ atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
|
|||||||
atomic_enum_to_builtin(failure_mo)); \
|
atomic_enum_to_builtin(failure_mo)); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE bool \
|
ATOMIC_INLINE bool atomic_compare_exchange_strong_##short_type( \
|
||||||
atomic_compare_exchange_strong_##short_type(atomic_##short_type##_t *a, \
|
atomic_##short_type##_t *a, UNUSED type *expected, type desired, \
|
||||||
UNUSED type *expected, type desired, \
|
|
||||||
atomic_memory_order_t success_mo, \
|
atomic_memory_order_t success_mo, \
|
||||||
atomic_memory_order_t failure_mo) { \
|
atomic_memory_order_t failure_mo) { \
|
||||||
return __atomic_compare_exchange(&a->repr, expected, &desired, \
|
return __atomic_compare_exchange(&a->repr, expected, &desired, \
|
||||||
false, \
|
false, atomic_enum_to_builtin(success_mo), \
|
||||||
atomic_enum_to_builtin(success_mo), \
|
|
||||||
atomic_enum_to_builtin(failure_mo)); \
|
atomic_enum_to_builtin(failure_mo)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define JEMALLOC_GENERATE_INT_ATOMICS(type, short_type, /* unused */ lg_size) \
|
||||||
#define JEMALLOC_GENERATE_INT_ATOMICS(type, short_type, \
|
|
||||||
/* unused */ lg_size) \
|
|
||||||
JEMALLOC_GENERATE_ATOMICS(type, short_type, /* unused */ lg_size) \
|
JEMALLOC_GENERATE_ATOMICS(type, short_type, /* unused */ lg_size) \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE type \
|
ATOMIC_INLINE type atomic_fetch_add_##short_type( \
|
||||||
atomic_fetch_add_##short_type(atomic_##short_type##_t *a, type val, \
|
atomic_##short_type##_t *a, type val, atomic_memory_order_t mo) { \
|
||||||
atomic_memory_order_t mo) { \
|
return __atomic_fetch_add( \
|
||||||
return __atomic_fetch_add(&a->repr, val, \
|
&a->repr, val, atomic_enum_to_builtin(mo)); \
|
||||||
atomic_enum_to_builtin(mo)); \
|
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE type \
|
ATOMIC_INLINE type atomic_fetch_sub_##short_type( \
|
||||||
atomic_fetch_sub_##short_type(atomic_##short_type##_t *a, type val, \
|
atomic_##short_type##_t *a, type val, atomic_memory_order_t mo) { \
|
||||||
atomic_memory_order_t mo) { \
|
return __atomic_fetch_sub( \
|
||||||
return __atomic_fetch_sub(&a->repr, val, \
|
&a->repr, val, atomic_enum_to_builtin(mo)); \
|
||||||
atomic_enum_to_builtin(mo)); \
|
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE type \
|
ATOMIC_INLINE type atomic_fetch_and_##short_type( \
|
||||||
atomic_fetch_and_##short_type(atomic_##short_type##_t *a, type val, \
|
atomic_##short_type##_t *a, type val, atomic_memory_order_t mo) { \
|
||||||
atomic_memory_order_t mo) { \
|
return __atomic_fetch_and( \
|
||||||
return __atomic_fetch_and(&a->repr, val, \
|
&a->repr, val, atomic_enum_to_builtin(mo)); \
|
||||||
atomic_enum_to_builtin(mo)); \
|
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE type \
|
ATOMIC_INLINE type atomic_fetch_or_##short_type( \
|
||||||
atomic_fetch_or_##short_type(atomic_##short_type##_t *a, type val, \
|
atomic_##short_type##_t *a, type val, atomic_memory_order_t mo) { \
|
||||||
atomic_memory_order_t mo) { \
|
return __atomic_fetch_or( \
|
||||||
return __atomic_fetch_or(&a->repr, val, \
|
&a->repr, val, atomic_enum_to_builtin(mo)); \
|
||||||
atomic_enum_to_builtin(mo)); \
|
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE type \
|
ATOMIC_INLINE type atomic_fetch_xor_##short_type( \
|
||||||
atomic_fetch_xor_##short_type(atomic_##short_type##_t *a, type val, \
|
atomic_##short_type##_t *a, type val, atomic_memory_order_t mo) { \
|
||||||
atomic_memory_order_t mo) { \
|
return __atomic_fetch_xor( \
|
||||||
return __atomic_fetch_xor(&a->repr, val, \
|
&a->repr, val, atomic_enum_to_builtin(mo)); \
|
||||||
atomic_enum_to_builtin(mo)); \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef ATOMIC_INLINE
|
#undef ATOMIC_INLINE
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
|
|
||||||
#define ATOMIC_INLINE JEMALLOC_ALWAYS_INLINE
|
#define ATOMIC_INLINE JEMALLOC_ALWAYS_INLINE
|
||||||
|
|
||||||
#define ATOMIC_INIT(...) {__VA_ARGS__}
|
#define ATOMIC_INIT(...) \
|
||||||
|
{ __VA_ARGS__ }
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
atomic_memory_order_relaxed,
|
atomic_memory_order_relaxed,
|
||||||
@@ -68,8 +69,8 @@ atomic_fence(atomic_memory_order_t mo) {
|
|||||||
|
|
||||||
ATOMIC_INLINE void
|
ATOMIC_INLINE void
|
||||||
atomic_pre_sc_load_fence() {
|
atomic_pre_sc_load_fence() {
|
||||||
# if defined(__i386__) || defined(__x86_64__) || \
|
#if defined(__i386__) || defined(__x86_64__) \
|
||||||
(defined(__sparc__) && defined(__arch64__))
|
|| (defined(__sparc__) && defined(__arch64__))
|
||||||
atomic_fence(atomic_memory_order_relaxed);
|
atomic_fence(atomic_memory_order_relaxed);
|
||||||
#else
|
#else
|
||||||
atomic_fence(atomic_memory_order_seq_cst);
|
atomic_fence(atomic_memory_order_seq_cst);
|
||||||
@@ -78,13 +79,12 @@ atomic_pre_sc_load_fence() {
|
|||||||
|
|
||||||
ATOMIC_INLINE void
|
ATOMIC_INLINE void
|
||||||
atomic_post_sc_store_fence() {
|
atomic_post_sc_store_fence() {
|
||||||
# if defined(__i386__) || defined(__x86_64__) || \
|
#if defined(__i386__) || defined(__x86_64__) \
|
||||||
(defined(__sparc__) && defined(__arch64__))
|
|| (defined(__sparc__) && defined(__arch64__))
|
||||||
atomic_fence(atomic_memory_order_seq_cst);
|
atomic_fence(atomic_memory_order_seq_cst);
|
||||||
#else
|
#else
|
||||||
atomic_fence(atomic_memory_order_relaxed);
|
atomic_fence(atomic_memory_order_relaxed);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
@@ -164,37 +164,31 @@ atomic_compare_exchange_strong_##short_type(atomic_##short_type##_t *a, \
|
|||||||
}
|
}
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
|
|
||||||
#define JEMALLOC_GENERATE_INT_ATOMICS(type, short_type, \
|
#define JEMALLOC_GENERATE_INT_ATOMICS(type, short_type, /* unused */ lg_size) \
|
||||||
/* unused */ lg_size) \
|
|
||||||
JEMALLOC_GENERATE_ATOMICS(type, short_type, /* unused */ lg_size) \
|
JEMALLOC_GENERATE_ATOMICS(type, short_type, /* unused */ lg_size) \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE type \
|
ATOMIC_INLINE type atomic_fetch_add_##short_type( \
|
||||||
atomic_fetch_add_##short_type(atomic_##short_type##_t *a, type val, \
|
atomic_##short_type##_t *a, type val, atomic_memory_order_t mo) { \
|
||||||
atomic_memory_order_t mo) { \
|
|
||||||
return __sync_fetch_and_add(&a->repr, val); \
|
return __sync_fetch_and_add(&a->repr, val); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE type \
|
ATOMIC_INLINE type atomic_fetch_sub_##short_type( \
|
||||||
atomic_fetch_sub_##short_type(atomic_##short_type##_t *a, type val, \
|
atomic_##short_type##_t *a, type val, atomic_memory_order_t mo) { \
|
||||||
atomic_memory_order_t mo) { \
|
|
||||||
return __sync_fetch_and_sub(&a->repr, val); \
|
return __sync_fetch_and_sub(&a->repr, val); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE type \
|
ATOMIC_INLINE type atomic_fetch_and_##short_type( \
|
||||||
atomic_fetch_and_##short_type(atomic_##short_type##_t *a, type val, \
|
atomic_##short_type##_t *a, type val, atomic_memory_order_t mo) { \
|
||||||
atomic_memory_order_t mo) { \
|
|
||||||
return __sync_fetch_and_and(&a->repr, val); \
|
return __sync_fetch_and_and(&a->repr, val); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE type \
|
ATOMIC_INLINE type atomic_fetch_or_##short_type( \
|
||||||
atomic_fetch_or_##short_type(atomic_##short_type##_t *a, type val, \
|
atomic_##short_type##_t *a, type val, atomic_memory_order_t mo) { \
|
||||||
atomic_memory_order_t mo) { \
|
|
||||||
return __sync_fetch_and_or(&a->repr, val); \
|
return __sync_fetch_and_or(&a->repr, val); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE type \
|
ATOMIC_INLINE type atomic_fetch_xor_##short_type( \
|
||||||
atomic_fetch_xor_##short_type(atomic_##short_type##_t *a, type val, \
|
atomic_##short_type##_t *a, type val, atomic_memory_order_t mo) { \
|
||||||
atomic_memory_order_t mo) { \
|
|
||||||
return __sync_fetch_and_xor(&a->repr, val); \
|
return __sync_fetch_and_xor(&a->repr, val); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
|
|
||||||
#define ATOMIC_INLINE JEMALLOC_ALWAYS_INLINE
|
#define ATOMIC_INLINE JEMALLOC_ALWAYS_INLINE
|
||||||
|
|
||||||
#define ATOMIC_INIT(...) {__VA_ARGS__}
|
#define ATOMIC_INIT(...) \
|
||||||
|
{ __VA_ARGS__ }
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
atomic_memory_order_relaxed,
|
atomic_memory_order_relaxed,
|
||||||
@@ -44,8 +45,8 @@ atomic_fence(atomic_memory_order_t mo) {
|
|||||||
#define ATOMIC_CONCAT(a, b) ATOMIC_RAW_CONCAT(a, b)
|
#define ATOMIC_CONCAT(a, b) ATOMIC_RAW_CONCAT(a, b)
|
||||||
#define ATOMIC_RAW_CONCAT(a, b) a##b
|
#define ATOMIC_RAW_CONCAT(a, b) a##b
|
||||||
|
|
||||||
#define ATOMIC_INTERLOCKED_NAME(base_name, lg_size) ATOMIC_CONCAT( \
|
#define ATOMIC_INTERLOCKED_NAME(base_name, lg_size) \
|
||||||
base_name, ATOMIC_INTERLOCKED_SUFFIX(lg_size))
|
ATOMIC_CONCAT(base_name, ATOMIC_INTERLOCKED_SUFFIX(lg_size))
|
||||||
|
|
||||||
#define ATOMIC_INTERLOCKED_SUFFIX(lg_size) \
|
#define ATOMIC_INTERLOCKED_SUFFIX(lg_size) \
|
||||||
ATOMIC_CONCAT(ATOMIC_INTERLOCKED_SUFFIX_, lg_size)
|
ATOMIC_CONCAT(ATOMIC_INTERLOCKED_SUFFIX_, lg_size)
|
||||||
@@ -60,9 +61,8 @@ typedef struct { \
|
|||||||
ATOMIC_INTERLOCKED_REPR(lg_size) repr; \
|
ATOMIC_INTERLOCKED_REPR(lg_size) repr; \
|
||||||
} atomic_##short_type##_t; \
|
} atomic_##short_type##_t; \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE type \
|
ATOMIC_INLINE type atomic_load_##short_type( \
|
||||||
atomic_load_##short_type(const atomic_##short_type##_t *a, \
|
const atomic_##short_type##_t *a, atomic_memory_order_t mo) { \
|
||||||
atomic_memory_order_t mo) { \
|
|
||||||
ATOMIC_INTERLOCKED_REPR(lg_size) ret = a->repr; \
|
ATOMIC_INTERLOCKED_REPR(lg_size) ret = a->repr; \
|
||||||
if (mo != atomic_memory_order_relaxed) { \
|
if (mo != atomic_memory_order_relaxed) { \
|
||||||
atomic_fence(atomic_memory_order_acquire); \
|
atomic_fence(atomic_memory_order_acquire); \
|
||||||
@@ -70,9 +70,8 @@ atomic_load_##short_type(const atomic_##short_type##_t *a, \
|
|||||||
return (type)ret; \
|
return (type)ret; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE void \
|
ATOMIC_INLINE void atomic_store_##short_type( \
|
||||||
atomic_store_##short_type(atomic_##short_type##_t *a, \
|
atomic_##short_type##_t *a, type val, atomic_memory_order_t mo) { \
|
||||||
type val, atomic_memory_order_t mo) { \
|
|
||||||
if (mo != atomic_memory_order_relaxed) { \
|
if (mo != atomic_memory_order_relaxed) { \
|
||||||
atomic_fence(atomic_memory_order_release); \
|
atomic_fence(atomic_memory_order_release); \
|
||||||
} \
|
} \
|
||||||
@@ -82,24 +81,23 @@ atomic_store_##short_type(atomic_##short_type##_t *a, \
|
|||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE type \
|
ATOMIC_INLINE type atomic_exchange_##short_type( \
|
||||||
atomic_exchange_##short_type(atomic_##short_type##_t *a, type val, \
|
atomic_##short_type##_t *a, type val, atomic_memory_order_t mo) { \
|
||||||
atomic_memory_order_t mo) { \
|
|
||||||
return (type)ATOMIC_INTERLOCKED_NAME(_InterlockedExchange, \
|
return (type)ATOMIC_INTERLOCKED_NAME(_InterlockedExchange, \
|
||||||
lg_size)(&a->repr, (ATOMIC_INTERLOCKED_REPR(lg_size))val); \
|
lg_size)(&a->repr, (ATOMIC_INTERLOCKED_REPR(lg_size))val); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE bool \
|
ATOMIC_INLINE bool atomic_compare_exchange_weak_##short_type( \
|
||||||
atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
|
atomic_##short_type##_t *a, type *expected, type desired, \
|
||||||
type *expected, type desired, atomic_memory_order_t success_mo, \
|
atomic_memory_order_t success_mo, \
|
||||||
atomic_memory_order_t failure_mo) { \
|
atomic_memory_order_t failure_mo) { \
|
||||||
ATOMIC_INTERLOCKED_REPR(lg_size) e = \
|
ATOMIC_INTERLOCKED_REPR(lg_size) \
|
||||||
(ATOMIC_INTERLOCKED_REPR(lg_size))*expected; \
|
e = (ATOMIC_INTERLOCKED_REPR(lg_size)) * expected; \
|
||||||
ATOMIC_INTERLOCKED_REPR(lg_size) d = \
|
ATOMIC_INTERLOCKED_REPR(lg_size) \
|
||||||
(ATOMIC_INTERLOCKED_REPR(lg_size))desired; \
|
d = (ATOMIC_INTERLOCKED_REPR(lg_size))desired; \
|
||||||
ATOMIC_INTERLOCKED_REPR(lg_size) old = \
|
ATOMIC_INTERLOCKED_REPR(lg_size) \
|
||||||
ATOMIC_INTERLOCKED_NAME(_InterlockedCompareExchange, \
|
old = ATOMIC_INTERLOCKED_NAME( \
|
||||||
lg_size)(&a->repr, d, e); \
|
_InterlockedCompareExchange, lg_size)(&a->repr, d, e); \
|
||||||
if (old == e) { \
|
if (old == e) { \
|
||||||
return true; \
|
return true; \
|
||||||
} else { \
|
} else { \
|
||||||
@@ -108,16 +106,15 @@ atomic_compare_exchange_weak_##short_type(atomic_##short_type##_t *a, \
|
|||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
ATOMIC_INLINE bool \
|
ATOMIC_INLINE bool atomic_compare_exchange_strong_##short_type( \
|
||||||
atomic_compare_exchange_strong_##short_type(atomic_##short_type##_t *a, \
|
atomic_##short_type##_t *a, type *expected, type desired, \
|
||||||
type *expected, type desired, atomic_memory_order_t success_mo, \
|
atomic_memory_order_t success_mo, \
|
||||||
atomic_memory_order_t failure_mo) { \
|
atomic_memory_order_t failure_mo) { \
|
||||||
/* We implement the weak version with strong semantics. */ \
|
/* We implement the weak version with strong semantics. */ \
|
||||||
return atomic_compare_exchange_weak_##short_type(a, expected, \
|
return atomic_compare_exchange_weak_##short_type( \
|
||||||
desired, success_mo, failure_mo); \
|
a, expected, desired, success_mo, failure_mo); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
#define JEMALLOC_GENERATE_INT_ATOMICS(type, short_type, lg_size) \
|
#define JEMALLOC_GENERATE_INT_ATOMICS(type, short_type, lg_size) \
|
||||||
JEMALLOC_GENERATE_ATOMICS(type, short_type, lg_size) \
|
JEMALLOC_GENERATE_ATOMICS(type, short_type, lg_size) \
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ bool background_thread_create(tsd_t *tsd, unsigned arena_ind);
|
|||||||
bool background_threads_enable(tsd_t *tsd);
|
bool background_threads_enable(tsd_t *tsd);
|
||||||
bool background_threads_disable(tsd_t *tsd);
|
bool background_threads_disable(tsd_t *tsd);
|
||||||
bool background_thread_is_started(background_thread_info_t *info);
|
bool background_thread_is_started(background_thread_info_t *info);
|
||||||
void background_thread_wakeup_early(background_thread_info_t *info,
|
void background_thread_wakeup_early(
|
||||||
nstime_t *remaining_sleep);
|
background_thread_info_t *info, nstime_t *remaining_sleep);
|
||||||
void background_thread_prefork0(tsdn_t *tsdn);
|
void background_thread_prefork0(tsdn_t *tsdn);
|
||||||
void background_thread_prefork1(tsdn_t *tsdn);
|
void background_thread_prefork1(tsdn_t *tsdn);
|
||||||
void background_thread_postfork_parent(tsdn_t *tsdn);
|
void background_thread_postfork_parent(tsdn_t *tsdn);
|
||||||
void background_thread_postfork_child(tsdn_t *tsdn);
|
void background_thread_postfork_child(tsdn_t *tsdn);
|
||||||
bool background_thread_stats_read(tsdn_t *tsdn,
|
bool background_thread_stats_read(
|
||||||
background_thread_stats_t *stats);
|
tsdn_t *tsdn, background_thread_stats_t *stats);
|
||||||
void background_thread_ctl_init(tsdn_t *tsdn);
|
void background_thread_ctl_init(tsdn_t *tsdn);
|
||||||
|
|
||||||
#ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER
|
#ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER
|
||||||
|
|||||||
@@ -36,14 +36,14 @@ background_thread_info_get(size_t ind) {
|
|||||||
JEMALLOC_ALWAYS_INLINE uint64_t
|
JEMALLOC_ALWAYS_INLINE uint64_t
|
||||||
background_thread_wakeup_time_get(background_thread_info_t *info) {
|
background_thread_wakeup_time_get(background_thread_info_t *info) {
|
||||||
uint64_t next_wakeup = nstime_ns(&info->next_wakeup);
|
uint64_t next_wakeup = nstime_ns(&info->next_wakeup);
|
||||||
assert(atomic_load_b(&info->indefinite_sleep, ATOMIC_ACQUIRE) ==
|
assert(atomic_load_b(&info->indefinite_sleep, ATOMIC_ACQUIRE)
|
||||||
(next_wakeup == BACKGROUND_THREAD_INDEFINITE_SLEEP));
|
== (next_wakeup == BACKGROUND_THREAD_INDEFINITE_SLEEP));
|
||||||
return next_wakeup;
|
return next_wakeup;
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
background_thread_wakeup_time_set(tsdn_t *tsdn, background_thread_info_t *info,
|
background_thread_wakeup_time_set(
|
||||||
uint64_t wakeup_time) {
|
tsdn_t *tsdn, background_thread_info_t *info, uint64_t wakeup_time) {
|
||||||
malloc_mutex_assert_owner(tsdn, &info->mtx);
|
malloc_mutex_assert_owner(tsdn, &info->mtx);
|
||||||
atomic_store_b(&info->indefinite_sleep,
|
atomic_store_b(&info->indefinite_sleep,
|
||||||
wakeup_time == BACKGROUND_THREAD_INDEFINITE_SLEEP, ATOMIC_RELEASE);
|
wakeup_time == BACKGROUND_THREAD_INDEFINITE_SLEEP, ATOMIC_RELEASE);
|
||||||
|
|||||||
@@ -102,13 +102,13 @@ metadata_thp_enabled(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
base_t *b0get(void);
|
base_t *b0get(void);
|
||||||
base_t *base_new(tsdn_t *tsdn, unsigned ind,
|
base_t *base_new(tsdn_t *tsdn, unsigned ind, const extent_hooks_t *extent_hooks,
|
||||||
const extent_hooks_t *extent_hooks, bool metadata_use_hooks);
|
bool metadata_use_hooks);
|
||||||
void base_delete(tsdn_t *tsdn, base_t *base);
|
void base_delete(tsdn_t *tsdn, base_t *base);
|
||||||
ehooks_t *base_ehooks_get(base_t *base);
|
ehooks_t *base_ehooks_get(base_t *base);
|
||||||
ehooks_t *base_ehooks_get_for_metadata(base_t *base);
|
ehooks_t *base_ehooks_get_for_metadata(base_t *base);
|
||||||
extent_hooks_t *base_extent_hooks_set(base_t *base,
|
extent_hooks_t *base_extent_hooks_set(
|
||||||
extent_hooks_t *extent_hooks);
|
base_t *base, extent_hooks_t *extent_hooks);
|
||||||
void *base_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment);
|
void *base_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment);
|
||||||
edata_t *base_alloc_edata(tsdn_t *tsdn, base_t *base);
|
edata_t *base_alloc_edata(tsdn_t *tsdn, base_t *base);
|
||||||
void *base_alloc_rtree(tsdn_t *tsdn, base_t *base, size_t size);
|
void *base_alloc_rtree(tsdn_t *tsdn, base_t *base, size_t size);
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ void batcher_init(batcher_t *batcher, size_t nelems_max);
|
|||||||
* BATCHER_NO_IDX if no index is free. If the former, the caller must call
|
* BATCHER_NO_IDX if no index is free. If the former, the caller must call
|
||||||
* batcher_push_end once done.
|
* batcher_push_end once done.
|
||||||
*/
|
*/
|
||||||
size_t batcher_push_begin(tsdn_t *tsdn, batcher_t *batcher,
|
size_t batcher_push_begin(
|
||||||
size_t elems_to_push);
|
tsdn_t *tsdn, batcher_t *batcher, size_t elems_to_push);
|
||||||
void batcher_push_end(tsdn_t *tsdn, batcher_t *batcher);
|
void batcher_push_end(tsdn_t *tsdn, batcher_t *batcher);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -14,8 +14,8 @@
|
|||||||
#ifdef JEMALLOC_JET
|
#ifdef JEMALLOC_JET
|
||||||
extern void (*bin_batching_test_after_push_hook)(size_t idx);
|
extern void (*bin_batching_test_after_push_hook)(size_t idx);
|
||||||
extern void (*bin_batching_test_mid_pop_hook)(size_t elems_to_pop);
|
extern void (*bin_batching_test_mid_pop_hook)(size_t elems_to_pop);
|
||||||
extern void (*bin_batching_test_after_unlock_hook)(unsigned slab_dalloc_count,
|
extern void (*bin_batching_test_after_unlock_hook)(
|
||||||
bool list_empty);
|
unsigned slab_dalloc_count, bool list_empty);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef JEMALLOC_JET
|
#ifdef JEMALLOC_JET
|
||||||
@@ -50,8 +50,8 @@ bin_batching_test_after_unlock(unsigned slab_dalloc_count, bool list_empty) {
|
|||||||
(void)list_empty;
|
(void)list_empty;
|
||||||
#ifdef JEMALLOC_JET
|
#ifdef JEMALLOC_JET
|
||||||
if (bin_batching_test_after_unlock_hook != NULL) {
|
if (bin_batching_test_after_unlock_hook != NULL) {
|
||||||
bin_batching_test_after_unlock_hook(slab_dalloc_count,
|
bin_batching_test_after_unlock_hook(
|
||||||
list_empty);
|
slab_dalloc_count, list_empty);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,10 @@
|
|||||||
#define N_BIN_SHARDS_DEFAULT 1
|
#define N_BIN_SHARDS_DEFAULT 1
|
||||||
|
|
||||||
/* Used in TSD static initializer only. Real init in arena_bind(). */
|
/* Used in TSD static initializer only. Real init in arena_bind(). */
|
||||||
#define TSD_BINSHARDS_ZERO_INITIALIZER {{UINT8_MAX}}
|
#define TSD_BINSHARDS_ZERO_INITIALIZER \
|
||||||
|
{ \
|
||||||
|
{ UINT8_MAX } \
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct tsd_binshards_s tsd_binshards_t;
|
typedef struct tsd_binshards_s tsd_binshards_t;
|
||||||
struct tsd_binshards_s {
|
struct tsd_binshards_s {
|
||||||
|
|||||||
@@ -117,7 +117,9 @@ fls_u(unsigned x) {
|
|||||||
* This never actually runs; we're just dodging a compiler error for the
|
* This never actually runs; we're just dodging a compiler error for the
|
||||||
* never-taken branch where sizeof(void *) == 8.
|
* never-taken branch where sizeof(void *) == 8.
|
||||||
*/
|
*/
|
||||||
#define DO_BSR64(bit, x) bit = 0; unreachable()
|
# define DO_BSR64(bit, x) \
|
||||||
|
bit = 0; \
|
||||||
|
unreachable()
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
/* clang-format off */
|
/* clang-format off */
|
||||||
@@ -317,7 +319,6 @@ fls_zu(size_t x) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline unsigned
|
static inline unsigned
|
||||||
ffs_u64(uint64_t x) {
|
ffs_u64(uint64_t x) {
|
||||||
#if LG_SIZEOF_LONG == 3
|
#if LG_SIZEOF_LONG == 3
|
||||||
@@ -413,9 +414,12 @@ lg_ceil(size_t x) {
|
|||||||
#define LG_FLOOR_2(x) (x < (1ULL << 1) ? LG_FLOOR_1(x) : 1 + LG_FLOOR_1(x >> 1))
|
#define LG_FLOOR_2(x) (x < (1ULL << 1) ? LG_FLOOR_1(x) : 1 + LG_FLOOR_1(x >> 1))
|
||||||
#define LG_FLOOR_4(x) (x < (1ULL << 2) ? LG_FLOOR_2(x) : 2 + LG_FLOOR_2(x >> 2))
|
#define LG_FLOOR_4(x) (x < (1ULL << 2) ? LG_FLOOR_2(x) : 2 + LG_FLOOR_2(x >> 2))
|
||||||
#define LG_FLOOR_8(x) (x < (1ULL << 4) ? LG_FLOOR_4(x) : 4 + LG_FLOOR_4(x >> 4))
|
#define LG_FLOOR_8(x) (x < (1ULL << 4) ? LG_FLOOR_4(x) : 4 + LG_FLOOR_4(x >> 4))
|
||||||
#define LG_FLOOR_16(x) (x < (1ULL << 8) ? LG_FLOOR_8(x) : 8 + LG_FLOOR_8(x >> 8))
|
#define LG_FLOOR_16(x) \
|
||||||
#define LG_FLOOR_32(x) (x < (1ULL << 16) ? LG_FLOOR_16(x) : 16 + LG_FLOOR_16(x >> 16))
|
(x < (1ULL << 8) ? LG_FLOOR_8(x) : 8 + LG_FLOOR_8(x >> 8))
|
||||||
#define LG_FLOOR_64(x) (x < (1ULL << 32) ? LG_FLOOR_32(x) : 32 + LG_FLOOR_32(x >> 32))
|
#define LG_FLOOR_32(x) \
|
||||||
|
(x < (1ULL << 16) ? LG_FLOOR_16(x) : 16 + LG_FLOOR_16(x >> 16))
|
||||||
|
#define LG_FLOOR_64(x) \
|
||||||
|
(x < (1ULL << 32) ? LG_FLOOR_32(x) : 32 + LG_FLOOR_32(x >> 32))
|
||||||
#if LG_SIZEOF_PTR == 2
|
#if LG_SIZEOF_PTR == 2
|
||||||
# define LG_FLOOR(x) LG_FLOOR_32((x))
|
# define LG_FLOOR(x) LG_FLOOR_32((x))
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -39,15 +39,13 @@ typedef unsigned long bitmap_t;
|
|||||||
/*
|
/*
|
||||||
* Number of groups required at a particular level for a given number of bits.
|
* Number of groups required at a particular level for a given number of bits.
|
||||||
*/
|
*/
|
||||||
#define BITMAP_GROUPS_L0(nbits) \
|
#define BITMAP_GROUPS_L0(nbits) BITMAP_BITS2GROUPS(nbits)
|
||||||
BITMAP_BITS2GROUPS(nbits)
|
#define BITMAP_GROUPS_L1(nbits) BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(nbits))
|
||||||
#define BITMAP_GROUPS_L1(nbits) \
|
|
||||||
BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(nbits))
|
|
||||||
#define BITMAP_GROUPS_L2(nbits) \
|
#define BITMAP_GROUPS_L2(nbits) \
|
||||||
BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits))))
|
BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits))))
|
||||||
#define BITMAP_GROUPS_L3(nbits) \
|
#define BITMAP_GROUPS_L3(nbits) \
|
||||||
BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \
|
BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \
|
||||||
BITMAP_BITS2GROUPS((nbits)))))
|
BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits)))))
|
||||||
#define BITMAP_GROUPS_L4(nbits) \
|
#define BITMAP_GROUPS_L4(nbits) \
|
||||||
BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \
|
BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS( \
|
||||||
BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits))))))
|
BITMAP_BITS2GROUPS(BITMAP_BITS2GROUPS((nbits))))))
|
||||||
@@ -56,8 +54,7 @@ typedef unsigned long bitmap_t;
|
|||||||
* Assuming the number of levels, number of groups required for a given number
|
* Assuming the number of levels, number of groups required for a given number
|
||||||
* of bits.
|
* of bits.
|
||||||
*/
|
*/
|
||||||
#define BITMAP_GROUPS_1_LEVEL(nbits) \
|
#define BITMAP_GROUPS_1_LEVEL(nbits) BITMAP_GROUPS_L0(nbits)
|
||||||
BITMAP_GROUPS_L0(nbits)
|
|
||||||
#define BITMAP_GROUPS_2_LEVEL(nbits) \
|
#define BITMAP_GROUPS_2_LEVEL(nbits) \
|
||||||
(BITMAP_GROUPS_1_LEVEL(nbits) + BITMAP_GROUPS_L1(nbits))
|
(BITMAP_GROUPS_1_LEVEL(nbits) + BITMAP_GROUPS_L1(nbits))
|
||||||
#define BITMAP_GROUPS_3_LEVEL(nbits) \
|
#define BITMAP_GROUPS_3_LEVEL(nbits) \
|
||||||
@@ -107,26 +104,37 @@ typedef unsigned long bitmap_t;
|
|||||||
*/
|
*/
|
||||||
# define BITMAP_MAX_LEVELS 5
|
# define BITMAP_MAX_LEVELS 5
|
||||||
|
|
||||||
#define BITMAP_INFO_INITIALIZER(nbits) { \
|
# define BITMAP_INFO_INITIALIZER(nbits) \
|
||||||
/* nbits. */ \
|
|
||||||
nbits, \
|
|
||||||
/* nlevels. */ \
|
|
||||||
(BITMAP_GROUPS_L0(nbits) > BITMAP_GROUPS_L1(nbits)) + \
|
|
||||||
(BITMAP_GROUPS_L1(nbits) > BITMAP_GROUPS_L2(nbits)) + \
|
|
||||||
(BITMAP_GROUPS_L2(nbits) > BITMAP_GROUPS_L3(nbits)) + \
|
|
||||||
(BITMAP_GROUPS_L3(nbits) > BITMAP_GROUPS_L4(nbits)) + 1, \
|
|
||||||
/* levels. */ \
|
|
||||||
{ \
|
{ \
|
||||||
{0}, \
|
/* nbits. */ \
|
||||||
{BITMAP_GROUPS_L0(nbits)}, \
|
nbits, /* nlevels. */ \
|
||||||
{BITMAP_GROUPS_L1(nbits) + BITMAP_GROUPS_L0(nbits)}, \
|
(BITMAP_GROUPS_L0(nbits) \
|
||||||
{BITMAP_GROUPS_L2(nbits) + BITMAP_GROUPS_L1(nbits) + \
|
> BITMAP_GROUPS_L1(nbits)) \
|
||||||
BITMAP_GROUPS_L0(nbits)}, \
|
+ (BITMAP_GROUPS_L1(nbits) \
|
||||||
{BITMAP_GROUPS_L3(nbits) + BITMAP_GROUPS_L2(nbits) + \
|
> BITMAP_GROUPS_L2(nbits)) \
|
||||||
BITMAP_GROUPS_L1(nbits) + BITMAP_GROUPS_L0(nbits)}, \
|
+ (BITMAP_GROUPS_L2(nbits) \
|
||||||
{BITMAP_GROUPS_L4(nbits) + BITMAP_GROUPS_L3(nbits) + \
|
> BITMAP_GROUPS_L3(nbits)) \
|
||||||
BITMAP_GROUPS_L2(nbits) + BITMAP_GROUPS_L1(nbits) \
|
+ (BITMAP_GROUPS_L3(nbits) \
|
||||||
+ BITMAP_GROUPS_L0(nbits)} \
|
> BITMAP_GROUPS_L4(nbits)) \
|
||||||
|
+ 1, /* levels. */ \
|
||||||
|
{ \
|
||||||
|
{0}, {BITMAP_GROUPS_L0(nbits)}, \
|
||||||
|
{BITMAP_GROUPS_L1(nbits) \
|
||||||
|
+ BITMAP_GROUPS_L0(nbits)}, \
|
||||||
|
{BITMAP_GROUPS_L2(nbits) \
|
||||||
|
+ BITMAP_GROUPS_L1(nbits) \
|
||||||
|
+ BITMAP_GROUPS_L0(nbits)}, \
|
||||||
|
{BITMAP_GROUPS_L3(nbits) \
|
||||||
|
+ BITMAP_GROUPS_L2(nbits) \
|
||||||
|
+ BITMAP_GROUPS_L1(nbits) \
|
||||||
|
+ BITMAP_GROUPS_L0(nbits)}, \
|
||||||
|
{ \
|
||||||
|
BITMAP_GROUPS_L4(nbits) \
|
||||||
|
+ BITMAP_GROUPS_L3(nbits) \
|
||||||
|
+ BITMAP_GROUPS_L2(nbits) \
|
||||||
|
+ BITMAP_GROUPS_L1(nbits) \
|
||||||
|
+ BITMAP_GROUPS_L0(nbits) \
|
||||||
|
} \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,10 +143,10 @@ typedef unsigned long bitmap_t;
|
|||||||
# define BITMAP_GROUPS(nbits) BITMAP_BITS2GROUPS(nbits)
|
# define BITMAP_GROUPS(nbits) BITMAP_BITS2GROUPS(nbits)
|
||||||
# define BITMAP_GROUPS_MAX BITMAP_BITS2GROUPS(BITMAP_MAXBITS)
|
# define BITMAP_GROUPS_MAX BITMAP_BITS2GROUPS(BITMAP_MAXBITS)
|
||||||
|
|
||||||
#define BITMAP_INFO_INITIALIZER(nbits) { \
|
# define BITMAP_INFO_INITIALIZER(nbits) \
|
||||||
|
{ \
|
||||||
/* nbits. */ \
|
/* nbits. */ \
|
||||||
nbits, \
|
nbits, /* ngroups. */ \
|
||||||
/* ngroups. */ \
|
|
||||||
BITMAP_BITS2GROUPS(nbits) \
|
BITMAP_BITS2GROUPS(nbits) \
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,12 +253,13 @@ bitmap_ffu(const bitmap_t *bitmap, const bitmap_info_t *binfo, size_t min_bit) {
|
|||||||
#ifdef BITMAP_USE_TREE
|
#ifdef BITMAP_USE_TREE
|
||||||
size_t bit = 0;
|
size_t bit = 0;
|
||||||
for (unsigned level = binfo->nlevels; level--;) {
|
for (unsigned level = binfo->nlevels; level--;) {
|
||||||
size_t lg_bits_per_group = (LG_BITMAP_GROUP_NBITS * (level +
|
size_t lg_bits_per_group = (LG_BITMAP_GROUP_NBITS
|
||||||
1));
|
* (level + 1));
|
||||||
bitmap_t group = bitmap[binfo->levels[level].group_offset + (bit
|
bitmap_t group = bitmap[binfo->levels[level].group_offset
|
||||||
>> lg_bits_per_group)];
|
+ (bit >> lg_bits_per_group)];
|
||||||
unsigned group_nmask = (unsigned)(((min_bit > bit) ? (min_bit -
|
unsigned group_nmask =
|
||||||
bit) : 0) >> (lg_bits_per_group - LG_BITMAP_GROUP_NBITS));
|
(unsigned)(((min_bit > bit) ? (min_bit - bit) : 0)
|
||||||
|
>> (lg_bits_per_group - LG_BITMAP_GROUP_NBITS));
|
||||||
assert(group_nmask <= BITMAP_GROUP_NBITS);
|
assert(group_nmask <= BITMAP_GROUP_NBITS);
|
||||||
bitmap_t group_mask = ~((1LU << group_nmask) - 1);
|
bitmap_t group_mask = ~((1LU << group_nmask) - 1);
|
||||||
bitmap_t group_masked = group & group_mask;
|
bitmap_t group_masked = group & group_mask;
|
||||||
@@ -273,16 +282,16 @@ bitmap_ffu(const bitmap_t *bitmap, const bitmap_info_t *binfo, size_t min_bit) {
|
|||||||
}
|
}
|
||||||
return bitmap_ffu(bitmap, binfo, sib_base);
|
return bitmap_ffu(bitmap, binfo, sib_base);
|
||||||
}
|
}
|
||||||
bit += ((size_t)ffs_lu(group_masked)) <<
|
bit += ((size_t)ffs_lu(group_masked))
|
||||||
(lg_bits_per_group - LG_BITMAP_GROUP_NBITS);
|
<< (lg_bits_per_group - LG_BITMAP_GROUP_NBITS);
|
||||||
}
|
}
|
||||||
assert(bit >= min_bit);
|
assert(bit >= min_bit);
|
||||||
assert(bit < binfo->nbits);
|
assert(bit < binfo->nbits);
|
||||||
return bit;
|
return bit;
|
||||||
#else
|
#else
|
||||||
size_t i = min_bit >> LG_BITMAP_GROUP_NBITS;
|
size_t i = min_bit >> LG_BITMAP_GROUP_NBITS;
|
||||||
bitmap_t g = bitmap[i] & ~((1LU << (min_bit & BITMAP_GROUP_NBITS_MASK))
|
bitmap_t g = bitmap[i]
|
||||||
- 1);
|
& ~((1LU << (min_bit & BITMAP_GROUP_NBITS_MASK)) - 1);
|
||||||
size_t bit;
|
size_t bit;
|
||||||
while (1) {
|
while (1) {
|
||||||
if (g != 0) {
|
if (g != 0) {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ write_cb_t buf_writer_cb;
|
|||||||
void buf_writer_terminate(tsdn_t *tsdn, buf_writer_t *buf_writer);
|
void buf_writer_terminate(tsdn_t *tsdn, buf_writer_t *buf_writer);
|
||||||
|
|
||||||
typedef ssize_t(read_cb_t)(void *read_cbopaque, void *buf, size_t limit);
|
typedef ssize_t(read_cb_t)(void *read_cbopaque, void *buf, size_t limit);
|
||||||
void buf_writer_pipe(buf_writer_t *buf_writer, read_cb_t *read_cb,
|
void buf_writer_pipe(
|
||||||
void *read_cbopaque);
|
buf_writer_t *buf_writer, read_cb_t *read_cb, void *read_cbopaque);
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_BUF_WRITER_H */
|
#endif /* JEMALLOC_INTERNAL_BUF_WRITER_H */
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ extern const uintptr_t disabled_bin;
|
|||||||
* 1 << (sizeof(cache_bin_sz_t) * 8)
|
* 1 << (sizeof(cache_bin_sz_t) * 8)
|
||||||
* bytes spread across pointer sized objects to get the maximum.
|
* bytes spread across pointer sized objects to get the maximum.
|
||||||
*/
|
*/
|
||||||
#define CACHE_BIN_NCACHED_MAX (((size_t)1 << sizeof(cache_bin_sz_t) * 8) \
|
#define CACHE_BIN_NCACHED_MAX \
|
||||||
/ sizeof(void *) - 1)
|
(((size_t)1 << sizeof(cache_bin_sz_t) * 8) / sizeof(void *) - 1)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This lives inside the cache_bin (for locality reasons), and is initialized
|
* This lives inside the cache_bin (for locality reasons), and is initialized
|
||||||
@@ -152,8 +152,8 @@ struct cache_bin_array_descriptor_s {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
cache_bin_array_descriptor_init(cache_bin_array_descriptor_t *descriptor,
|
cache_bin_array_descriptor_init(
|
||||||
cache_bin_t *bins) {
|
cache_bin_array_descriptor_t *descriptor, cache_bin_t *bins) {
|
||||||
ql_elm_new(descriptor, link);
|
ql_elm_new(descriptor, link);
|
||||||
descriptor->bins = bins;
|
descriptor->bins = bins;
|
||||||
}
|
}
|
||||||
@@ -222,7 +222,8 @@ cache_bin_ncached_max_get(cache_bin_t *bin) {
|
|||||||
* with later.
|
* with later.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
cache_bin_assert_earlier(cache_bin_t *bin, cache_bin_sz_t earlier, cache_bin_sz_t later) {
|
cache_bin_assert_earlier(
|
||||||
|
cache_bin_t *bin, cache_bin_sz_t earlier, cache_bin_sz_t later) {
|
||||||
if (earlier > later) {
|
if (earlier > later) {
|
||||||
assert(bin->low_bits_full > bin->low_bits_empty);
|
assert(bin->low_bits_full > bin->low_bits_empty);
|
||||||
}
|
}
|
||||||
@@ -305,8 +306,8 @@ cache_bin_empty_position_get(cache_bin_t *bin) {
|
|||||||
*/
|
*/
|
||||||
static inline cache_bin_sz_t
|
static inline cache_bin_sz_t
|
||||||
cache_bin_low_bits_low_bound_get(cache_bin_t *bin) {
|
cache_bin_low_bits_low_bound_get(cache_bin_t *bin) {
|
||||||
return (cache_bin_sz_t)bin->low_bits_empty -
|
return (cache_bin_sz_t)bin->low_bits_empty
|
||||||
cache_bin_ncached_max_get(bin) * sizeof(void *);
|
- cache_bin_ncached_max_get(bin) * sizeof(void *);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -340,8 +341,8 @@ cache_bin_assert_empty(cache_bin_t *bin) {
|
|||||||
*/
|
*/
|
||||||
static inline cache_bin_sz_t
|
static inline cache_bin_sz_t
|
||||||
cache_bin_low_water_get_internal(cache_bin_t *bin) {
|
cache_bin_low_water_get_internal(cache_bin_t *bin) {
|
||||||
return cache_bin_diff(bin, bin->low_bits_low_water,
|
return cache_bin_diff(bin, bin->low_bits_low_water, bin->low_bits_empty)
|
||||||
bin->low_bits_empty) / sizeof(void *);
|
/ sizeof(void *);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the numeric value of low water in [0, ncached]. */
|
/* Returns the numeric value of low water in [0, ncached]. */
|
||||||
@@ -351,7 +352,8 @@ cache_bin_low_water_get(cache_bin_t *bin) {
|
|||||||
assert(low_water <= cache_bin_ncached_max_get(bin));
|
assert(low_water <= cache_bin_ncached_max_get(bin));
|
||||||
assert(low_water <= cache_bin_ncached_get_local(bin));
|
assert(low_water <= cache_bin_ncached_get_local(bin));
|
||||||
|
|
||||||
cache_bin_assert_earlier(bin, (cache_bin_sz_t)(uintptr_t)bin->stack_head,
|
cache_bin_assert_earlier(bin,
|
||||||
|
(cache_bin_sz_t)(uintptr_t)bin->stack_head,
|
||||||
bin->low_bits_low_water);
|
bin->low_bits_low_water);
|
||||||
|
|
||||||
return low_water;
|
return low_water;
|
||||||
@@ -455,7 +457,8 @@ cache_bin_alloc_batch(cache_bin_t *bin, size_t num, void **out) {
|
|||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE bool
|
JEMALLOC_ALWAYS_INLINE bool
|
||||||
cache_bin_full(cache_bin_t *bin) {
|
cache_bin_full(cache_bin_t *bin) {
|
||||||
return ((cache_bin_sz_t)(uintptr_t)bin->stack_head == bin->low_bits_full);
|
return (
|
||||||
|
(cache_bin_sz_t)(uintptr_t)bin->stack_head == bin->low_bits_full);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -516,9 +519,11 @@ cache_bin_stash(cache_bin_t *bin, void *ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Stash at the full position, in the [full, head) range. */
|
/* Stash at the full position, in the [full, head) range. */
|
||||||
cache_bin_sz_t low_bits_head = (cache_bin_sz_t)(uintptr_t)bin->stack_head;
|
cache_bin_sz_t low_bits_head = (cache_bin_sz_t)(uintptr_t)
|
||||||
|
bin->stack_head;
|
||||||
/* Wraparound handled as well. */
|
/* Wraparound handled as well. */
|
||||||
cache_bin_sz_t diff = cache_bin_diff(bin, bin->low_bits_full, low_bits_head);
|
cache_bin_sz_t diff = cache_bin_diff(
|
||||||
|
bin, bin->low_bits_full, low_bits_head);
|
||||||
*(void **)((byte_t *)bin->stack_head - diff) = ptr;
|
*(void **)((byte_t *)bin->stack_head - diff) = ptr;
|
||||||
|
|
||||||
assert(!cache_bin_full(bin));
|
assert(!cache_bin_full(bin));
|
||||||
@@ -532,16 +537,19 @@ cache_bin_stash(cache_bin_t *bin, void *ptr) {
|
|||||||
JEMALLOC_ALWAYS_INLINE cache_bin_sz_t
|
JEMALLOC_ALWAYS_INLINE cache_bin_sz_t
|
||||||
cache_bin_nstashed_get_internal(cache_bin_t *bin) {
|
cache_bin_nstashed_get_internal(cache_bin_t *bin) {
|
||||||
cache_bin_sz_t ncached_max = cache_bin_ncached_max_get(bin);
|
cache_bin_sz_t ncached_max = cache_bin_ncached_max_get(bin);
|
||||||
cache_bin_sz_t low_bits_low_bound = cache_bin_low_bits_low_bound_get(bin);
|
cache_bin_sz_t low_bits_low_bound = cache_bin_low_bits_low_bound_get(
|
||||||
|
bin);
|
||||||
|
|
||||||
cache_bin_sz_t n = cache_bin_diff(bin, low_bits_low_bound,
|
cache_bin_sz_t n = cache_bin_diff(
|
||||||
bin->low_bits_full) / sizeof(void *);
|
bin, low_bits_low_bound, bin->low_bits_full)
|
||||||
|
/ sizeof(void *);
|
||||||
assert(n <= ncached_max);
|
assert(n <= ncached_max);
|
||||||
if (config_debug && n != 0) {
|
if (config_debug && n != 0) {
|
||||||
/* Below are for assertions only. */
|
/* Below are for assertions only. */
|
||||||
void **low_bound = cache_bin_low_bound_get(bin);
|
void **low_bound = cache_bin_low_bound_get(bin);
|
||||||
|
|
||||||
assert((cache_bin_sz_t)(uintptr_t)low_bound == low_bits_low_bound);
|
assert(
|
||||||
|
(cache_bin_sz_t)(uintptr_t)low_bound == low_bits_low_bound);
|
||||||
void *stashed = *(low_bound + n - 1);
|
void *stashed = *(low_bound + n - 1);
|
||||||
bool aligned = cache_bin_nonfast_aligned(stashed);
|
bool aligned = cache_bin_nonfast_aligned(stashed);
|
||||||
#ifdef JEMALLOC_JET
|
#ifdef JEMALLOC_JET
|
||||||
@@ -582,16 +590,17 @@ cache_bin_nstashed_get_local(cache_bin_t *bin) {
|
|||||||
* they help access values that will not be concurrently modified.
|
* they help access values that will not be concurrently modified.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
cache_bin_nitems_get_remote(cache_bin_t *bin, cache_bin_sz_t *ncached,
|
cache_bin_nitems_get_remote(
|
||||||
cache_bin_sz_t *nstashed) {
|
cache_bin_t *bin, cache_bin_sz_t *ncached, cache_bin_sz_t *nstashed) {
|
||||||
/* Racy version of cache_bin_ncached_get_internal. */
|
/* Racy version of cache_bin_ncached_get_internal. */
|
||||||
cache_bin_sz_t diff = bin->low_bits_empty -
|
cache_bin_sz_t diff = bin->low_bits_empty
|
||||||
(cache_bin_sz_t)(uintptr_t)bin->stack_head;
|
- (cache_bin_sz_t)(uintptr_t)bin->stack_head;
|
||||||
cache_bin_sz_t n = diff / sizeof(void *);
|
cache_bin_sz_t n = diff / sizeof(void *);
|
||||||
*ncached = n;
|
*ncached = n;
|
||||||
|
|
||||||
/* Racy version of cache_bin_nstashed_get_internal. */
|
/* Racy version of cache_bin_nstashed_get_internal. */
|
||||||
cache_bin_sz_t low_bits_low_bound = cache_bin_low_bits_low_bound_get(bin);
|
cache_bin_sz_t low_bits_low_bound = cache_bin_low_bits_low_bound_get(
|
||||||
|
bin);
|
||||||
n = (bin->low_bits_full - low_bits_low_bound) / sizeof(void *);
|
n = (bin->low_bits_full - low_bits_low_bound) / sizeof(void *);
|
||||||
*nstashed = n;
|
*nstashed = n;
|
||||||
/*
|
/*
|
||||||
@@ -616,7 +625,8 @@ struct cache_bin_fill_ctl_s {
|
|||||||
* This is to avoid stack overflow when we do batch edata look up, which
|
* This is to avoid stack overflow when we do batch edata look up, which
|
||||||
* reserves a nflush * sizeof(emap_batch_lookup_result_t) stack variable.
|
* reserves a nflush * sizeof(emap_batch_lookup_result_t) stack variable.
|
||||||
*/
|
*/
|
||||||
#define CACHE_BIN_NFLUSH_BATCH_MAX ((VARIABLE_ARRAY_SIZE_MAX >> LG_SIZEOF_PTR) - 1)
|
#define CACHE_BIN_NFLUSH_BATCH_MAX \
|
||||||
|
((VARIABLE_ARRAY_SIZE_MAX >> LG_SIZEOF_PTR) - 1)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Filling and flushing are done in batch, on arrays of void *s. For filling,
|
* Filling and flushing are done in batch, on arrays of void *s. For filling,
|
||||||
@@ -659,8 +669,8 @@ struct cache_bin_ptr_array_s {
|
|||||||
* finish_fill call before doing any alloc/dalloc operations on the bin.
|
* finish_fill call before doing any alloc/dalloc operations on the bin.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
cache_bin_init_ptr_array_for_fill(cache_bin_t *bin, cache_bin_ptr_array_t *arr,
|
cache_bin_init_ptr_array_for_fill(
|
||||||
cache_bin_sz_t nfill) {
|
cache_bin_t *bin, cache_bin_ptr_array_t *arr, cache_bin_sz_t nfill) {
|
||||||
cache_bin_assert_empty(bin);
|
cache_bin_assert_empty(bin);
|
||||||
arr->ptr = cache_bin_empty_position_get(bin) - nfill;
|
arr->ptr = cache_bin_empty_position_get(bin) - nfill;
|
||||||
}
|
}
|
||||||
@@ -671,8 +681,8 @@ cache_bin_init_ptr_array_for_fill(cache_bin_t *bin, cache_bin_ptr_array_t *arr,
|
|||||||
* case of OOM.
|
* case of OOM.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
cache_bin_finish_fill(cache_bin_t *bin, cache_bin_ptr_array_t *arr,
|
cache_bin_finish_fill(
|
||||||
cache_bin_sz_t nfilled) {
|
cache_bin_t *bin, cache_bin_ptr_array_t *arr, cache_bin_sz_t nfilled) {
|
||||||
cache_bin_assert_empty(bin);
|
cache_bin_assert_empty(bin);
|
||||||
void **empty_position = cache_bin_empty_position_get(bin);
|
void **empty_position = cache_bin_empty_position_get(bin);
|
||||||
if (nfilled < arr->n) {
|
if (nfilled < arr->n) {
|
||||||
@@ -687,19 +697,18 @@ cache_bin_finish_fill(cache_bin_t *bin, cache_bin_ptr_array_t *arr,
|
|||||||
* everything we give them.
|
* everything we give them.
|
||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
cache_bin_init_ptr_array_for_flush(cache_bin_t *bin,
|
cache_bin_init_ptr_array_for_flush(
|
||||||
cache_bin_ptr_array_t *arr, cache_bin_sz_t nflush) {
|
cache_bin_t *bin, cache_bin_ptr_array_t *arr, cache_bin_sz_t nflush) {
|
||||||
arr->ptr = cache_bin_empty_position_get(bin) - nflush;
|
arr->ptr = cache_bin_empty_position_get(bin) - nflush;
|
||||||
assert(cache_bin_ncached_get_local(bin) == 0
|
assert(cache_bin_ncached_get_local(bin) == 0 || *arr->ptr != NULL);
|
||||||
|| *arr->ptr != NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
cache_bin_finish_flush(cache_bin_t *bin, cache_bin_ptr_array_t *arr,
|
cache_bin_finish_flush(
|
||||||
cache_bin_sz_t nflushed) {
|
cache_bin_t *bin, cache_bin_ptr_array_t *arr, cache_bin_sz_t nflushed) {
|
||||||
unsigned rem = cache_bin_ncached_get_local(bin) - nflushed;
|
unsigned rem = cache_bin_ncached_get_local(bin) - nflushed;
|
||||||
memmove(bin->stack_head + nflushed, bin->stack_head,
|
memmove(
|
||||||
rem * sizeof(void *));
|
bin->stack_head + nflushed, bin->stack_head, rem * sizeof(void *));
|
||||||
bin->stack_head += nflushed;
|
bin->stack_head += nflushed;
|
||||||
cache_bin_low_water_adjust(bin);
|
cache_bin_low_water_adjust(bin);
|
||||||
}
|
}
|
||||||
@@ -728,14 +737,14 @@ cache_bin_finish_flush_stashed(cache_bin_t *bin) {
|
|||||||
* Initialize a cache_bin_info to represent up to the given number of items in
|
* Initialize a cache_bin_info to represent up to the given number of items in
|
||||||
* the cache_bins it is associated with.
|
* the cache_bins it is associated with.
|
||||||
*/
|
*/
|
||||||
void cache_bin_info_init(cache_bin_info_t *bin_info,
|
void cache_bin_info_init(
|
||||||
cache_bin_sz_t ncached_max);
|
cache_bin_info_t *bin_info, cache_bin_sz_t ncached_max);
|
||||||
/*
|
/*
|
||||||
* Given an array of initialized cache_bin_info_ts, determine how big an
|
* Given an array of initialized cache_bin_info_ts, determine how big an
|
||||||
* allocation is required to initialize a full set of cache_bin_ts.
|
* allocation is required to initialize a full set of cache_bin_ts.
|
||||||
*/
|
*/
|
||||||
void cache_bin_info_compute_alloc(const cache_bin_info_t *infos,
|
void cache_bin_info_compute_alloc(const cache_bin_info_t *infos, szind_t ninfos,
|
||||||
szind_t ninfos, size_t *size, size_t *alignment);
|
size_t *size, size_t *alignment);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Actually initialize some cache bins. Callers should allocate the backing
|
* Actually initialize some cache bins. Callers should allocate the backing
|
||||||
@@ -747,8 +756,8 @@ void cache_bin_info_compute_alloc(const cache_bin_info_t *infos,
|
|||||||
void cache_bin_preincrement(const cache_bin_info_t *infos, szind_t ninfos,
|
void cache_bin_preincrement(const cache_bin_info_t *infos, szind_t ninfos,
|
||||||
void *alloc, size_t *cur_offset);
|
void *alloc, size_t *cur_offset);
|
||||||
void cache_bin_postincrement(void *alloc, size_t *cur_offset);
|
void cache_bin_postincrement(void *alloc, size_t *cur_offset);
|
||||||
void cache_bin_init(cache_bin_t *bin, const cache_bin_info_t *info,
|
void cache_bin_init(cache_bin_t *bin, const cache_bin_info_t *info, void *alloc,
|
||||||
void *alloc, size_t *cur_offset);
|
size_t *cur_offset);
|
||||||
void cache_bin_init_disabled(cache_bin_t *bin, cache_bin_sz_t ncached_max);
|
void cache_bin_init_disabled(cache_bin_t *bin, cache_bin_sz_t ncached_max);
|
||||||
|
|
||||||
bool cache_bin_stack_use_thp(void);
|
bool cache_bin_stack_use_thp(void);
|
||||||
|
|||||||
@@ -89,8 +89,8 @@ bool ckh_iter(ckh_t *ckh, size_t *tabind, void **key, void **data);
|
|||||||
* the key and value, and doesn't do any lifetime management.
|
* the key and value, and doesn't do any lifetime management.
|
||||||
*/
|
*/
|
||||||
bool ckh_insert(tsd_t *tsd, ckh_t *ckh, const void *key, const void *data);
|
bool ckh_insert(tsd_t *tsd, ckh_t *ckh, const void *key, const void *data);
|
||||||
bool ckh_remove(tsd_t *tsd, ckh_t *ckh, const void *searchkey, void **key,
|
bool ckh_remove(
|
||||||
void **data);
|
tsd_t *tsd, ckh_t *ckh, const void *searchkey, void **key, void **data);
|
||||||
bool ckh_search(ckh_t *ckh, const void *searchkey, void **key, void **data);
|
bool ckh_search(ckh_t *ckh, const void *searchkey, void **key, void **data);
|
||||||
|
|
||||||
/* Some useful hash and comparison functions for strings and pointers. */
|
/* Some useful hash and comparison functions for strings and pointers. */
|
||||||
|
|||||||
@@ -26,14 +26,14 @@ typedef struct ctl_named_node_s {
|
|||||||
/* If (nchildren == 0), this is a terminal node. */
|
/* If (nchildren == 0), this is a terminal node. */
|
||||||
size_t nchildren;
|
size_t nchildren;
|
||||||
const ctl_node_t *children;
|
const ctl_node_t *children;
|
||||||
int (*ctl)(tsd_t *, const size_t *, size_t, void *, size_t *, void *,
|
int (*ctl)(
|
||||||
size_t);
|
tsd_t *, const size_t *, size_t, void *, size_t *, void *, size_t);
|
||||||
} ctl_named_node_t;
|
} ctl_named_node_t;
|
||||||
|
|
||||||
typedef struct ctl_indexed_node_s {
|
typedef struct ctl_indexed_node_s {
|
||||||
struct ctl_node_s node;
|
struct ctl_node_s node;
|
||||||
const ctl_named_node_t *(*index)(tsdn_t *, const size_t *, size_t,
|
const ctl_named_node_t *(*index)(
|
||||||
size_t);
|
tsdn_t *, const size_t *, size_t, size_t);
|
||||||
} ctl_indexed_node_t;
|
} ctl_indexed_node_t;
|
||||||
|
|
||||||
typedef struct ctl_arena_stats_s {
|
typedef struct ctl_arena_stats_s {
|
||||||
@@ -107,8 +107,8 @@ int ctl_byname(tsd_t *tsd, const char *name, void *oldp, size_t *oldlenp,
|
|||||||
int ctl_nametomib(tsd_t *tsd, const char *name, size_t *mibp, size_t *miblenp);
|
int ctl_nametomib(tsd_t *tsd, const char *name, size_t *mibp, size_t *miblenp);
|
||||||
int ctl_bymib(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
int ctl_bymib(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
||||||
size_t *oldlenp, void *newp, size_t newlen);
|
size_t *oldlenp, void *newp, size_t newlen);
|
||||||
int ctl_mibnametomib(tsd_t *tsd, size_t *mib, size_t miblen, const char *name,
|
int ctl_mibnametomib(
|
||||||
size_t *miblenp);
|
tsd_t *tsd, size_t *mib, size_t miblen, const char *name, size_t *miblenp);
|
||||||
int ctl_bymibname(tsd_t *tsd, size_t *mib, size_t miblen, const char *name,
|
int ctl_bymibname(tsd_t *tsd, size_t *mib, size_t miblen, const char *name,
|
||||||
size_t *miblenp, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
|
size_t *miblenp, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
|
||||||
bool ctl_boot(void);
|
bool ctl_boot(void);
|
||||||
@@ -117,9 +117,9 @@ void ctl_postfork_parent(tsdn_t *tsdn);
|
|||||||
void ctl_postfork_child(tsdn_t *tsdn);
|
void ctl_postfork_child(tsdn_t *tsdn);
|
||||||
void ctl_mtx_assert_held(tsdn_t *tsdn);
|
void ctl_mtx_assert_held(tsdn_t *tsdn);
|
||||||
|
|
||||||
#define xmallctl(name, oldp, oldlenp, newp, newlen) do { \
|
#define xmallctl(name, oldp, oldlenp, newp, newlen) \
|
||||||
if (je_mallctl(name, oldp, oldlenp, newp, newlen) \
|
do { \
|
||||||
!= 0) { \
|
if (je_mallctl(name, oldp, oldlenp, newp, newlen) != 0) { \
|
||||||
malloc_printf( \
|
malloc_printf( \
|
||||||
"<jemalloc>: Failure in xmallctl(\"%s\", ...)\n", \
|
"<jemalloc>: Failure in xmallctl(\"%s\", ...)\n", \
|
||||||
name); \
|
name); \
|
||||||
@@ -127,24 +127,29 @@ void ctl_mtx_assert_held(tsdn_t *tsdn);
|
|||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define xmallctlnametomib(name, mibp, miblenp) do { \
|
#define xmallctlnametomib(name, mibp, miblenp) \
|
||||||
|
do { \
|
||||||
if (je_mallctlnametomib(name, mibp, miblenp) != 0) { \
|
if (je_mallctlnametomib(name, mibp, miblenp) != 0) { \
|
||||||
malloc_printf("<jemalloc>: Failure in " \
|
malloc_printf( \
|
||||||
"xmallctlnametomib(\"%s\", ...)\n", name); \
|
"<jemalloc>: Failure in " \
|
||||||
|
"xmallctlnametomib(\"%s\", ...)\n", \
|
||||||
|
name); \
|
||||||
abort(); \
|
abort(); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define xmallctlbymib(mib, miblen, oldp, oldlenp, newp, newlen) do { \
|
#define xmallctlbymib(mib, miblen, oldp, oldlenp, newp, newlen) \
|
||||||
if (je_mallctlbymib(mib, miblen, oldp, oldlenp, newp, \
|
do { \
|
||||||
newlen) != 0) { \
|
if (je_mallctlbymib(mib, miblen, oldp, oldlenp, newp, newlen) \
|
||||||
|
!= 0) { \
|
||||||
malloc_write( \
|
malloc_write( \
|
||||||
"<jemalloc>: Failure in xmallctlbymib()\n"); \
|
"<jemalloc>: Failure in xmallctlbymib()\n"); \
|
||||||
abort(); \
|
abort(); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define xmallctlmibnametomib(mib, miblen, name, miblenp) do { \
|
#define xmallctlmibnametomib(mib, miblen, name, miblenp) \
|
||||||
|
do { \
|
||||||
if (ctl_mibnametomib(tsd_fetch(), mib, miblen, name, miblenp) \
|
if (ctl_mibnametomib(tsd_fetch(), mib, miblen, name, miblenp) \
|
||||||
!= 0) { \
|
!= 0) { \
|
||||||
malloc_write( \
|
malloc_write( \
|
||||||
@@ -153,10 +158,12 @@ void ctl_mtx_assert_held(tsdn_t *tsdn);
|
|||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define xmallctlbymibname(mib, miblen, name, miblenp, oldp, oldlenp, \
|
#define xmallctlbymibname( \
|
||||||
newp, newlen) do { \
|
mib, miblen, name, miblenp, oldp, oldlenp, newp, newlen) \
|
||||||
|
do { \
|
||||||
if (ctl_bymibname(tsd_fetch(), mib, miblen, name, miblenp, \
|
if (ctl_bymibname(tsd_fetch(), mib, miblen, name, miblenp, \
|
||||||
oldp, oldlenp, newp, newlen) != 0) { \
|
oldp, oldlenp, newp, newlen) \
|
||||||
|
!= 0) { \
|
||||||
malloc_write( \
|
malloc_write( \
|
||||||
"<jemalloc>: Failure in ctl_bymibname()\n"); \
|
"<jemalloc>: Failure in ctl_bymibname()\n"); \
|
||||||
abort(); \
|
abort(); \
|
||||||
|
|||||||
@@ -168,12 +168,12 @@ void decay_reinit(decay_t *decay, nstime_t *cur_time, ssize_t decay_ms);
|
|||||||
/*
|
/*
|
||||||
* Compute how many of 'npages_new' pages we would need to purge in 'time'.
|
* Compute how many of 'npages_new' pages we would need to purge in 'time'.
|
||||||
*/
|
*/
|
||||||
uint64_t decay_npages_purge_in(decay_t *decay, nstime_t *time,
|
uint64_t decay_npages_purge_in(
|
||||||
size_t npages_new);
|
decay_t *decay, nstime_t *time, size_t npages_new);
|
||||||
|
|
||||||
/* Returns true if the epoch advanced and there are pages to purge. */
|
/* Returns true if the epoch advanced and there are pages to purge. */
|
||||||
bool decay_maybe_advance_epoch(decay_t *decay, nstime_t *new_time,
|
bool decay_maybe_advance_epoch(
|
||||||
size_t current_npages);
|
decay_t *decay, nstime_t *new_time, size_t current_npages);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculates wait time until a number of pages in the interval
|
* Calculates wait time until a number of pages in the interval
|
||||||
@@ -182,7 +182,7 @@ bool decay_maybe_advance_epoch(decay_t *decay, nstime_t *new_time,
|
|||||||
* Returns number of nanoseconds or DECAY_UNBOUNDED_TIME_TO_PURGE in case of
|
* Returns number of nanoseconds or DECAY_UNBOUNDED_TIME_TO_PURGE in case of
|
||||||
* indefinite wait.
|
* indefinite wait.
|
||||||
*/
|
*/
|
||||||
uint64_t decay_ns_until_purge(decay_t *decay, size_t npages_current,
|
uint64_t decay_ns_until_purge(
|
||||||
uint64_t npages_threshold);
|
decay_t *decay, size_t npages_current, uint64_t npages_threshold);
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_DECAY_H */
|
#endif /* JEMALLOC_INTERNAL_DECAY_H */
|
||||||
|
|||||||
@@ -24,22 +24,22 @@ struct ecache_s {
|
|||||||
|
|
||||||
static inline size_t
|
static inline size_t
|
||||||
ecache_npages_get(ecache_t *ecache) {
|
ecache_npages_get(ecache_t *ecache) {
|
||||||
return eset_npages_get(&ecache->eset) +
|
return eset_npages_get(&ecache->eset)
|
||||||
eset_npages_get(&ecache->guarded_eset);
|
+ eset_npages_get(&ecache->guarded_eset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the number of extents in the given page size index. */
|
/* Get the number of extents in the given page size index. */
|
||||||
static inline size_t
|
static inline size_t
|
||||||
ecache_nextents_get(ecache_t *ecache, pszind_t ind) {
|
ecache_nextents_get(ecache_t *ecache, pszind_t ind) {
|
||||||
return eset_nextents_get(&ecache->eset, ind) +
|
return eset_nextents_get(&ecache->eset, ind)
|
||||||
eset_nextents_get(&ecache->guarded_eset, ind);
|
+ eset_nextents_get(&ecache->guarded_eset, ind);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the sum total bytes of the extents in the given page size index. */
|
/* Get the sum total bytes of the extents in the given page size index. */
|
||||||
static inline size_t
|
static inline size_t
|
||||||
ecache_nbytes_get(ecache_t *ecache, pszind_t ind) {
|
ecache_nbytes_get(ecache_t *ecache, pszind_t ind) {
|
||||||
return eset_nbytes_get(&ecache->eset, ind) +
|
return eset_nbytes_get(&ecache->eset, ind)
|
||||||
eset_nbytes_get(&ecache->guarded_eset, ind);
|
+ eset_nbytes_get(&ecache->guarded_eset, ind);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned
|
static inline unsigned
|
||||||
|
|||||||
@@ -50,10 +50,7 @@ typedef enum extent_head_state_e extent_head_state_t;
|
|||||||
* Which implementation of the page allocator interface, (PAI, defined in
|
* Which implementation of the page allocator interface, (PAI, defined in
|
||||||
* pai.h) owns the given extent?
|
* pai.h) owns the given extent?
|
||||||
*/
|
*/
|
||||||
enum extent_pai_e {
|
enum extent_pai_e { EXTENT_PAI_PAC = 0, EXTENT_PAI_HPA = 1 };
|
||||||
EXTENT_PAI_PAC = 0,
|
|
||||||
EXTENT_PAI_HPA = 1
|
|
||||||
};
|
|
||||||
typedef enum extent_pai_e extent_pai_t;
|
typedef enum extent_pai_e extent_pai_t;
|
||||||
|
|
||||||
struct e_prof_info_s {
|
struct e_prof_info_s {
|
||||||
@@ -150,51 +147,68 @@ struct edata_s {
|
|||||||
* bin_shard: the shard of the bin from which this extent came.
|
* bin_shard: the shard of the bin from which this extent came.
|
||||||
*/
|
*/
|
||||||
uint64_t e_bits;
|
uint64_t e_bits;
|
||||||
#define MASK(CURRENT_FIELD_WIDTH, CURRENT_FIELD_SHIFT) ((((((uint64_t)0x1U) << (CURRENT_FIELD_WIDTH)) - 1)) << (CURRENT_FIELD_SHIFT))
|
#define MASK(CURRENT_FIELD_WIDTH, CURRENT_FIELD_SHIFT) \
|
||||||
|
((((((uint64_t)0x1U) << (CURRENT_FIELD_WIDTH)) - 1)) \
|
||||||
|
<< (CURRENT_FIELD_SHIFT))
|
||||||
|
|
||||||
#define EDATA_BITS_ARENA_WIDTH MALLOCX_ARENA_BITS
|
#define EDATA_BITS_ARENA_WIDTH MALLOCX_ARENA_BITS
|
||||||
#define EDATA_BITS_ARENA_SHIFT 0
|
#define EDATA_BITS_ARENA_SHIFT 0
|
||||||
#define EDATA_BITS_ARENA_MASK MASK(EDATA_BITS_ARENA_WIDTH, EDATA_BITS_ARENA_SHIFT)
|
#define EDATA_BITS_ARENA_MASK \
|
||||||
|
MASK(EDATA_BITS_ARENA_WIDTH, EDATA_BITS_ARENA_SHIFT)
|
||||||
|
|
||||||
#define EDATA_BITS_SLAB_WIDTH 1
|
#define EDATA_BITS_SLAB_WIDTH 1
|
||||||
#define EDATA_BITS_SLAB_SHIFT (EDATA_BITS_ARENA_WIDTH + EDATA_BITS_ARENA_SHIFT)
|
#define EDATA_BITS_SLAB_SHIFT (EDATA_BITS_ARENA_WIDTH + EDATA_BITS_ARENA_SHIFT)
|
||||||
#define EDATA_BITS_SLAB_MASK MASK(EDATA_BITS_SLAB_WIDTH, EDATA_BITS_SLAB_SHIFT)
|
#define EDATA_BITS_SLAB_MASK MASK(EDATA_BITS_SLAB_WIDTH, EDATA_BITS_SLAB_SHIFT)
|
||||||
|
|
||||||
#define EDATA_BITS_COMMITTED_WIDTH 1
|
#define EDATA_BITS_COMMITTED_WIDTH 1
|
||||||
#define EDATA_BITS_COMMITTED_SHIFT (EDATA_BITS_SLAB_WIDTH + EDATA_BITS_SLAB_SHIFT)
|
#define EDATA_BITS_COMMITTED_SHIFT \
|
||||||
#define EDATA_BITS_COMMITTED_MASK MASK(EDATA_BITS_COMMITTED_WIDTH, EDATA_BITS_COMMITTED_SHIFT)
|
(EDATA_BITS_SLAB_WIDTH + EDATA_BITS_SLAB_SHIFT)
|
||||||
|
#define EDATA_BITS_COMMITTED_MASK \
|
||||||
|
MASK(EDATA_BITS_COMMITTED_WIDTH, EDATA_BITS_COMMITTED_SHIFT)
|
||||||
|
|
||||||
#define EDATA_BITS_PAI_WIDTH 1
|
#define EDATA_BITS_PAI_WIDTH 1
|
||||||
#define EDATA_BITS_PAI_SHIFT (EDATA_BITS_COMMITTED_WIDTH + EDATA_BITS_COMMITTED_SHIFT)
|
#define EDATA_BITS_PAI_SHIFT \
|
||||||
|
(EDATA_BITS_COMMITTED_WIDTH + EDATA_BITS_COMMITTED_SHIFT)
|
||||||
#define EDATA_BITS_PAI_MASK MASK(EDATA_BITS_PAI_WIDTH, EDATA_BITS_PAI_SHIFT)
|
#define EDATA_BITS_PAI_MASK MASK(EDATA_BITS_PAI_WIDTH, EDATA_BITS_PAI_SHIFT)
|
||||||
|
|
||||||
#define EDATA_BITS_ZEROED_WIDTH 1
|
#define EDATA_BITS_ZEROED_WIDTH 1
|
||||||
#define EDATA_BITS_ZEROED_SHIFT (EDATA_BITS_PAI_WIDTH + EDATA_BITS_PAI_SHIFT)
|
#define EDATA_BITS_ZEROED_SHIFT (EDATA_BITS_PAI_WIDTH + EDATA_BITS_PAI_SHIFT)
|
||||||
#define EDATA_BITS_ZEROED_MASK MASK(EDATA_BITS_ZEROED_WIDTH, EDATA_BITS_ZEROED_SHIFT)
|
#define EDATA_BITS_ZEROED_MASK \
|
||||||
|
MASK(EDATA_BITS_ZEROED_WIDTH, EDATA_BITS_ZEROED_SHIFT)
|
||||||
|
|
||||||
#define EDATA_BITS_GUARDED_WIDTH 1
|
#define EDATA_BITS_GUARDED_WIDTH 1
|
||||||
#define EDATA_BITS_GUARDED_SHIFT (EDATA_BITS_ZEROED_WIDTH + EDATA_BITS_ZEROED_SHIFT)
|
#define EDATA_BITS_GUARDED_SHIFT \
|
||||||
#define EDATA_BITS_GUARDED_MASK MASK(EDATA_BITS_GUARDED_WIDTH, EDATA_BITS_GUARDED_SHIFT)
|
(EDATA_BITS_ZEROED_WIDTH + EDATA_BITS_ZEROED_SHIFT)
|
||||||
|
#define EDATA_BITS_GUARDED_MASK \
|
||||||
|
MASK(EDATA_BITS_GUARDED_WIDTH, EDATA_BITS_GUARDED_SHIFT)
|
||||||
|
|
||||||
#define EDATA_BITS_STATE_WIDTH 3
|
#define EDATA_BITS_STATE_WIDTH 3
|
||||||
#define EDATA_BITS_STATE_SHIFT (EDATA_BITS_GUARDED_WIDTH + EDATA_BITS_GUARDED_SHIFT)
|
#define EDATA_BITS_STATE_SHIFT \
|
||||||
#define EDATA_BITS_STATE_MASK MASK(EDATA_BITS_STATE_WIDTH, EDATA_BITS_STATE_SHIFT)
|
(EDATA_BITS_GUARDED_WIDTH + EDATA_BITS_GUARDED_SHIFT)
|
||||||
|
#define EDATA_BITS_STATE_MASK \
|
||||||
|
MASK(EDATA_BITS_STATE_WIDTH, EDATA_BITS_STATE_SHIFT)
|
||||||
|
|
||||||
#define EDATA_BITS_SZIND_WIDTH LG_CEIL(SC_NSIZES)
|
#define EDATA_BITS_SZIND_WIDTH LG_CEIL(SC_NSIZES)
|
||||||
#define EDATA_BITS_SZIND_SHIFT (EDATA_BITS_STATE_WIDTH + EDATA_BITS_STATE_SHIFT)
|
#define EDATA_BITS_SZIND_SHIFT (EDATA_BITS_STATE_WIDTH + EDATA_BITS_STATE_SHIFT)
|
||||||
#define EDATA_BITS_SZIND_MASK MASK(EDATA_BITS_SZIND_WIDTH, EDATA_BITS_SZIND_SHIFT)
|
#define EDATA_BITS_SZIND_MASK \
|
||||||
|
MASK(EDATA_BITS_SZIND_WIDTH, EDATA_BITS_SZIND_SHIFT)
|
||||||
|
|
||||||
#define EDATA_BITS_NFREE_WIDTH (SC_LG_SLAB_MAXREGS + 1)
|
#define EDATA_BITS_NFREE_WIDTH (SC_LG_SLAB_MAXREGS + 1)
|
||||||
#define EDATA_BITS_NFREE_SHIFT (EDATA_BITS_SZIND_WIDTH + EDATA_BITS_SZIND_SHIFT)
|
#define EDATA_BITS_NFREE_SHIFT (EDATA_BITS_SZIND_WIDTH + EDATA_BITS_SZIND_SHIFT)
|
||||||
#define EDATA_BITS_NFREE_MASK MASK(EDATA_BITS_NFREE_WIDTH, EDATA_BITS_NFREE_SHIFT)
|
#define EDATA_BITS_NFREE_MASK \
|
||||||
|
MASK(EDATA_BITS_NFREE_WIDTH, EDATA_BITS_NFREE_SHIFT)
|
||||||
|
|
||||||
#define EDATA_BITS_BINSHARD_WIDTH 6
|
#define EDATA_BITS_BINSHARD_WIDTH 6
|
||||||
#define EDATA_BITS_BINSHARD_SHIFT (EDATA_BITS_NFREE_WIDTH + EDATA_BITS_NFREE_SHIFT)
|
#define EDATA_BITS_BINSHARD_SHIFT \
|
||||||
#define EDATA_BITS_BINSHARD_MASK MASK(EDATA_BITS_BINSHARD_WIDTH, EDATA_BITS_BINSHARD_SHIFT)
|
(EDATA_BITS_NFREE_WIDTH + EDATA_BITS_NFREE_SHIFT)
|
||||||
|
#define EDATA_BITS_BINSHARD_MASK \
|
||||||
|
MASK(EDATA_BITS_BINSHARD_WIDTH, EDATA_BITS_BINSHARD_SHIFT)
|
||||||
|
|
||||||
#define EDATA_BITS_IS_HEAD_WIDTH 1
|
#define EDATA_BITS_IS_HEAD_WIDTH 1
|
||||||
#define EDATA_BITS_IS_HEAD_SHIFT (EDATA_BITS_BINSHARD_WIDTH + EDATA_BITS_BINSHARD_SHIFT)
|
#define EDATA_BITS_IS_HEAD_SHIFT \
|
||||||
#define EDATA_BITS_IS_HEAD_MASK MASK(EDATA_BITS_IS_HEAD_WIDTH, EDATA_BITS_IS_HEAD_SHIFT)
|
(EDATA_BITS_BINSHARD_WIDTH + EDATA_BITS_BINSHARD_SHIFT)
|
||||||
|
#define EDATA_BITS_IS_HEAD_MASK \
|
||||||
|
MASK(EDATA_BITS_IS_HEAD_WIDTH, EDATA_BITS_IS_HEAD_SHIFT)
|
||||||
|
|
||||||
/* Pointer to the extent that this structure is responsible for. */
|
/* Pointer to the extent that this structure is responsible for. */
|
||||||
void *e_addr;
|
void *e_addr;
|
||||||
@@ -265,8 +279,8 @@ TYPED_LIST(edata_list_inactive, edata_t, ql_link_inactive)
|
|||||||
|
|
||||||
static inline unsigned
|
static inline unsigned
|
||||||
edata_arena_ind_get(const edata_t *edata) {
|
edata_arena_ind_get(const edata_t *edata) {
|
||||||
unsigned arena_ind = (unsigned)((edata->e_bits &
|
unsigned arena_ind = (unsigned)((edata->e_bits & EDATA_BITS_ARENA_MASK)
|
||||||
EDATA_BITS_ARENA_MASK) >> EDATA_BITS_ARENA_SHIFT);
|
>> EDATA_BITS_ARENA_SHIFT);
|
||||||
assert(arena_ind < MALLOCX_ARENA_LIMIT);
|
assert(arena_ind < MALLOCX_ARENA_LIMIT);
|
||||||
|
|
||||||
return arena_ind;
|
return arena_ind;
|
||||||
@@ -274,8 +288,8 @@ edata_arena_ind_get(const edata_t *edata) {
|
|||||||
|
|
||||||
static inline szind_t
|
static inline szind_t
|
||||||
edata_szind_get_maybe_invalid(const edata_t *edata) {
|
edata_szind_get_maybe_invalid(const edata_t *edata) {
|
||||||
szind_t szind = (szind_t)((edata->e_bits & EDATA_BITS_SZIND_MASK) >>
|
szind_t szind = (szind_t)((edata->e_bits & EDATA_BITS_SZIND_MASK)
|
||||||
EDATA_BITS_SZIND_SHIFT);
|
>> EDATA_BITS_SZIND_SHIFT);
|
||||||
assert(szind <= SC_NSIZES);
|
assert(szind <= SC_NSIZES);
|
||||||
return szind;
|
return szind;
|
||||||
}
|
}
|
||||||
@@ -318,8 +332,8 @@ edata_usize_get(const edata_t *edata) {
|
|||||||
|
|
||||||
if (!sz_large_size_classes_disabled() || szind < SC_NBINS) {
|
if (!sz_large_size_classes_disabled() || szind < SC_NBINS) {
|
||||||
size_t usize_from_ind = sz_index2size(szind);
|
size_t usize_from_ind = sz_index2size(szind);
|
||||||
if (!sz_large_size_classes_disabled() &&
|
if (!sz_large_size_classes_disabled()
|
||||||
usize_from_ind >= SC_LARGE_MINCLASS) {
|
&& usize_from_ind >= SC_LARGE_MINCLASS) {
|
||||||
size_t size = (edata->e_size_esn & EDATA_SIZE_MASK);
|
size_t size = (edata->e_size_esn & EDATA_SIZE_MASK);
|
||||||
assert(size > sz_large_pad);
|
assert(size > sz_large_pad);
|
||||||
size_t usize_from_size = size - sz_large_pad;
|
size_t usize_from_size = size - sz_large_pad;
|
||||||
@@ -341,8 +355,9 @@ edata_usize_get(const edata_t *edata) {
|
|||||||
|
|
||||||
static inline unsigned
|
static inline unsigned
|
||||||
edata_binshard_get(const edata_t *edata) {
|
edata_binshard_get(const edata_t *edata) {
|
||||||
unsigned binshard = (unsigned)((edata->e_bits &
|
unsigned binshard = (unsigned)((edata->e_bits
|
||||||
EDATA_BITS_BINSHARD_MASK) >> EDATA_BITS_BINSHARD_SHIFT);
|
& EDATA_BITS_BINSHARD_MASK)
|
||||||
|
>> EDATA_BITS_BINSHARD_SHIFT);
|
||||||
assert(binshard < bin_infos[edata_szind_get(edata)].n_shards);
|
assert(binshard < bin_infos[edata_szind_get(edata)].n_shards);
|
||||||
return binshard;
|
return binshard;
|
||||||
}
|
}
|
||||||
@@ -354,58 +369,58 @@ edata_sn_get(const edata_t *edata) {
|
|||||||
|
|
||||||
static inline extent_state_t
|
static inline extent_state_t
|
||||||
edata_state_get(const edata_t *edata) {
|
edata_state_get(const edata_t *edata) {
|
||||||
return (extent_state_t)((edata->e_bits & EDATA_BITS_STATE_MASK) >>
|
return (extent_state_t)((edata->e_bits & EDATA_BITS_STATE_MASK)
|
||||||
EDATA_BITS_STATE_SHIFT);
|
>> EDATA_BITS_STATE_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
edata_guarded_get(const edata_t *edata) {
|
edata_guarded_get(const edata_t *edata) {
|
||||||
return (bool)((edata->e_bits & EDATA_BITS_GUARDED_MASK) >>
|
return (bool)((edata->e_bits & EDATA_BITS_GUARDED_MASK)
|
||||||
EDATA_BITS_GUARDED_SHIFT);
|
>> EDATA_BITS_GUARDED_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
edata_zeroed_get(const edata_t *edata) {
|
edata_zeroed_get(const edata_t *edata) {
|
||||||
return (bool)((edata->e_bits & EDATA_BITS_ZEROED_MASK) >>
|
return (bool)((edata->e_bits & EDATA_BITS_ZEROED_MASK)
|
||||||
EDATA_BITS_ZEROED_SHIFT);
|
>> EDATA_BITS_ZEROED_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
edata_committed_get(const edata_t *edata) {
|
edata_committed_get(const edata_t *edata) {
|
||||||
return (bool)((edata->e_bits & EDATA_BITS_COMMITTED_MASK) >>
|
return (bool)((edata->e_bits & EDATA_BITS_COMMITTED_MASK)
|
||||||
EDATA_BITS_COMMITTED_SHIFT);
|
>> EDATA_BITS_COMMITTED_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline extent_pai_t
|
static inline extent_pai_t
|
||||||
edata_pai_get(const edata_t *edata) {
|
edata_pai_get(const edata_t *edata) {
|
||||||
return (extent_pai_t)((edata->e_bits & EDATA_BITS_PAI_MASK) >>
|
return (extent_pai_t)((edata->e_bits & EDATA_BITS_PAI_MASK)
|
||||||
EDATA_BITS_PAI_SHIFT);
|
>> EDATA_BITS_PAI_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
edata_slab_get(const edata_t *edata) {
|
edata_slab_get(const edata_t *edata) {
|
||||||
return (bool)((edata->e_bits & EDATA_BITS_SLAB_MASK) >>
|
return (bool)((edata->e_bits & EDATA_BITS_SLAB_MASK)
|
||||||
EDATA_BITS_SLAB_SHIFT);
|
>> EDATA_BITS_SLAB_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned
|
static inline unsigned
|
||||||
edata_nfree_get(const edata_t *edata) {
|
edata_nfree_get(const edata_t *edata) {
|
||||||
assert(edata_slab_get(edata));
|
assert(edata_slab_get(edata));
|
||||||
return (unsigned)((edata->e_bits & EDATA_BITS_NFREE_MASK) >>
|
return (unsigned)((edata->e_bits & EDATA_BITS_NFREE_MASK)
|
||||||
EDATA_BITS_NFREE_SHIFT);
|
>> EDATA_BITS_NFREE_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void *
|
static inline void *
|
||||||
edata_base_get(const edata_t *edata) {
|
edata_base_get(const edata_t *edata) {
|
||||||
assert(edata->e_addr == PAGE_ADDR2BASE(edata->e_addr) ||
|
assert(edata->e_addr == PAGE_ADDR2BASE(edata->e_addr)
|
||||||
!edata_slab_get(edata));
|
|| !edata_slab_get(edata));
|
||||||
return PAGE_ADDR2BASE(edata->e_addr);
|
return PAGE_ADDR2BASE(edata->e_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void *
|
static inline void *
|
||||||
edata_addr_get(const edata_t *edata) {
|
edata_addr_get(const edata_t *edata) {
|
||||||
assert(edata->e_addr == PAGE_ADDR2BASE(edata->e_addr) ||
|
assert(edata->e_addr == PAGE_ADDR2BASE(edata->e_addr)
|
||||||
!edata_slab_get(edata));
|
|| !edata_slab_get(edata));
|
||||||
return edata->e_addr;
|
return edata->e_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -437,14 +452,14 @@ edata_before_get(const edata_t *edata) {
|
|||||||
|
|
||||||
static inline void *
|
static inline void *
|
||||||
edata_last_get(const edata_t *edata) {
|
edata_last_get(const edata_t *edata) {
|
||||||
return (void *)((byte_t *)edata_base_get(edata) +
|
return (void *)((byte_t *)edata_base_get(edata) + edata_size_get(edata)
|
||||||
edata_size_get(edata) - PAGE);
|
- PAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void *
|
static inline void *
|
||||||
edata_past_get(const edata_t *edata) {
|
edata_past_get(const edata_t *edata) {
|
||||||
return (void *)((byte_t *)edata_base_get(edata) +
|
return (
|
||||||
edata_size_get(edata));
|
void *)((byte_t *)edata_base_get(edata) + edata_size_get(edata));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline slab_data_t *
|
static inline slab_data_t *
|
||||||
@@ -461,8 +476,8 @@ edata_slab_data_get_const(const edata_t *edata) {
|
|||||||
|
|
||||||
static inline prof_tctx_t *
|
static inline prof_tctx_t *
|
||||||
edata_prof_tctx_get(const edata_t *edata) {
|
edata_prof_tctx_get(const edata_t *edata) {
|
||||||
return (prof_tctx_t *)atomic_load_p(&edata->e_prof_info.e_prof_tctx,
|
return (prof_tctx_t *)atomic_load_p(
|
||||||
ATOMIC_ACQUIRE);
|
&edata->e_prof_info.e_prof_tctx, ATOMIC_ACQUIRE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline const nstime_t *
|
static inline const nstime_t *
|
||||||
@@ -483,16 +498,16 @@ edata_prof_recent_alloc_get_dont_call_directly(const edata_t *edata) {
|
|||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
edata_arena_ind_set(edata_t *edata, unsigned arena_ind) {
|
edata_arena_ind_set(edata_t *edata, unsigned arena_ind) {
|
||||||
edata->e_bits = (edata->e_bits & ~EDATA_BITS_ARENA_MASK) |
|
edata->e_bits = (edata->e_bits & ~EDATA_BITS_ARENA_MASK)
|
||||||
((uint64_t)arena_ind << EDATA_BITS_ARENA_SHIFT);
|
| ((uint64_t)arena_ind << EDATA_BITS_ARENA_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
edata_binshard_set(edata_t *edata, unsigned binshard) {
|
edata_binshard_set(edata_t *edata, unsigned binshard) {
|
||||||
/* The assertion assumes szind is set already. */
|
/* The assertion assumes szind is set already. */
|
||||||
assert(binshard < bin_infos[edata_szind_get(edata)].n_shards);
|
assert(binshard < bin_infos[edata_szind_get(edata)].n_shards);
|
||||||
edata->e_bits = (edata->e_bits & ~EDATA_BITS_BINSHARD_MASK) |
|
edata->e_bits = (edata->e_bits & ~EDATA_BITS_BINSHARD_MASK)
|
||||||
((uint64_t)binshard << EDATA_BITS_BINSHARD_SHIFT);
|
| ((uint64_t)binshard << EDATA_BITS_BINSHARD_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
@@ -508,8 +523,8 @@ edata_size_set(edata_t *edata, size_t size) {
|
|||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
edata_esn_set(edata_t *edata, size_t esn) {
|
edata_esn_set(edata_t *edata, size_t esn) {
|
||||||
edata->e_size_esn = (edata->e_size_esn & ~EDATA_ESN_MASK) | (esn &
|
edata->e_size_esn = (edata->e_size_esn & ~EDATA_ESN_MASK)
|
||||||
EDATA_ESN_MASK);
|
| (esn & EDATA_ESN_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
@@ -526,25 +541,26 @@ edata_ps_set(edata_t *edata, hpdata_t *ps) {
|
|||||||
static inline void
|
static inline void
|
||||||
edata_szind_set(edata_t *edata, szind_t szind) {
|
edata_szind_set(edata_t *edata, szind_t szind) {
|
||||||
assert(szind <= SC_NSIZES); /* SC_NSIZES means "invalid". */
|
assert(szind <= SC_NSIZES); /* SC_NSIZES means "invalid". */
|
||||||
edata->e_bits = (edata->e_bits & ~EDATA_BITS_SZIND_MASK) |
|
edata->e_bits = (edata->e_bits & ~EDATA_BITS_SZIND_MASK)
|
||||||
((uint64_t)szind << EDATA_BITS_SZIND_SHIFT);
|
| ((uint64_t)szind << EDATA_BITS_SZIND_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
edata_nfree_set(edata_t *edata, unsigned nfree) {
|
edata_nfree_set(edata_t *edata, unsigned nfree) {
|
||||||
assert(edata_slab_get(edata));
|
assert(edata_slab_get(edata));
|
||||||
edata->e_bits = (edata->e_bits & ~EDATA_BITS_NFREE_MASK) |
|
edata->e_bits = (edata->e_bits & ~EDATA_BITS_NFREE_MASK)
|
||||||
((uint64_t)nfree << EDATA_BITS_NFREE_SHIFT);
|
| ((uint64_t)nfree << EDATA_BITS_NFREE_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
edata_nfree_binshard_set(edata_t *edata, unsigned nfree, unsigned binshard) {
|
edata_nfree_binshard_set(edata_t *edata, unsigned nfree, unsigned binshard) {
|
||||||
/* The assertion assumes szind is set already. */
|
/* The assertion assumes szind is set already. */
|
||||||
assert(binshard < bin_infos[edata_szind_get(edata)].n_shards);
|
assert(binshard < bin_infos[edata_szind_get(edata)].n_shards);
|
||||||
edata->e_bits = (edata->e_bits &
|
edata->e_bits = (edata->e_bits
|
||||||
(~EDATA_BITS_NFREE_MASK & ~EDATA_BITS_BINSHARD_MASK)) |
|
& (~EDATA_BITS_NFREE_MASK
|
||||||
((uint64_t)binshard << EDATA_BITS_BINSHARD_SHIFT) |
|
& ~EDATA_BITS_BINSHARD_MASK))
|
||||||
((uint64_t)nfree << EDATA_BITS_NFREE_SHIFT);
|
| ((uint64_t)binshard << EDATA_BITS_BINSHARD_SHIFT)
|
||||||
|
| ((uint64_t)nfree << EDATA_BITS_NFREE_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
@@ -572,38 +588,38 @@ edata_sn_set(edata_t *edata, uint64_t sn) {
|
|||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
edata_state_set(edata_t *edata, extent_state_t state) {
|
edata_state_set(edata_t *edata, extent_state_t state) {
|
||||||
edata->e_bits = (edata->e_bits & ~EDATA_BITS_STATE_MASK) |
|
edata->e_bits = (edata->e_bits & ~EDATA_BITS_STATE_MASK)
|
||||||
((uint64_t)state << EDATA_BITS_STATE_SHIFT);
|
| ((uint64_t)state << EDATA_BITS_STATE_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
edata_guarded_set(edata_t *edata, bool guarded) {
|
edata_guarded_set(edata_t *edata, bool guarded) {
|
||||||
edata->e_bits = (edata->e_bits & ~EDATA_BITS_GUARDED_MASK) |
|
edata->e_bits = (edata->e_bits & ~EDATA_BITS_GUARDED_MASK)
|
||||||
((uint64_t)guarded << EDATA_BITS_GUARDED_SHIFT);
|
| ((uint64_t)guarded << EDATA_BITS_GUARDED_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
edata_zeroed_set(edata_t *edata, bool zeroed) {
|
edata_zeroed_set(edata_t *edata, bool zeroed) {
|
||||||
edata->e_bits = (edata->e_bits & ~EDATA_BITS_ZEROED_MASK) |
|
edata->e_bits = (edata->e_bits & ~EDATA_BITS_ZEROED_MASK)
|
||||||
((uint64_t)zeroed << EDATA_BITS_ZEROED_SHIFT);
|
| ((uint64_t)zeroed << EDATA_BITS_ZEROED_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
edata_committed_set(edata_t *edata, bool committed) {
|
edata_committed_set(edata_t *edata, bool committed) {
|
||||||
edata->e_bits = (edata->e_bits & ~EDATA_BITS_COMMITTED_MASK) |
|
edata->e_bits = (edata->e_bits & ~EDATA_BITS_COMMITTED_MASK)
|
||||||
((uint64_t)committed << EDATA_BITS_COMMITTED_SHIFT);
|
| ((uint64_t)committed << EDATA_BITS_COMMITTED_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
edata_pai_set(edata_t *edata, extent_pai_t pai) {
|
edata_pai_set(edata_t *edata, extent_pai_t pai) {
|
||||||
edata->e_bits = (edata->e_bits & ~EDATA_BITS_PAI_MASK) |
|
edata->e_bits = (edata->e_bits & ~EDATA_BITS_PAI_MASK)
|
||||||
((uint64_t)pai << EDATA_BITS_PAI_SHIFT);
|
| ((uint64_t)pai << EDATA_BITS_PAI_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
edata_slab_set(edata_t *edata, bool slab) {
|
edata_slab_set(edata_t *edata, bool slab) {
|
||||||
edata->e_bits = (edata->e_bits & ~EDATA_BITS_SLAB_MASK) |
|
edata->e_bits = (edata->e_bits & ~EDATA_BITS_SLAB_MASK)
|
||||||
((uint64_t)slab << EDATA_BITS_SLAB_SHIFT);
|
| ((uint64_t)slab << EDATA_BITS_SLAB_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
@@ -622,22 +638,22 @@ edata_prof_alloc_size_set(edata_t *edata, size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
edata_prof_recent_alloc_set_dont_call_directly(edata_t *edata,
|
edata_prof_recent_alloc_set_dont_call_directly(
|
||||||
prof_recent_t *recent_alloc) {
|
edata_t *edata, prof_recent_t *recent_alloc) {
|
||||||
atomic_store_p(&edata->e_prof_info.e_prof_recent_alloc, recent_alloc,
|
atomic_store_p(&edata->e_prof_info.e_prof_recent_alloc, recent_alloc,
|
||||||
ATOMIC_RELAXED);
|
ATOMIC_RELAXED);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
edata_is_head_get(edata_t *edata) {
|
edata_is_head_get(edata_t *edata) {
|
||||||
return (bool)((edata->e_bits & EDATA_BITS_IS_HEAD_MASK) >>
|
return (bool)((edata->e_bits & EDATA_BITS_IS_HEAD_MASK)
|
||||||
EDATA_BITS_IS_HEAD_SHIFT);
|
>> EDATA_BITS_IS_HEAD_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
edata_is_head_set(edata_t *edata, bool is_head) {
|
edata_is_head_set(edata_t *edata, bool is_head) {
|
||||||
edata->e_bits = (edata->e_bits & ~EDATA_BITS_IS_HEAD_MASK) |
|
edata->e_bits = (edata->e_bits & ~EDATA_BITS_IS_HEAD_MASK)
|
||||||
((uint64_t)is_head << EDATA_BITS_IS_HEAD_SHIFT);
|
| ((uint64_t)is_head << EDATA_BITS_IS_HEAD_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
@@ -676,8 +692,8 @@ edata_init(edata_t *edata, unsigned arena_ind, void *addr, size_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
edata_binit(edata_t *edata, void *addr, size_t bsize, uint64_t sn,
|
edata_binit(
|
||||||
bool reused) {
|
edata_t *edata, void *addr, size_t bsize, uint64_t sn, bool reused) {
|
||||||
edata_arena_ind_set(edata, (1U << MALLOCX_ARENA_BITS) - 1);
|
edata_arena_ind_set(edata, (1U << MALLOCX_ARENA_BITS) - 1);
|
||||||
edata_addr_set(edata, addr);
|
edata_addr_set(edata, addr);
|
||||||
edata_bsize_set(edata, bsize);
|
edata_bsize_set(edata, bsize);
|
||||||
@@ -731,8 +747,10 @@ static inline int
|
|||||||
edata_cmp_summary_comp(edata_cmp_summary_t a, edata_cmp_summary_t b) {
|
edata_cmp_summary_comp(edata_cmp_summary_t a, edata_cmp_summary_t b) {
|
||||||
unsigned __int128 a_encoded = edata_cmp_summary_encode(a);
|
unsigned __int128 a_encoded = edata_cmp_summary_encode(a);
|
||||||
unsigned __int128 b_encoded = edata_cmp_summary_encode(b);
|
unsigned __int128 b_encoded = edata_cmp_summary_encode(b);
|
||||||
if (a_encoded < b_encoded) return -1;
|
if (a_encoded < b_encoded)
|
||||||
if (a_encoded == b_encoded) return 0;
|
return -1;
|
||||||
|
if (a_encoded == b_encoded)
|
||||||
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@@ -750,8 +768,8 @@ edata_cmp_summary_comp(edata_cmp_summary_t a, edata_cmp_summary_t b) {
|
|||||||
* prediction accuracy is not great. As a result, this implementation
|
* prediction accuracy is not great. As a result, this implementation
|
||||||
* is measurably faster (by around 30%).
|
* is measurably faster (by around 30%).
|
||||||
*/
|
*/
|
||||||
return (2 * ((a.sn > b.sn) - (a.sn < b.sn))) +
|
return (2 * ((a.sn > b.sn) - (a.sn < b.sn)))
|
||||||
((a.addr > b.addr) - (a.addr < b.addr));
|
+ ((a.addr > b.addr) - (a.addr < b.addr));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -772,7 +790,6 @@ edata_esnead_comp(const edata_t *a, const edata_t *b) {
|
|||||||
return (2 * edata_esn_comp(a, b)) + edata_ead_comp(a, b);
|
return (2 * edata_esn_comp(a, b)) + edata_ead_comp(a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
ph_proto(, edata_avail, edata_t)
|
ph_proto(, edata_avail, edata_t) ph_proto(, edata_heap, edata_t)
|
||||||
ph_proto(, edata_heap, edata_t)
|
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_EDATA_H */
|
#endif /* JEMALLOC_INTERNAL_EDATA_H */
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ struct edata_cache_fast_s {
|
|||||||
|
|
||||||
void edata_cache_fast_init(edata_cache_fast_t *ecs, edata_cache_t *fallback);
|
void edata_cache_fast_init(edata_cache_fast_t *ecs, edata_cache_t *fallback);
|
||||||
edata_t *edata_cache_fast_get(tsdn_t *tsdn, edata_cache_fast_t *ecs);
|
edata_t *edata_cache_fast_get(tsdn_t *tsdn, edata_cache_fast_t *ecs);
|
||||||
void edata_cache_fast_put(tsdn_t *tsdn, edata_cache_fast_t *ecs,
|
void edata_cache_fast_put(
|
||||||
edata_t *edata);
|
tsdn_t *tsdn, edata_cache_fast_t *ecs, edata_t *edata);
|
||||||
void edata_cache_fast_disable(tsdn_t *tsdn, edata_cache_fast_t *ecs);
|
void edata_cache_fast_disable(tsdn_t *tsdn, edata_cache_fast_t *ecs);
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_EDATA_CACHE_H */
|
#endif /* JEMALLOC_INTERNAL_EDATA_CACHE_H */
|
||||||
|
|||||||
@@ -116,8 +116,8 @@ ehooks_get_extent_hooks_ptr(ehooks_t *ehooks) {
|
|||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
ehooks_are_default(ehooks_t *ehooks) {
|
ehooks_are_default(ehooks_t *ehooks) {
|
||||||
return ehooks_get_extent_hooks_ptr(ehooks) ==
|
return ehooks_get_extent_hooks_ptr(ehooks)
|
||||||
&ehooks_default_extent_hooks;
|
== &ehooks_default_extent_hooks;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -189,7 +189,6 @@ ehooks_debug_zero_check(void *addr, size_t size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void *
|
static inline void *
|
||||||
ehooks_alloc(tsdn_t *tsdn, ehooks_t *ehooks, void *new_addr, size_t size,
|
ehooks_alloc(tsdn_t *tsdn, ehooks_t *ehooks, void *new_addr, size_t size,
|
||||||
size_t alignment, bool *zero, bool *commit) {
|
size_t alignment, bool *zero, bool *commit) {
|
||||||
@@ -197,8 +196,8 @@ ehooks_alloc(tsdn_t *tsdn, ehooks_t *ehooks, void *new_addr, size_t size,
|
|||||||
void *ret;
|
void *ret;
|
||||||
extent_hooks_t *extent_hooks = ehooks_get_extent_hooks_ptr(ehooks);
|
extent_hooks_t *extent_hooks = ehooks_get_extent_hooks_ptr(ehooks);
|
||||||
if (extent_hooks == &ehooks_default_extent_hooks) {
|
if (extent_hooks == &ehooks_default_extent_hooks) {
|
||||||
ret = ehooks_default_alloc_impl(tsdn, new_addr, size,
|
ret = ehooks_default_alloc_impl(tsdn, new_addr, size, alignment,
|
||||||
alignment, zero, commit, ehooks_ind_get(ehooks));
|
zero, commit, ehooks_ind_get(ehooks));
|
||||||
} else {
|
} else {
|
||||||
ehooks_pre_reentrancy(tsdn);
|
ehooks_pre_reentrancy(tsdn);
|
||||||
ret = extent_hooks->alloc(extent_hooks, new_addr, size,
|
ret = extent_hooks->alloc(extent_hooks, new_addr, size,
|
||||||
@@ -214,8 +213,8 @@ ehooks_alloc(tsdn_t *tsdn, ehooks_t *ehooks, void *new_addr, size_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
ehooks_dalloc(tsdn_t *tsdn, ehooks_t *ehooks, void *addr, size_t size,
|
ehooks_dalloc(
|
||||||
bool committed) {
|
tsdn_t *tsdn, ehooks_t *ehooks, void *addr, size_t size, bool committed) {
|
||||||
extent_hooks_t *extent_hooks = ehooks_get_extent_hooks_ptr(ehooks);
|
extent_hooks_t *extent_hooks = ehooks_get_extent_hooks_ptr(ehooks);
|
||||||
if (extent_hooks == &ehooks_default_extent_hooks) {
|
if (extent_hooks == &ehooks_default_extent_hooks) {
|
||||||
return ehooks_default_dalloc_impl(addr, size);
|
return ehooks_default_dalloc_impl(addr, size);
|
||||||
@@ -231,8 +230,8 @@ ehooks_dalloc(tsdn_t *tsdn, ehooks_t *ehooks, void *addr, size_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
ehooks_destroy(tsdn_t *tsdn, ehooks_t *ehooks, void *addr, size_t size,
|
ehooks_destroy(
|
||||||
bool committed) {
|
tsdn_t *tsdn, ehooks_t *ehooks, void *addr, size_t size, bool committed) {
|
||||||
extent_hooks_t *extent_hooks = ehooks_get_extent_hooks_ptr(ehooks);
|
extent_hooks_t *extent_hooks = ehooks_get_extent_hooks_ptr(ehooks);
|
||||||
if (extent_hooks == &ehooks_default_extent_hooks) {
|
if (extent_hooks == &ehooks_default_extent_hooks) {
|
||||||
ehooks_default_destroy_impl(addr, size);
|
ehooks_default_destroy_impl(addr, size);
|
||||||
@@ -257,8 +256,8 @@ ehooks_commit(tsdn_t *tsdn, ehooks_t *ehooks, void *addr, size_t size,
|
|||||||
err = true;
|
err = true;
|
||||||
} else {
|
} else {
|
||||||
ehooks_pre_reentrancy(tsdn);
|
ehooks_pre_reentrancy(tsdn);
|
||||||
err = extent_hooks->commit(extent_hooks, addr, size,
|
err = extent_hooks->commit(extent_hooks, addr, size, offset,
|
||||||
offset, length, ehooks_ind_get(ehooks));
|
length, ehooks_ind_get(ehooks));
|
||||||
ehooks_post_reentrancy(tsdn);
|
ehooks_post_reentrancy(tsdn);
|
||||||
}
|
}
|
||||||
if (!err) {
|
if (!err) {
|
||||||
|
|||||||
@@ -36,11 +36,11 @@ struct emap_full_alloc_ctx_s {
|
|||||||
|
|
||||||
bool emap_init(emap_t *emap, base_t *base, bool zeroed);
|
bool emap_init(emap_t *emap, base_t *base, bool zeroed);
|
||||||
|
|
||||||
void emap_remap(tsdn_t *tsdn, emap_t *emap, edata_t *edata, szind_t szind,
|
void emap_remap(
|
||||||
bool slab);
|
tsdn_t *tsdn, emap_t *emap, edata_t *edata, szind_t szind, bool slab);
|
||||||
|
|
||||||
void emap_update_edata_state(tsdn_t *tsdn, emap_t *emap, edata_t *edata,
|
void emap_update_edata_state(
|
||||||
extent_state_t state);
|
tsdn_t *tsdn, emap_t *emap, edata_t *edata, extent_state_t state);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The two acquire functions below allow accessing neighbor edatas, if it's safe
|
* The two acquire functions below allow accessing neighbor edatas, if it's safe
|
||||||
@@ -62,16 +62,16 @@ edata_t *emap_try_acquire_edata_neighbor(tsdn_t *tsdn, emap_t *emap,
|
|||||||
bool forward);
|
bool forward);
|
||||||
edata_t *emap_try_acquire_edata_neighbor_expand(tsdn_t *tsdn, emap_t *emap,
|
edata_t *emap_try_acquire_edata_neighbor_expand(tsdn_t *tsdn, emap_t *emap,
|
||||||
edata_t *edata, extent_pai_t pai, extent_state_t expected_state);
|
edata_t *edata, extent_pai_t pai, extent_state_t expected_state);
|
||||||
void emap_release_edata(tsdn_t *tsdn, emap_t *emap, edata_t *edata,
|
void emap_release_edata(
|
||||||
extent_state_t new_state);
|
tsdn_t *tsdn, emap_t *emap, edata_t *edata, extent_state_t new_state);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Associate the given edata with its beginning and end address, setting the
|
* Associate the given edata with its beginning and end address, setting the
|
||||||
* szind and slab info appropriately.
|
* szind and slab info appropriately.
|
||||||
* Returns true on error (i.e. resource exhaustion).
|
* Returns true on error (i.e. resource exhaustion).
|
||||||
*/
|
*/
|
||||||
bool emap_register_boundary(tsdn_t *tsdn, emap_t *emap, edata_t *edata,
|
bool emap_register_boundary(
|
||||||
szind_t szind, bool slab);
|
tsdn_t *tsdn, emap_t *emap, edata_t *edata, szind_t szind, bool slab);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Does the same thing, but with the interior of the range, for slab
|
* Does the same thing, but with the interior of the range, for slab
|
||||||
@@ -92,8 +92,8 @@ bool emap_register_boundary(tsdn_t *tsdn, emap_t *emap, edata_t *edata,
|
|||||||
* touched, so no allocation is necessary to fill the interior once the boundary
|
* touched, so no allocation is necessary to fill the interior once the boundary
|
||||||
* has been touched.
|
* has been touched.
|
||||||
*/
|
*/
|
||||||
void emap_register_interior(tsdn_t *tsdn, emap_t *emap, edata_t *edata,
|
void emap_register_interior(
|
||||||
szind_t szind);
|
tsdn_t *tsdn, emap_t *emap, edata_t *edata, szind_t szind);
|
||||||
|
|
||||||
void emap_deregister_boundary(tsdn_t *tsdn, emap_t *emap, edata_t *edata);
|
void emap_deregister_boundary(tsdn_t *tsdn, emap_t *emap, edata_t *edata);
|
||||||
void emap_deregister_interior(tsdn_t *tsdn, emap_t *emap, edata_t *edata);
|
void emap_deregister_interior(tsdn_t *tsdn, emap_t *emap, edata_t *edata);
|
||||||
@@ -161,8 +161,8 @@ emap_edata_in_transition(tsdn_t *tsdn, emap_t *emap, edata_t *edata) {
|
|||||||
emap_assert_mapped(tsdn, emap, edata);
|
emap_assert_mapped(tsdn, emap, edata);
|
||||||
|
|
||||||
EMAP_DECLARE_RTREE_CTX;
|
EMAP_DECLARE_RTREE_CTX;
|
||||||
rtree_contents_t contents = rtree_read(tsdn, &emap->rtree, rtree_ctx,
|
rtree_contents_t contents = rtree_read(
|
||||||
(uintptr_t)edata_base_get(edata));
|
tsdn, &emap->rtree, rtree_ctx, (uintptr_t)edata_base_get(edata));
|
||||||
|
|
||||||
return edata_state_in_transition(contents.metadata.state);
|
return edata_state_in_transition(contents.metadata.state);
|
||||||
}
|
}
|
||||||
@@ -194,9 +194,9 @@ emap_edata_is_acquired(tsdn_t *tsdn, emap_t *emap, edata_t *edata) {
|
|||||||
}
|
}
|
||||||
rtree_contents_t contents = rtree_leaf_elm_read(tsdn, &emap->rtree, elm,
|
rtree_contents_t contents = rtree_leaf_elm_read(tsdn, &emap->rtree, elm,
|
||||||
/* dependent */ false);
|
/* dependent */ false);
|
||||||
if (contents.edata == NULL ||
|
if (contents.edata == NULL
|
||||||
contents.metadata.state == extent_state_active ||
|
|| contents.metadata.state == extent_state_active
|
||||||
edata_state_in_transition(contents.metadata.state)) {
|
|| edata_state_in_transition(contents.metadata.state)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,8 +211,8 @@ extent_assert_can_coalesce(const edata_t *inner, const edata_t *outer) {
|
|||||||
assert(edata_state_get(inner) == extent_state_active);
|
assert(edata_state_get(inner) == extent_state_active);
|
||||||
assert(edata_state_get(outer) == extent_state_merging);
|
assert(edata_state_get(outer) == extent_state_merging);
|
||||||
assert(!edata_guarded_get(inner) && !edata_guarded_get(outer));
|
assert(!edata_guarded_get(inner) && !edata_guarded_get(outer));
|
||||||
assert(edata_base_get(inner) == edata_past_get(outer) ||
|
assert(edata_base_get(inner) == edata_past_get(outer)
|
||||||
edata_base_get(outer) == edata_past_get(inner));
|
|| edata_base_get(outer) == edata_past_get(inner));
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
@@ -232,13 +232,13 @@ emap_edata_lookup(tsdn_t *tsdn, emap_t *emap, const void *ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
emap_alloc_ctx_init(emap_alloc_ctx_t *alloc_ctx, szind_t szind, bool slab,
|
emap_alloc_ctx_init(
|
||||||
size_t usize) {
|
emap_alloc_ctx_t *alloc_ctx, szind_t szind, bool slab, size_t usize) {
|
||||||
alloc_ctx->szind = szind;
|
alloc_ctx->szind = szind;
|
||||||
alloc_ctx->slab = slab;
|
alloc_ctx->slab = slab;
|
||||||
alloc_ctx->usize = usize;
|
alloc_ctx->usize = usize;
|
||||||
assert(sz_large_size_classes_disabled() ||
|
assert(
|
||||||
usize == sz_index2size(szind));
|
sz_large_size_classes_disabled() || usize == sz_index2size(szind));
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE size_t
|
JEMALLOC_ALWAYS_INLINE size_t
|
||||||
@@ -248,27 +248,29 @@ emap_alloc_ctx_usize_get(emap_alloc_ctx_t *alloc_ctx) {
|
|||||||
assert(alloc_ctx->usize == sz_index2size(alloc_ctx->szind));
|
assert(alloc_ctx->usize == sz_index2size(alloc_ctx->szind));
|
||||||
return sz_index2size(alloc_ctx->szind);
|
return sz_index2size(alloc_ctx->szind);
|
||||||
}
|
}
|
||||||
assert(sz_large_size_classes_disabled() ||
|
assert(sz_large_size_classes_disabled()
|
||||||
alloc_ctx->usize == sz_index2size(alloc_ctx->szind));
|
|| alloc_ctx->usize == sz_index2size(alloc_ctx->szind));
|
||||||
assert(alloc_ctx->usize <= SC_LARGE_MAXCLASS);
|
assert(alloc_ctx->usize <= SC_LARGE_MAXCLASS);
|
||||||
return alloc_ctx->usize;
|
return alloc_ctx->usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fills in alloc_ctx with the info in the map. */
|
/* Fills in alloc_ctx with the info in the map. */
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
emap_alloc_ctx_lookup(tsdn_t *tsdn, emap_t *emap, const void *ptr,
|
emap_alloc_ctx_lookup(
|
||||||
emap_alloc_ctx_t *alloc_ctx) {
|
tsdn_t *tsdn, emap_t *emap, const void *ptr, emap_alloc_ctx_t *alloc_ctx) {
|
||||||
EMAP_DECLARE_RTREE_CTX;
|
EMAP_DECLARE_RTREE_CTX;
|
||||||
|
|
||||||
rtree_contents_t contents = rtree_read(tsdn, &emap->rtree,
|
rtree_contents_t contents = rtree_read(
|
||||||
rtree_ctx, (uintptr_t)ptr);
|
tsdn, &emap->rtree, rtree_ctx, (uintptr_t)ptr);
|
||||||
/*
|
/*
|
||||||
* If the alloc is invalid, do not calculate usize since edata
|
* If the alloc is invalid, do not calculate usize since edata
|
||||||
* could be corrupted.
|
* could be corrupted.
|
||||||
*/
|
*/
|
||||||
emap_alloc_ctx_init(alloc_ctx, contents.metadata.szind,
|
emap_alloc_ctx_init(alloc_ctx, contents.metadata.szind,
|
||||||
contents.metadata.slab, (contents.metadata.szind == SC_NSIZES
|
contents.metadata.slab,
|
||||||
|| contents.edata == NULL)? 0: edata_usize_get(contents.edata));
|
(contents.metadata.szind == SC_NSIZES || contents.edata == NULL)
|
||||||
|
? 0
|
||||||
|
: edata_usize_get(contents.edata));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The pointer must be mapped. */
|
/* The pointer must be mapped. */
|
||||||
@@ -277,8 +279,8 @@ emap_full_alloc_ctx_lookup(tsdn_t *tsdn, emap_t *emap, const void *ptr,
|
|||||||
emap_full_alloc_ctx_t *full_alloc_ctx) {
|
emap_full_alloc_ctx_t *full_alloc_ctx) {
|
||||||
EMAP_DECLARE_RTREE_CTX;
|
EMAP_DECLARE_RTREE_CTX;
|
||||||
|
|
||||||
rtree_contents_t contents = rtree_read(tsdn, &emap->rtree, rtree_ctx,
|
rtree_contents_t contents = rtree_read(
|
||||||
(uintptr_t)ptr);
|
tsdn, &emap->rtree, rtree_ctx, (uintptr_t)ptr);
|
||||||
full_alloc_ctx->edata = contents.edata;
|
full_alloc_ctx->edata = contents.edata;
|
||||||
full_alloc_ctx->szind = contents.metadata.szind;
|
full_alloc_ctx->szind = contents.metadata.szind;
|
||||||
full_alloc_ctx->slab = contents.metadata.slab;
|
full_alloc_ctx->slab = contents.metadata.slab;
|
||||||
@@ -295,8 +297,8 @@ emap_full_alloc_ctx_try_lookup(tsdn_t *tsdn, emap_t *emap, const void *ptr,
|
|||||||
EMAP_DECLARE_RTREE_CTX;
|
EMAP_DECLARE_RTREE_CTX;
|
||||||
|
|
||||||
rtree_contents_t contents;
|
rtree_contents_t contents;
|
||||||
bool err = rtree_read_independent(tsdn, &emap->rtree, rtree_ctx,
|
bool err = rtree_read_independent(
|
||||||
(uintptr_t)ptr, &contents);
|
tsdn, &emap->rtree, rtree_ctx, (uintptr_t)ptr, &contents);
|
||||||
if (err) {
|
if (err) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -311,14 +313,14 @@ emap_full_alloc_ctx_try_lookup(tsdn_t *tsdn, emap_t *emap, const void *ptr,
|
|||||||
* fast path, e.g. when the metadata key is not cached.
|
* fast path, e.g. when the metadata key is not cached.
|
||||||
*/
|
*/
|
||||||
JEMALLOC_ALWAYS_INLINE bool
|
JEMALLOC_ALWAYS_INLINE bool
|
||||||
emap_alloc_ctx_try_lookup_fast(tsd_t *tsd, emap_t *emap, const void *ptr,
|
emap_alloc_ctx_try_lookup_fast(
|
||||||
emap_alloc_ctx_t *alloc_ctx) {
|
tsd_t *tsd, emap_t *emap, const void *ptr, emap_alloc_ctx_t *alloc_ctx) {
|
||||||
/* Use the unsafe getter since this may gets called during exit. */
|
/* Use the unsafe getter since this may gets called during exit. */
|
||||||
rtree_ctx_t *rtree_ctx = tsd_rtree_ctxp_get_unsafe(tsd);
|
rtree_ctx_t *rtree_ctx = tsd_rtree_ctxp_get_unsafe(tsd);
|
||||||
|
|
||||||
rtree_metadata_t metadata;
|
rtree_metadata_t metadata;
|
||||||
bool err = rtree_metadata_try_read_fast(tsd_tsdn(tsd), &emap->rtree,
|
bool err = rtree_metadata_try_read_fast(
|
||||||
rtree_ctx, (uintptr_t)ptr, &metadata);
|
tsd_tsdn(tsd), &emap->rtree, rtree_ctx, (uintptr_t)ptr, &metadata);
|
||||||
if (err) {
|
if (err) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -345,7 +347,8 @@ typedef const void *(*emap_ptr_getter)(void *ctx, size_t ind);
|
|||||||
* This allows size-checking assertions, which we can only do while we're in the
|
* This allows size-checking assertions, which we can only do while we're in the
|
||||||
* process of edata lookups.
|
* process of edata lookups.
|
||||||
*/
|
*/
|
||||||
typedef void (*emap_metadata_visitor)(void *ctx, emap_full_alloc_ctx_t *alloc_ctx);
|
typedef void (*emap_metadata_visitor)(
|
||||||
|
void *ctx, emap_full_alloc_ctx_t *alloc_ctx);
|
||||||
|
|
||||||
typedef union emap_batch_lookup_result_u emap_batch_lookup_result_t;
|
typedef union emap_batch_lookup_result_u emap_batch_lookup_result_t;
|
||||||
union emap_batch_lookup_result_u {
|
union emap_batch_lookup_result_u {
|
||||||
@@ -375,8 +378,8 @@ emap_edata_lookup_batch(tsd_t *tsd, emap_t *emap, size_t nptrs,
|
|||||||
|
|
||||||
for (size_t i = 0; i < nptrs; i++) {
|
for (size_t i = 0; i < nptrs; i++) {
|
||||||
rtree_leaf_elm_t *elm = result[i].rtree_leaf;
|
rtree_leaf_elm_t *elm = result[i].rtree_leaf;
|
||||||
rtree_contents_t contents = rtree_leaf_elm_read(tsd_tsdn(tsd),
|
rtree_contents_t contents = rtree_leaf_elm_read(
|
||||||
&emap->rtree, elm, /* dependent */ true);
|
tsd_tsdn(tsd), &emap->rtree, elm, /* dependent */ true);
|
||||||
result[i].edata = contents.edata;
|
result[i].edata = contents.edata;
|
||||||
emap_full_alloc_ctx_t alloc_ctx;
|
emap_full_alloc_ctx_t alloc_ctx;
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -83,8 +83,8 @@ struct emitter_s {
|
|||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
emitter_outputs_json(emitter_t *emitter) {
|
emitter_outputs_json(emitter_t *emitter) {
|
||||||
return emitter->output == emitter_output_json ||
|
return emitter->output == emitter_output_json
|
||||||
emitter->output == emitter_output_json_compact;
|
|| emitter->output == emitter_output_json_compact;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Internal convenience function. Write to the emitter the given string. */
|
/* Internal convenience function. Write to the emitter the given string. */
|
||||||
@@ -98,20 +98,20 @@ emitter_printf(emitter_t *emitter, const char *format, ...) {
|
|||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline const char * JEMALLOC_FORMAT_ARG(3)
|
static inline const char *
|
||||||
emitter_gen_fmt(char *out_fmt, size_t out_size, const char *fmt_specifier,
|
JEMALLOC_FORMAT_ARG(3) emitter_gen_fmt(char *out_fmt, size_t out_size,
|
||||||
emitter_justify_t justify, int width) {
|
const char *fmt_specifier, emitter_justify_t justify, int width) {
|
||||||
size_t written;
|
size_t written;
|
||||||
fmt_specifier++;
|
fmt_specifier++;
|
||||||
if (justify == emitter_justify_none) {
|
if (justify == emitter_justify_none) {
|
||||||
written = malloc_snprintf(out_fmt, out_size,
|
written = malloc_snprintf(
|
||||||
"%%%s", fmt_specifier);
|
out_fmt, out_size, "%%%s", fmt_specifier);
|
||||||
} else if (justify == emitter_justify_left) {
|
} else if (justify == emitter_justify_left) {
|
||||||
written = malloc_snprintf(out_fmt, out_size,
|
written = malloc_snprintf(
|
||||||
"%%-%d%s", width, fmt_specifier);
|
out_fmt, out_size, "%%-%d%s", width, fmt_specifier);
|
||||||
} else {
|
} else {
|
||||||
written = malloc_snprintf(out_fmt, out_size,
|
written = malloc_snprintf(
|
||||||
"%%%d%s", width, fmt_specifier);
|
out_fmt, out_size, "%%%d%s", width, fmt_specifier);
|
||||||
}
|
}
|
||||||
/* Only happens in case of bad format string, which *we* choose. */
|
/* Only happens in case of bad format string, which *we* choose. */
|
||||||
assert(written < out_size);
|
assert(written < out_size);
|
||||||
@@ -124,8 +124,8 @@ emitter_emit_str(emitter_t *emitter, emitter_justify_t justify, int width,
|
|||||||
#define BUF_SIZE 256
|
#define BUF_SIZE 256
|
||||||
char buf[BUF_SIZE];
|
char buf[BUF_SIZE];
|
||||||
size_t str_written = malloc_snprintf(buf, BUF_SIZE, "\"%s\"", str);
|
size_t str_written = malloc_snprintf(buf, BUF_SIZE, "\"%s\"", str);
|
||||||
emitter_printf(emitter,
|
emitter_printf(
|
||||||
emitter_gen_fmt(fmt, fmt_size, "%s", justify, width), buf);
|
emitter, emitter_gen_fmt(fmt, fmt_size, "%s", justify, width), buf);
|
||||||
if (str_written < BUF_SIZE) {
|
if (str_written < BUF_SIZE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -213,7 +213,6 @@ emitter_print_value(emitter_t *emitter, emitter_justify_t justify, int width,
|
|||||||
#undef FMT_SIZE
|
#undef FMT_SIZE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Internal functions. In json mode, tracks nesting state. */
|
/* Internal functions. In json mode, tracks nesting state. */
|
||||||
static inline void
|
static inline void
|
||||||
emitter_nest_inc(emitter_t *emitter) {
|
emitter_nest_inc(emitter_t *emitter) {
|
||||||
@@ -291,12 +290,12 @@ emitter_json_key(emitter_t *emitter, const char *json_key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
emitter_json_value(emitter_t *emitter, emitter_type_t value_type,
|
emitter_json_value(
|
||||||
const void *value) {
|
emitter_t *emitter, emitter_type_t value_type, const void *value) {
|
||||||
if (emitter_outputs_json(emitter)) {
|
if (emitter_outputs_json(emitter)) {
|
||||||
emitter_json_key_prefix(emitter);
|
emitter_json_key_prefix(emitter);
|
||||||
emitter_print_value(emitter, emitter_justify_none, -1,
|
emitter_print_value(
|
||||||
value_type, value);
|
emitter, emitter_justify_none, -1, value_type, value);
|
||||||
emitter->item_at_depth = true;
|
emitter->item_at_depth = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -367,7 +366,6 @@ emitter_json_object_end(emitter_t *emitter) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* Table public API. */
|
/* Table public API. */
|
||||||
|
|
||||||
@@ -389,14 +387,13 @@ emitter_table_dict_end(emitter_t *emitter) {
|
|||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
emitter_table_kv_note(emitter_t *emitter, const char *table_key,
|
emitter_table_kv_note(emitter_t *emitter, const char *table_key,
|
||||||
emitter_type_t value_type, const void *value,
|
emitter_type_t value_type, const void *value, const char *table_note_key,
|
||||||
const char *table_note_key, emitter_type_t table_note_value_type,
|
emitter_type_t table_note_value_type, const void *table_note_value) {
|
||||||
const void *table_note_value) {
|
|
||||||
if (emitter->output == emitter_output_table) {
|
if (emitter->output == emitter_output_table) {
|
||||||
emitter_indent(emitter);
|
emitter_indent(emitter);
|
||||||
emitter_printf(emitter, "%s: ", table_key);
|
emitter_printf(emitter, "%s: ", table_key);
|
||||||
emitter_print_value(emitter, emitter_justify_none, -1,
|
emitter_print_value(
|
||||||
value_type, value);
|
emitter, emitter_justify_none, -1, value_type, value);
|
||||||
if (table_note_key != NULL) {
|
if (table_note_key != NULL) {
|
||||||
emitter_printf(emitter, " (%s: ", table_note_key);
|
emitter_printf(emitter, " (%s: ", table_note_key);
|
||||||
emitter_print_value(emitter, emitter_justify_none, -1,
|
emitter_print_value(emitter, emitter_justify_none, -1,
|
||||||
@@ -415,7 +412,6 @@ emitter_table_kv(emitter_t *emitter, const char *table_key,
|
|||||||
emitter_type_bool, NULL);
|
emitter_type_bool, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Write to the emitter the given string, but only in table mode. */
|
/* Write to the emitter the given string, but only in table mode. */
|
||||||
JEMALLOC_FORMAT_PRINTF(2, 3)
|
JEMALLOC_FORMAT_PRINTF(2, 3)
|
||||||
static inline void
|
static inline void
|
||||||
@@ -423,7 +419,8 @@ emitter_table_printf(emitter_t *emitter, const char *format, ...) {
|
|||||||
if (emitter->output == emitter_output_table) {
|
if (emitter->output == emitter_output_table) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
malloc_vcprintf(emitter->write_cb, emitter->cbopaque, format, ap);
|
malloc_vcprintf(
|
||||||
|
emitter->write_cb, emitter->cbopaque, format, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -452,7 +449,6 @@ emitter_col_init(emitter_col_t *col, emitter_row_t *row) {
|
|||||||
ql_tail_insert(&row->cols, col, link);
|
ql_tail_insert(&row->cols, col, link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/*
|
/*
|
||||||
* Generalized public API. Emits using either JSON or table, according to
|
* Generalized public API. Emits using either JSON or table, according to
|
||||||
@@ -464,9 +460,8 @@ emitter_col_init(emitter_col_t *col, emitter_row_t *row) {
|
|||||||
*/
|
*/
|
||||||
static inline void
|
static inline void
|
||||||
emitter_kv_note(emitter_t *emitter, const char *json_key, const char *table_key,
|
emitter_kv_note(emitter_t *emitter, const char *json_key, const char *table_key,
|
||||||
emitter_type_t value_type, const void *value,
|
emitter_type_t value_type, const void *value, const char *table_note_key,
|
||||||
const char *table_note_key, emitter_type_t table_note_value_type,
|
emitter_type_t table_note_value_type, const void *table_note_value) {
|
||||||
const void *table_note_value) {
|
|
||||||
if (emitter_outputs_json(emitter)) {
|
if (emitter_outputs_json(emitter)) {
|
||||||
emitter_json_key(emitter, json_key);
|
emitter_json_key(emitter, json_key);
|
||||||
emitter_json_value(emitter, value_type, value);
|
emitter_json_value(emitter, value_type, value);
|
||||||
@@ -485,8 +480,8 @@ emitter_kv(emitter_t *emitter, const char *json_key, const char *table_key,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
emitter_dict_begin(emitter_t *emitter, const char *json_key,
|
emitter_dict_begin(
|
||||||
const char *table_header) {
|
emitter_t *emitter, const char *json_key, const char *table_header) {
|
||||||
if (emitter_outputs_json(emitter)) {
|
if (emitter_outputs_json(emitter)) {
|
||||||
emitter_json_key(emitter, json_key);
|
emitter_json_key(emitter, json_key);
|
||||||
emitter_json_object_begin(emitter);
|
emitter_json_object_begin(emitter);
|
||||||
@@ -526,8 +521,9 @@ emitter_end(emitter_t *emitter) {
|
|||||||
if (emitter_outputs_json(emitter)) {
|
if (emitter_outputs_json(emitter)) {
|
||||||
assert(emitter->nesting_depth == 1);
|
assert(emitter->nesting_depth == 1);
|
||||||
emitter_nest_dec(emitter);
|
emitter_nest_dec(emitter);
|
||||||
emitter_printf(emitter, "%s", emitter->output ==
|
emitter_printf(emitter, "%s",
|
||||||
emitter_output_json_compact ? "}" : "\n}\n");
|
emitter->output == emitter_output_json_compact ? "}"
|
||||||
|
: "\n}\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,7 @@ exp_grow_size_prepare(exp_grow_t *exp_grow, size_t alloc_size_min,
|
|||||||
*r_alloc_size = sz_pind2sz(exp_grow->next + *r_skip);
|
*r_alloc_size = sz_pind2sz(exp_grow->next + *r_skip);
|
||||||
while (*r_alloc_size < alloc_size_min) {
|
while (*r_alloc_size < alloc_size_min) {
|
||||||
(*r_skip)++;
|
(*r_skip)++;
|
||||||
if (exp_grow->next + *r_skip >=
|
if (exp_grow->next + *r_skip >= sz_psz2ind(SC_LARGE_MAXCLASS)) {
|
||||||
sz_psz2ind(SC_LARGE_MAXCLASS)) {
|
|
||||||
/* Outside legal range. */
|
/* Outside legal range. */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -44,7 +43,6 @@ exp_grow_size_commit(exp_grow_t *exp_grow, pszind_t skip) {
|
|||||||
} else {
|
} else {
|
||||||
exp_grow->next = exp_grow->limit;
|
exp_grow->next = exp_grow->limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void exp_grow_init(exp_grow_t *exp_grow);
|
void exp_grow_init(exp_grow_t *exp_grow);
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ extern size_t opt_process_madvise_max_batch;
|
|||||||
|
|
||||||
#ifdef JEMALLOC_HAVE_PROCESS_MADVISE
|
#ifdef JEMALLOC_HAVE_PROCESS_MADVISE
|
||||||
/* The iovec is on stack. Limit the max batch to avoid stack overflow. */
|
/* The iovec is on stack. Limit the max batch to avoid stack overflow. */
|
||||||
#define PROCESS_MADVISE_MAX_BATCH_LIMIT (VARIABLE_ARRAY_SIZE_MAX / sizeof(struct iovec))
|
# define PROCESS_MADVISE_MAX_BATCH_LIMIT \
|
||||||
|
(VARIABLE_ARRAY_SIZE_MAX / sizeof(struct iovec))
|
||||||
#else
|
#else
|
||||||
# define PROCESS_MADVISE_MAX_BATCH_LIMIT 0
|
# define PROCESS_MADVISE_MAX_BATCH_LIMIT 0
|
||||||
#endif
|
#endif
|
||||||
@@ -37,44 +38,43 @@ edata_t *ecache_alloc(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
|||||||
edata_t *ecache_alloc_grow(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
edata_t *ecache_alloc_grow(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
||||||
ecache_t *ecache, edata_t *expand_edata, size_t size, size_t alignment,
|
ecache_t *ecache, edata_t *expand_edata, size_t size, size_t alignment,
|
||||||
bool zero, bool guarded);
|
bool zero, bool guarded);
|
||||||
void ecache_dalloc(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
void ecache_dalloc(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, ecache_t *ecache,
|
||||||
ecache_t *ecache, edata_t *edata);
|
edata_t *edata);
|
||||||
edata_t *ecache_evict(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
edata_t *ecache_evict(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
||||||
ecache_t *ecache, size_t npages_min);
|
ecache_t *ecache, size_t npages_min);
|
||||||
|
|
||||||
void extent_gdump_add(tsdn_t *tsdn, const edata_t *edata);
|
void extent_gdump_add(tsdn_t *tsdn, const edata_t *edata);
|
||||||
void extent_record(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, ecache_t *ecache,
|
void extent_record(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, ecache_t *ecache,
|
||||||
edata_t *edata);
|
edata_t *edata);
|
||||||
void extent_dalloc_gap(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
void extent_dalloc_gap(
|
||||||
edata_t *edata);
|
tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, edata_t *edata);
|
||||||
edata_t *extent_alloc_wrapper(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
edata_t *extent_alloc_wrapper(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
||||||
void *new_addr, size_t size, size_t alignment, bool zero, bool *commit,
|
void *new_addr, size_t size, size_t alignment, bool zero, bool *commit,
|
||||||
bool growing_retained);
|
bool growing_retained);
|
||||||
void extent_dalloc_wrapper(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
void extent_dalloc_wrapper(
|
||||||
edata_t *edata);
|
tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, edata_t *edata);
|
||||||
void extent_dalloc_wrapper_purged(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
void extent_dalloc_wrapper_purged(
|
||||||
edata_t *edata);
|
tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, edata_t *edata);
|
||||||
void extent_destroy_wrapper(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
void extent_destroy_wrapper(
|
||||||
edata_t *edata);
|
tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, edata_t *edata);
|
||||||
bool extent_commit_wrapper(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
|
bool extent_commit_wrapper(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
|
||||||
size_t offset, size_t length);
|
size_t offset, size_t length);
|
||||||
bool extent_purge_lazy_wrapper(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
|
bool extent_purge_lazy_wrapper(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
|
||||||
size_t offset, size_t length);
|
size_t offset, size_t length);
|
||||||
bool extent_purge_forced_wrapper(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
|
bool extent_purge_forced_wrapper(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
|
||||||
size_t offset, size_t length);
|
size_t offset, size_t length);
|
||||||
edata_t *extent_split_wrapper(tsdn_t *tsdn, pac_t *pac,
|
edata_t *extent_split_wrapper(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
||||||
ehooks_t *ehooks, edata_t *edata, size_t size_a, size_t size_b,
|
edata_t *edata, size_t size_a, size_t size_b, bool holding_core_locks);
|
||||||
bool holding_core_locks);
|
bool extent_merge_wrapper(
|
||||||
bool extent_merge_wrapper(tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks,
|
tsdn_t *tsdn, pac_t *pac, ehooks_t *ehooks, edata_t *a, edata_t *b);
|
||||||
edata_t *a, edata_t *b);
|
|
||||||
bool extent_commit_zero(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
|
bool extent_commit_zero(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
|
||||||
bool commit, bool zero, bool growing_retained);
|
bool commit, bool zero, bool growing_retained);
|
||||||
size_t extent_sn_next(pac_t *pac);
|
size_t extent_sn_next(pac_t *pac);
|
||||||
bool extent_boot(void);
|
bool extent_boot(void);
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE bool
|
JEMALLOC_ALWAYS_INLINE bool
|
||||||
extent_neighbor_head_state_mergeable(bool edata_is_head,
|
extent_neighbor_head_state_mergeable(
|
||||||
bool neighbor_is_head, bool forward) {
|
bool edata_is_head, bool neighbor_is_head, bool forward) {
|
||||||
/*
|
/*
|
||||||
* Head states checking: disallow merging if the higher addr extent is a
|
* Head states checking: disallow merging if the higher addr extent is a
|
||||||
* head extent. This helps preserve first-fit, and more importantly
|
* head extent. This helps preserve first-fit, and more importantly
|
||||||
@@ -102,8 +102,8 @@ extent_can_acquire_neighbor(edata_t *edata, rtree_contents_t contents,
|
|||||||
}
|
}
|
||||||
/* It's not safe to access *neighbor yet; must verify states first. */
|
/* It's not safe to access *neighbor yet; must verify states first. */
|
||||||
bool neighbor_is_head = contents.metadata.is_head;
|
bool neighbor_is_head = contents.metadata.is_head;
|
||||||
if (!extent_neighbor_head_state_mergeable(edata_is_head_get(edata),
|
if (!extent_neighbor_head_state_mergeable(
|
||||||
neighbor_is_head, forward)) {
|
edata_is_head_get(edata), neighbor_is_head, forward)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
extent_state_t neighbor_state = contents.metadata.state;
|
extent_state_t neighbor_state = contents.metadata.state;
|
||||||
@@ -112,8 +112,9 @@ extent_can_acquire_neighbor(edata_t *edata, rtree_contents_t contents,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* From this point, it's safe to access *neighbor. */
|
/* From this point, it's safe to access *neighbor. */
|
||||||
if (!expanding && (edata_committed_get(edata) !=
|
if (!expanding
|
||||||
edata_committed_get(neighbor))) {
|
&& (edata_committed_get(edata)
|
||||||
|
!= edata_committed_get(neighbor))) {
|
||||||
/*
|
/*
|
||||||
* Some platforms (e.g. Windows) require an explicit
|
* Some platforms (e.g. Windows) require an explicit
|
||||||
* commit step (and writing to uncommitted memory is not
|
* commit step (and writing to uncommitted memory is not
|
||||||
@@ -133,11 +134,11 @@ extent_can_acquire_neighbor(edata_t *edata, rtree_contents_t contents,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (opt_retain) {
|
if (opt_retain) {
|
||||||
assert(edata_arena_ind_get(edata) ==
|
assert(edata_arena_ind_get(edata)
|
||||||
edata_arena_ind_get(neighbor));
|
== edata_arena_ind_get(neighbor));
|
||||||
} else {
|
} else {
|
||||||
if (edata_arena_ind_get(edata) !=
|
if (edata_arena_ind_get(edata)
|
||||||
edata_arena_ind_get(neighbor)) {
|
!= edata_arena_ind_get(neighbor)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
extern bool opt_retain;
|
extern bool opt_retain;
|
||||||
|
|
||||||
void *extent_alloc_mmap(void *new_addr, size_t size, size_t alignment,
|
void *extent_alloc_mmap(
|
||||||
bool *zero, bool *commit);
|
void *new_addr, size_t size, size_t alignment, bool *zero, bool *commit);
|
||||||
bool extent_dalloc_mmap(void *addr, size_t size);
|
bool extent_dalloc_mmap(void *addr, size_t size);
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_EXTENT_MMAP_EXTERNS_H */
|
#endif /* JEMALLOC_INTERNAL_EXTENT_MMAP_EXTERNS_H */
|
||||||
|
|||||||
@@ -15,8 +15,8 @@
|
|||||||
|
|
||||||
typedef unsigned long fb_group_t;
|
typedef unsigned long fb_group_t;
|
||||||
#define FB_GROUP_BITS (ZU(1) << (LG_SIZEOF_LONG + 3))
|
#define FB_GROUP_BITS (ZU(1) << (LG_SIZEOF_LONG + 3))
|
||||||
#define FB_NGROUPS(nbits) ((nbits) / FB_GROUP_BITS \
|
#define FB_NGROUPS(nbits) \
|
||||||
+ ((nbits) % FB_GROUP_BITS == 0 ? 0 : 1))
|
((nbits) / FB_GROUP_BITS + ((nbits) % FB_GROUP_BITS == 0 ? 0 : 1))
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
fb_init(fb_group_t *fb, size_t nbits) {
|
fb_init(fb_group_t *fb, size_t nbits) {
|
||||||
@@ -75,7 +75,6 @@ fb_unset(fb_group_t *fb, size_t nbits, size_t bit) {
|
|||||||
fb[group_ind] &= ~((fb_group_t)1 << bit_ind);
|
fb[group_ind] &= ~((fb_group_t)1 << bit_ind);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some implementation details. This visitation function lets us apply a group
|
* Some implementation details. This visitation function lets us apply a group
|
||||||
* visitor to each group in the bitmap (potentially modifying it). The mask
|
* visitor to each group in the bitmap (potentially modifying it). The mask
|
||||||
@@ -94,7 +93,8 @@ fb_visit_impl(fb_group_t *fb, size_t nbits, fb_group_visitor_t visit, void *ctx,
|
|||||||
* to from bit 0.
|
* to from bit 0.
|
||||||
*/
|
*/
|
||||||
size_t first_group_cnt = (start_bit_ind + cnt > FB_GROUP_BITS
|
size_t first_group_cnt = (start_bit_ind + cnt > FB_GROUP_BITS
|
||||||
? FB_GROUP_BITS - start_bit_ind : cnt);
|
? FB_GROUP_BITS - start_bit_ind
|
||||||
|
: cnt);
|
||||||
/*
|
/*
|
||||||
* We can basically split affected words into:
|
* We can basically split affected words into:
|
||||||
* - The first group, where we touch only the high bits
|
* - The first group, where we touch only the high bits
|
||||||
@@ -104,8 +104,8 @@ fb_visit_impl(fb_group_t *fb, size_t nbits, fb_group_visitor_t visit, void *ctx,
|
|||||||
* this can lead to bad codegen for those middle words.
|
* this can lead to bad codegen for those middle words.
|
||||||
*/
|
*/
|
||||||
/* First group */
|
/* First group */
|
||||||
fb_group_t mask = ((~(fb_group_t)0)
|
fb_group_t mask =
|
||||||
>> (FB_GROUP_BITS - first_group_cnt))
|
((~(fb_group_t)0) >> (FB_GROUP_BITS - first_group_cnt))
|
||||||
<< start_bit_ind;
|
<< start_bit_ind;
|
||||||
visit(ctx, &fb[group_ind], mask);
|
visit(ctx, &fb[group_ind], mask);
|
||||||
|
|
||||||
@@ -176,8 +176,8 @@ fb_ucount(fb_group_t *fb, size_t nbits, size_t start, size_t cnt) {
|
|||||||
* Returns the number of bits in the bitmap if no such bit exists.
|
* Returns the number of bits in the bitmap if no such bit exists.
|
||||||
*/
|
*/
|
||||||
JEMALLOC_ALWAYS_INLINE ssize_t
|
JEMALLOC_ALWAYS_INLINE ssize_t
|
||||||
fb_find_impl(fb_group_t *fb, size_t nbits, size_t start, bool val,
|
fb_find_impl(
|
||||||
bool forward) {
|
fb_group_t *fb, size_t nbits, size_t start, bool val, bool forward) {
|
||||||
assert(start < nbits);
|
assert(start < nbits);
|
||||||
size_t ngroups = FB_NGROUPS(nbits);
|
size_t ngroups = FB_NGROUPS(nbits);
|
||||||
ssize_t group_ind = start / FB_GROUP_BITS;
|
ssize_t group_ind = start / FB_GROUP_BITS;
|
||||||
@@ -265,8 +265,8 @@ fb_iter_range_impl(fb_group_t *fb, size_t nbits, size_t start, size_t *r_begin,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* Half open range; the set bits are [begin, end). */
|
/* Half open range; the set bits are [begin, end). */
|
||||||
ssize_t next_range_end = fb_find_impl(fb, nbits, next_range_begin, !val,
|
ssize_t next_range_end = fb_find_impl(
|
||||||
forward);
|
fb, nbits, next_range_begin, !val, forward);
|
||||||
if (forward) {
|
if (forward) {
|
||||||
*r_begin = next_range_begin;
|
*r_begin = next_range_begin;
|
||||||
*r_len = next_range_end - next_range_begin;
|
*r_len = next_range_end - next_range_begin;
|
||||||
@@ -324,8 +324,9 @@ fb_range_longest_impl(fb_group_t *fb, size_t nbits, bool val) {
|
|||||||
size_t begin = 0;
|
size_t begin = 0;
|
||||||
size_t longest_len = 0;
|
size_t longest_len = 0;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
while (begin < nbits && fb_iter_range_impl(fb, nbits, begin, &begin,
|
while (begin < nbits
|
||||||
&len, val, /* forward */ true)) {
|
&& fb_iter_range_impl(
|
||||||
|
fb, nbits, begin, &begin, &len, val, /* forward */ true)) {
|
||||||
if (len > longest_len) {
|
if (len > longest_len) {
|
||||||
longest_len = len;
|
longest_len = len;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,10 +105,18 @@ hash_x86_32(const void *key, int len, uint32_t seed) {
|
|||||||
uint32_t k1 = 0;
|
uint32_t k1 = 0;
|
||||||
|
|
||||||
switch (len & 3) {
|
switch (len & 3) {
|
||||||
case 3: k1 ^= tail[2] << 16; JEMALLOC_FALLTHROUGH;
|
case 3:
|
||||||
case 2: k1 ^= tail[1] << 8; JEMALLOC_FALLTHROUGH;
|
k1 ^= tail[2] << 16;
|
||||||
case 1: k1 ^= tail[0]; k1 *= c1; k1 = hash_rotl_32(k1, 15);
|
JEMALLOC_FALLTHROUGH;
|
||||||
k1 *= c2; h1 ^= k1;
|
case 2:
|
||||||
|
k1 ^= tail[1] << 8;
|
||||||
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 1:
|
||||||
|
k1 ^= tail[0];
|
||||||
|
k1 *= c1;
|
||||||
|
k1 = hash_rotl_32(k1, 15);
|
||||||
|
k1 *= c2;
|
||||||
|
h1 ^= k1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,8 +129,7 @@ hash_x86_32(const void *key, int len, uint32_t seed) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
hash_x86_128(const void *key, const int len, uint32_t seed,
|
hash_x86_128(const void *key, const int len, uint32_t seed, uint64_t r_out[2]) {
|
||||||
uint64_t r_out[2]) {
|
|
||||||
const uint8_t *data = (const uint8_t *)key;
|
const uint8_t *data = (const uint8_t *)key;
|
||||||
const int nblocks = len / 16;
|
const int nblocks = len / 16;
|
||||||
|
|
||||||
@@ -138,7 +145,8 @@ hash_x86_128(const void *key, const int len, uint32_t seed,
|
|||||||
|
|
||||||
/* body */
|
/* body */
|
||||||
{
|
{
|
||||||
const uint32_t *blocks = (const uint32_t *) (data + nblocks*16);
|
const uint32_t *blocks = (const uint32_t *)(data
|
||||||
|
+ nblocks * 16);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = -nblocks; i; i++) {
|
for (i = -nblocks; i; i++) {
|
||||||
@@ -147,24 +155,40 @@ hash_x86_128(const void *key, const int len, uint32_t seed,
|
|||||||
uint32_t k3 = hash_get_block_32(blocks, i * 4 + 2);
|
uint32_t k3 = hash_get_block_32(blocks, i * 4 + 2);
|
||||||
uint32_t k4 = hash_get_block_32(blocks, i * 4 + 3);
|
uint32_t k4 = hash_get_block_32(blocks, i * 4 + 3);
|
||||||
|
|
||||||
k1 *= c1; k1 = hash_rotl_32(k1, 15); k1 *= c2; h1 ^= k1;
|
k1 *= c1;
|
||||||
|
k1 = hash_rotl_32(k1, 15);
|
||||||
|
k1 *= c2;
|
||||||
|
h1 ^= k1;
|
||||||
|
|
||||||
h1 = hash_rotl_32(h1, 19); h1 += h2;
|
h1 = hash_rotl_32(h1, 19);
|
||||||
|
h1 += h2;
|
||||||
h1 = h1 * 5 + 0x561ccd1b;
|
h1 = h1 * 5 + 0x561ccd1b;
|
||||||
|
|
||||||
k2 *= c2; k2 = hash_rotl_32(k2, 16); k2 *= c3; h2 ^= k2;
|
k2 *= c2;
|
||||||
|
k2 = hash_rotl_32(k2, 16);
|
||||||
|
k2 *= c3;
|
||||||
|
h2 ^= k2;
|
||||||
|
|
||||||
h2 = hash_rotl_32(h2, 17); h2 += h3;
|
h2 = hash_rotl_32(h2, 17);
|
||||||
|
h2 += h3;
|
||||||
h2 = h2 * 5 + 0x0bcaa747;
|
h2 = h2 * 5 + 0x0bcaa747;
|
||||||
|
|
||||||
k3 *= c3; k3 = hash_rotl_32(k3, 17); k3 *= c4; h3 ^= k3;
|
k3 *= c3;
|
||||||
|
k3 = hash_rotl_32(k3, 17);
|
||||||
|
k3 *= c4;
|
||||||
|
h3 ^= k3;
|
||||||
|
|
||||||
h3 = hash_rotl_32(h3, 15); h3 += h4;
|
h3 = hash_rotl_32(h3, 15);
|
||||||
|
h3 += h4;
|
||||||
h3 = h3 * 5 + 0x96cd1c35;
|
h3 = h3 * 5 + 0x96cd1c35;
|
||||||
|
|
||||||
k4 *= c4; k4 = hash_rotl_32(k4, 18); k4 *= c1; h4 ^= k4;
|
k4 *= c4;
|
||||||
|
k4 = hash_rotl_32(k4, 18);
|
||||||
|
k4 *= c1;
|
||||||
|
h4 ^= k4;
|
||||||
|
|
||||||
h4 = hash_rotl_32(h4, 13); h4 += h1;
|
h4 = hash_rotl_32(h4, 13);
|
||||||
|
h4 += h1;
|
||||||
h4 = h4 * 5 + 0x32ac3b17;
|
h4 = h4 * 5 + 0x32ac3b17;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,53 +202,102 @@ hash_x86_128(const void *key, const int len, uint32_t seed,
|
|||||||
uint32_t k4 = 0;
|
uint32_t k4 = 0;
|
||||||
|
|
||||||
switch (len & 15) {
|
switch (len & 15) {
|
||||||
case 15: k4 ^= tail[14] << 16; JEMALLOC_FALLTHROUGH;
|
case 15:
|
||||||
case 14: k4 ^= tail[13] << 8; JEMALLOC_FALLTHROUGH;
|
k4 ^= tail[14] << 16;
|
||||||
case 13: k4 ^= tail[12] << 0;
|
|
||||||
k4 *= c4; k4 = hash_rotl_32(k4, 18); k4 *= c1; h4 ^= k4;
|
|
||||||
JEMALLOC_FALLTHROUGH;
|
JEMALLOC_FALLTHROUGH;
|
||||||
case 12: k3 ^= (uint32_t) tail[11] << 24; JEMALLOC_FALLTHROUGH;
|
case 14:
|
||||||
case 11: k3 ^= tail[10] << 16; JEMALLOC_FALLTHROUGH;
|
k4 ^= tail[13] << 8;
|
||||||
case 10: k3 ^= tail[ 9] << 8; JEMALLOC_FALLTHROUGH;
|
|
||||||
case 9: k3 ^= tail[ 8] << 0;
|
|
||||||
k3 *= c3; k3 = hash_rotl_32(k3, 17); k3 *= c4; h3 ^= k3;
|
|
||||||
JEMALLOC_FALLTHROUGH;
|
JEMALLOC_FALLTHROUGH;
|
||||||
case 8: k2 ^= (uint32_t) tail[ 7] << 24; JEMALLOC_FALLTHROUGH;
|
case 13:
|
||||||
case 7: k2 ^= tail[ 6] << 16; JEMALLOC_FALLTHROUGH;
|
k4 ^= tail[12] << 0;
|
||||||
case 6: k2 ^= tail[ 5] << 8; JEMALLOC_FALLTHROUGH;
|
k4 *= c4;
|
||||||
case 5: k2 ^= tail[ 4] << 0;
|
k4 = hash_rotl_32(k4, 18);
|
||||||
k2 *= c2; k2 = hash_rotl_32(k2, 16); k2 *= c3; h2 ^= k2;
|
k4 *= c1;
|
||||||
|
h4 ^= k4;
|
||||||
JEMALLOC_FALLTHROUGH;
|
JEMALLOC_FALLTHROUGH;
|
||||||
case 4: k1 ^= (uint32_t) tail[ 3] << 24; JEMALLOC_FALLTHROUGH;
|
case 12:
|
||||||
case 3: k1 ^= tail[ 2] << 16; JEMALLOC_FALLTHROUGH;
|
k3 ^= (uint32_t)tail[11] << 24;
|
||||||
case 2: k1 ^= tail[ 1] << 8; JEMALLOC_FALLTHROUGH;
|
JEMALLOC_FALLTHROUGH;
|
||||||
case 1: k1 ^= tail[ 0] << 0;
|
case 11:
|
||||||
k1 *= c1; k1 = hash_rotl_32(k1, 15); k1 *= c2; h1 ^= k1;
|
k3 ^= tail[10] << 16;
|
||||||
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 10:
|
||||||
|
k3 ^= tail[9] << 8;
|
||||||
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 9:
|
||||||
|
k3 ^= tail[8] << 0;
|
||||||
|
k3 *= c3;
|
||||||
|
k3 = hash_rotl_32(k3, 17);
|
||||||
|
k3 *= c4;
|
||||||
|
h3 ^= k3;
|
||||||
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 8:
|
||||||
|
k2 ^= (uint32_t)tail[7] << 24;
|
||||||
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 7:
|
||||||
|
k2 ^= tail[6] << 16;
|
||||||
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 6:
|
||||||
|
k2 ^= tail[5] << 8;
|
||||||
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 5:
|
||||||
|
k2 ^= tail[4] << 0;
|
||||||
|
k2 *= c2;
|
||||||
|
k2 = hash_rotl_32(k2, 16);
|
||||||
|
k2 *= c3;
|
||||||
|
h2 ^= k2;
|
||||||
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 4:
|
||||||
|
k1 ^= (uint32_t)tail[3] << 24;
|
||||||
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 3:
|
||||||
|
k1 ^= tail[2] << 16;
|
||||||
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 2:
|
||||||
|
k1 ^= tail[1] << 8;
|
||||||
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 1:
|
||||||
|
k1 ^= tail[0] << 0;
|
||||||
|
k1 *= c1;
|
||||||
|
k1 = hash_rotl_32(k1, 15);
|
||||||
|
k1 *= c2;
|
||||||
|
h1 ^= k1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* finalization */
|
/* finalization */
|
||||||
h1 ^= len; h2 ^= len; h3 ^= len; h4 ^= len;
|
h1 ^= len;
|
||||||
|
h2 ^= len;
|
||||||
|
h3 ^= len;
|
||||||
|
h4 ^= len;
|
||||||
|
|
||||||
h1 += h2; h1 += h3; h1 += h4;
|
h1 += h2;
|
||||||
h2 += h1; h3 += h1; h4 += h1;
|
h1 += h3;
|
||||||
|
h1 += h4;
|
||||||
|
h2 += h1;
|
||||||
|
h3 += h1;
|
||||||
|
h4 += h1;
|
||||||
|
|
||||||
h1 = hash_fmix_32(h1);
|
h1 = hash_fmix_32(h1);
|
||||||
h2 = hash_fmix_32(h2);
|
h2 = hash_fmix_32(h2);
|
||||||
h3 = hash_fmix_32(h3);
|
h3 = hash_fmix_32(h3);
|
||||||
h4 = hash_fmix_32(h4);
|
h4 = hash_fmix_32(h4);
|
||||||
|
|
||||||
h1 += h2; h1 += h3; h1 += h4;
|
h1 += h2;
|
||||||
h2 += h1; h3 += h1; h4 += h1;
|
h1 += h3;
|
||||||
|
h1 += h4;
|
||||||
|
h2 += h1;
|
||||||
|
h3 += h1;
|
||||||
|
h4 += h1;
|
||||||
|
|
||||||
r_out[0] = (((uint64_t)h2) << 32) | h1;
|
r_out[0] = (((uint64_t)h2) << 32) | h1;
|
||||||
r_out[1] = (((uint64_t)h4) << 32) | h3;
|
r_out[1] = (((uint64_t)h4) << 32) | h3;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
hash_x64_128(const void *key, const int len, const uint32_t seed,
|
hash_x64_128(
|
||||||
uint64_t r_out[2]) {
|
const void *key, const int len, const uint32_t seed, uint64_t r_out[2]) {
|
||||||
const uint8_t *data = (const uint8_t *)key;
|
const uint8_t *data = (const uint8_t *)key;
|
||||||
const int nblocks = len / 16;
|
const int nblocks = len / 16;
|
||||||
|
|
||||||
@@ -243,14 +316,22 @@ hash_x64_128(const void *key, const int len, const uint32_t seed,
|
|||||||
uint64_t k1 = hash_get_block_64(blocks, i * 2 + 0);
|
uint64_t k1 = hash_get_block_64(blocks, i * 2 + 0);
|
||||||
uint64_t k2 = hash_get_block_64(blocks, i * 2 + 1);
|
uint64_t k2 = hash_get_block_64(blocks, i * 2 + 1);
|
||||||
|
|
||||||
k1 *= c1; k1 = hash_rotl_64(k1, 31); k1 *= c2; h1 ^= k1;
|
k1 *= c1;
|
||||||
|
k1 = hash_rotl_64(k1, 31);
|
||||||
|
k1 *= c2;
|
||||||
|
h1 ^= k1;
|
||||||
|
|
||||||
h1 = hash_rotl_64(h1, 27); h1 += h2;
|
h1 = hash_rotl_64(h1, 27);
|
||||||
|
h1 += h2;
|
||||||
h1 = h1 * 5 + 0x52dce729;
|
h1 = h1 * 5 + 0x52dce729;
|
||||||
|
|
||||||
k2 *= c2; k2 = hash_rotl_64(k2, 33); k2 *= c1; h2 ^= k2;
|
k2 *= c2;
|
||||||
|
k2 = hash_rotl_64(k2, 33);
|
||||||
|
k2 *= c1;
|
||||||
|
h2 ^= k2;
|
||||||
|
|
||||||
h2 = hash_rotl_64(h2, 31); h2 += h1;
|
h2 = hash_rotl_64(h2, 31);
|
||||||
|
h2 += h1;
|
||||||
h2 = h2 * 5 + 0x38495ab5;
|
h2 = h2 * 5 + 0x38495ab5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -262,30 +343,65 @@ hash_x64_128(const void *key, const int len, const uint32_t seed,
|
|||||||
uint64_t k2 = 0;
|
uint64_t k2 = 0;
|
||||||
|
|
||||||
switch (len & 15) {
|
switch (len & 15) {
|
||||||
case 15: k2 ^= ((uint64_t)(tail[14])) << 48; JEMALLOC_FALLTHROUGH;
|
case 15:
|
||||||
case 14: k2 ^= ((uint64_t)(tail[13])) << 40; JEMALLOC_FALLTHROUGH;
|
k2 ^= ((uint64_t)(tail[14])) << 48;
|
||||||
case 13: k2 ^= ((uint64_t)(tail[12])) << 32; JEMALLOC_FALLTHROUGH;
|
|
||||||
case 12: k2 ^= ((uint64_t)(tail[11])) << 24; JEMALLOC_FALLTHROUGH;
|
|
||||||
case 11: k2 ^= ((uint64_t)(tail[10])) << 16; JEMALLOC_FALLTHROUGH;
|
|
||||||
case 10: k2 ^= ((uint64_t)(tail[ 9])) << 8; JEMALLOC_FALLTHROUGH;
|
|
||||||
case 9: k2 ^= ((uint64_t)(tail[ 8])) << 0;
|
|
||||||
k2 *= c2; k2 = hash_rotl_64(k2, 33); k2 *= c1; h2 ^= k2;
|
|
||||||
JEMALLOC_FALLTHROUGH;
|
JEMALLOC_FALLTHROUGH;
|
||||||
case 8: k1 ^= ((uint64_t)(tail[ 7])) << 56; JEMALLOC_FALLTHROUGH;
|
case 14:
|
||||||
case 7: k1 ^= ((uint64_t)(tail[ 6])) << 48; JEMALLOC_FALLTHROUGH;
|
k2 ^= ((uint64_t)(tail[13])) << 40;
|
||||||
case 6: k1 ^= ((uint64_t)(tail[ 5])) << 40; JEMALLOC_FALLTHROUGH;
|
JEMALLOC_FALLTHROUGH;
|
||||||
case 5: k1 ^= ((uint64_t)(tail[ 4])) << 32; JEMALLOC_FALLTHROUGH;
|
case 13:
|
||||||
case 4: k1 ^= ((uint64_t)(tail[ 3])) << 24; JEMALLOC_FALLTHROUGH;
|
k2 ^= ((uint64_t)(tail[12])) << 32;
|
||||||
case 3: k1 ^= ((uint64_t)(tail[ 2])) << 16; JEMALLOC_FALLTHROUGH;
|
JEMALLOC_FALLTHROUGH;
|
||||||
case 2: k1 ^= ((uint64_t)(tail[ 1])) << 8; JEMALLOC_FALLTHROUGH;
|
case 12:
|
||||||
case 1: k1 ^= ((uint64_t)(tail[ 0])) << 0;
|
k2 ^= ((uint64_t)(tail[11])) << 24;
|
||||||
k1 *= c1; k1 = hash_rotl_64(k1, 31); k1 *= c2; h1 ^= k1;
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 11:
|
||||||
|
k2 ^= ((uint64_t)(tail[10])) << 16;
|
||||||
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 10:
|
||||||
|
k2 ^= ((uint64_t)(tail[9])) << 8;
|
||||||
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 9:
|
||||||
|
k2 ^= ((uint64_t)(tail[8])) << 0;
|
||||||
|
k2 *= c2;
|
||||||
|
k2 = hash_rotl_64(k2, 33);
|
||||||
|
k2 *= c1;
|
||||||
|
h2 ^= k2;
|
||||||
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 8:
|
||||||
|
k1 ^= ((uint64_t)(tail[7])) << 56;
|
||||||
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 7:
|
||||||
|
k1 ^= ((uint64_t)(tail[6])) << 48;
|
||||||
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 6:
|
||||||
|
k1 ^= ((uint64_t)(tail[5])) << 40;
|
||||||
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 5:
|
||||||
|
k1 ^= ((uint64_t)(tail[4])) << 32;
|
||||||
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 4:
|
||||||
|
k1 ^= ((uint64_t)(tail[3])) << 24;
|
||||||
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 3:
|
||||||
|
k1 ^= ((uint64_t)(tail[2])) << 16;
|
||||||
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 2:
|
||||||
|
k1 ^= ((uint64_t)(tail[1])) << 8;
|
||||||
|
JEMALLOC_FALLTHROUGH;
|
||||||
|
case 1:
|
||||||
|
k1 ^= ((uint64_t)(tail[0])) << 0;
|
||||||
|
k1 *= c1;
|
||||||
|
k1 = hash_rotl_64(k1, 31);
|
||||||
|
k1 *= c2;
|
||||||
|
h1 ^= k1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* finalization */
|
/* finalization */
|
||||||
h1 ^= len; h2 ^= len;
|
h1 ^= len;
|
||||||
|
h2 ^= len;
|
||||||
|
|
||||||
h1 += h2;
|
h1 += h2;
|
||||||
h2 += h1;
|
h2 += h1;
|
||||||
|
|||||||
@@ -83,7 +83,6 @@ enum hook_dalloc_e {
|
|||||||
};
|
};
|
||||||
typedef enum hook_dalloc_e hook_dalloc_t;
|
typedef enum hook_dalloc_e hook_dalloc_t;
|
||||||
|
|
||||||
|
|
||||||
enum hook_expand_e {
|
enum hook_expand_e {
|
||||||
hook_expand_realloc,
|
hook_expand_realloc,
|
||||||
hook_expand_rallocx,
|
hook_expand_rallocx,
|
||||||
@@ -91,16 +90,15 @@ enum hook_expand_e {
|
|||||||
};
|
};
|
||||||
typedef enum hook_expand_e hook_expand_t;
|
typedef enum hook_expand_e hook_expand_t;
|
||||||
|
|
||||||
typedef void (*hook_alloc)(
|
typedef void (*hook_alloc)(void *extra, hook_alloc_t type, void *result,
|
||||||
void *extra, hook_alloc_t type, void *result, uintptr_t result_raw,
|
uintptr_t result_raw, uintptr_t args_raw[3]);
|
||||||
uintptr_t args_raw[3]);
|
|
||||||
|
|
||||||
typedef void (*hook_dalloc)(
|
typedef void (*hook_dalloc)(
|
||||||
void *extra, hook_dalloc_t type, void *address, uintptr_t args_raw[3]);
|
void *extra, hook_dalloc_t type, void *address, uintptr_t args_raw[3]);
|
||||||
|
|
||||||
typedef void (*hook_expand)(
|
typedef void (*hook_expand)(void *extra, hook_expand_t type, void *address,
|
||||||
void *extra, hook_expand_t type, void *address, size_t old_usize,
|
size_t old_usize, size_t new_usize, uintptr_t result_raw,
|
||||||
size_t new_usize, uintptr_t result_raw, uintptr_t args_raw[4]);
|
uintptr_t args_raw[4]);
|
||||||
|
|
||||||
typedef struct hooks_s hooks_t;
|
typedef struct hooks_s hooks_t;
|
||||||
struct hooks_s {
|
struct hooks_s {
|
||||||
@@ -156,8 +154,8 @@ void hook_remove(tsdn_t *tsdn, void *opaque);
|
|||||||
void hook_invoke_alloc(hook_alloc_t type, void *result, uintptr_t result_raw,
|
void hook_invoke_alloc(hook_alloc_t type, void *result, uintptr_t result_raw,
|
||||||
uintptr_t args_raw[3]);
|
uintptr_t args_raw[3]);
|
||||||
|
|
||||||
void hook_invoke_dalloc(hook_dalloc_t type, void *address,
|
void hook_invoke_dalloc(
|
||||||
uintptr_t args_raw[3]);
|
hook_dalloc_t type, void *address, uintptr_t args_raw[3]);
|
||||||
|
|
||||||
void hook_invoke_expand(hook_expand_t type, void *address, size_t old_usize,
|
void hook_invoke_expand(hook_expand_t type, void *address, size_t old_usize,
|
||||||
size_t new_usize, uintptr_t result_raw, uintptr_t args_raw[4]);
|
size_t new_usize, uintptr_t result_raw, uintptr_t args_raw[4]);
|
||||||
|
|||||||
@@ -156,14 +156,15 @@ bool hpa_hugepage_size_exceeds_limit(void);
|
|||||||
* just that it can function properly given the system it's running on.
|
* just that it can function properly given the system it's running on.
|
||||||
*/
|
*/
|
||||||
bool hpa_supported(void);
|
bool hpa_supported(void);
|
||||||
bool hpa_central_init(hpa_central_t *central, base_t *base, const hpa_hooks_t *hooks);
|
bool hpa_central_init(
|
||||||
|
hpa_central_t *central, base_t *base, const hpa_hooks_t *hooks);
|
||||||
bool hpa_shard_init(hpa_shard_t *shard, hpa_central_t *central, emap_t *emap,
|
bool hpa_shard_init(hpa_shard_t *shard, hpa_central_t *central, emap_t *emap,
|
||||||
base_t *base, edata_cache_t *edata_cache, unsigned ind,
|
base_t *base, edata_cache_t *edata_cache, unsigned ind,
|
||||||
const hpa_shard_opts_t *opts);
|
const hpa_shard_opts_t *opts);
|
||||||
|
|
||||||
void hpa_shard_stats_accum(hpa_shard_stats_t *dst, hpa_shard_stats_t *src);
|
void hpa_shard_stats_accum(hpa_shard_stats_t *dst, hpa_shard_stats_t *src);
|
||||||
void hpa_shard_stats_merge(tsdn_t *tsdn, hpa_shard_t *shard,
|
void hpa_shard_stats_merge(
|
||||||
hpa_shard_stats_t *dst);
|
tsdn_t *tsdn, hpa_shard_t *shard, hpa_shard_stats_t *dst);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Notify the shard that we won't use it for allocations much longer. Due to
|
* Notify the shard that we won't use it for allocations much longer. Due to
|
||||||
@@ -173,8 +174,8 @@ void hpa_shard_stats_merge(tsdn_t *tsdn, hpa_shard_t *shard,
|
|||||||
void hpa_shard_disable(tsdn_t *tsdn, hpa_shard_t *shard);
|
void hpa_shard_disable(tsdn_t *tsdn, hpa_shard_t *shard);
|
||||||
void hpa_shard_destroy(tsdn_t *tsdn, hpa_shard_t *shard);
|
void hpa_shard_destroy(tsdn_t *tsdn, hpa_shard_t *shard);
|
||||||
|
|
||||||
void hpa_shard_set_deferral_allowed(tsdn_t *tsdn, hpa_shard_t *shard,
|
void hpa_shard_set_deferral_allowed(
|
||||||
bool deferral_allowed);
|
tsdn_t *tsdn, hpa_shard_t *shard, bool deferral_allowed);
|
||||||
void hpa_shard_do_deferred_work(tsdn_t *tsdn, hpa_shard_t *shard);
|
void hpa_shard_do_deferred_work(tsdn_t *tsdn, hpa_shard_t *shard);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ hpa_try_vectorized_purge(
|
|||||||
* failed, we could avoid that penalty.
|
* failed, we could avoid that penalty.
|
||||||
*/
|
*/
|
||||||
for (size_t i = 0; i < vlen; ++i) {
|
for (size_t i = 0; i < vlen; ++i) {
|
||||||
shard->central->hooks.purge(vec[i].iov_base, vec[i].iov_len);
|
shard->central->hooks.purge(
|
||||||
|
vec[i].iov_base, vec[i].iov_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -250,7 +250,6 @@ hpdata_changing_state_get(const hpdata_t *hpdata) {
|
|||||||
return hpdata->h_mid_purge || hpdata->h_mid_hugify;
|
return hpdata->h_mid_purge || hpdata->h_mid_hugify;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
hpdata_updating_get(const hpdata_t *hpdata) {
|
hpdata_updating_get(const hpdata_t *hpdata) {
|
||||||
return hpdata->h_updating;
|
return hpdata->h_updating;
|
||||||
@@ -398,8 +397,8 @@ struct hpdata_purge_state_s {
|
|||||||
* Returns the number of dirty pages that will be purged and sets nranges
|
* Returns the number of dirty pages that will be purged and sets nranges
|
||||||
* to number of ranges with dirty pages that will be purged.
|
* to number of ranges with dirty pages that will be purged.
|
||||||
*/
|
*/
|
||||||
size_t hpdata_purge_begin(hpdata_t *hpdata, hpdata_purge_state_t *purge_state,
|
size_t hpdata_purge_begin(
|
||||||
size_t *nranges);
|
hpdata_t *hpdata, hpdata_purge_state_t *purge_state, size_t *nranges);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there are more extents to purge, sets *r_purge_addr and *r_purge_size to
|
* If there are more extents to purge, sets *r_purge_addr and *r_purge_size to
|
||||||
|
|||||||
@@ -34,10 +34,10 @@ struct inspect_extent_util_stats_verbose_s {
|
|||||||
size_t bin_nregs;
|
size_t bin_nregs;
|
||||||
};
|
};
|
||||||
|
|
||||||
void inspect_extent_util_stats_get(tsdn_t *tsdn, const void *ptr,
|
void inspect_extent_util_stats_get(
|
||||||
size_t *nfree, size_t *nregs, size_t *size);
|
tsdn_t *tsdn, const void *ptr, size_t *nfree, size_t *nregs, size_t *size);
|
||||||
void inspect_extent_util_stats_verbose_get(tsdn_t *tsdn, const void *ptr,
|
void inspect_extent_util_stats_verbose_get(tsdn_t *tsdn, const void *ptr,
|
||||||
size_t *nfree, size_t *nregs, size_t *size,
|
size_t *nfree, size_t *nregs, size_t *size, size_t *bin_nfree,
|
||||||
size_t *bin_nfree, size_t *bin_nregs, void **slabcur_addr);
|
size_t *bin_nregs, void **slabcur_addr);
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_INSPECT_H */
|
#endif /* JEMALLOC_INTERNAL_INSPECT_H */
|
||||||
|
|||||||
@@ -32,7 +32,8 @@
|
|||||||
# include <sys/uio.h>
|
# include <sys/uio.h>
|
||||||
# endif
|
# endif
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
# if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
|
# if defined(__FreeBSD__) || defined(__DragonFly__) \
|
||||||
|
|| defined(__OpenBSD__)
|
||||||
# include <pthread_np.h>
|
# include <pthread_np.h>
|
||||||
# include <sched.h>
|
# include <sched.h>
|
||||||
# if defined(__FreeBSD__)
|
# if defined(__FreeBSD__)
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ percpu_arena_choose(void) {
|
|||||||
assert(cpuid >= 0);
|
assert(cpuid >= 0);
|
||||||
|
|
||||||
unsigned arena_ind;
|
unsigned arena_ind;
|
||||||
if ((opt_percpu_arena == percpu_arena) || ((unsigned)cpuid < ncpus /
|
if ((opt_percpu_arena == percpu_arena)
|
||||||
2)) {
|
|| ((unsigned)cpuid < ncpus / 2)) {
|
||||||
arena_ind = cpuid;
|
arena_ind = cpuid;
|
||||||
} else {
|
} else {
|
||||||
assert(opt_percpu_arena == per_phycpu_arena);
|
assert(opt_percpu_arena == per_phycpu_arena);
|
||||||
|
|||||||
@@ -24,13 +24,12 @@ percpu_arena_update(tsd_t *tsd, unsigned cpu) {
|
|||||||
if (tcache != NULL) {
|
if (tcache != NULL) {
|
||||||
tcache_slow_t *tcache_slow = tsd_tcache_slowp_get(tsd);
|
tcache_slow_t *tcache_slow = tsd_tcache_slowp_get(tsd);
|
||||||
assert(tcache_slow->arena != NULL);
|
assert(tcache_slow->arena != NULL);
|
||||||
tcache_arena_reassociate(tsd_tsdn(tsd), tcache_slow,
|
tcache_arena_reassociate(
|
||||||
tcache, newarena);
|
tsd_tsdn(tsd), tcache_slow, tcache, newarena);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Choose an arena based on a per-thread value. */
|
/* Choose an arena based on a per-thread value. */
|
||||||
static inline arena_t *
|
static inline arena_t *
|
||||||
arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) {
|
arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) {
|
||||||
@@ -54,15 +53,15 @@ arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) {
|
|||||||
tcache_t *tcache = tsd_tcachep_get(tsd);
|
tcache_t *tcache = tsd_tcachep_get(tsd);
|
||||||
if (tcache_slow->arena != NULL) {
|
if (tcache_slow->arena != NULL) {
|
||||||
/* See comments in tsd_tcache_data_init().*/
|
/* See comments in tsd_tcache_data_init().*/
|
||||||
assert(tcache_slow->arena ==
|
assert(tcache_slow->arena
|
||||||
arena_get(tsd_tsdn(tsd), 0, false));
|
== arena_get(tsd_tsdn(tsd), 0, false));
|
||||||
if (tcache_slow->arena != ret) {
|
if (tcache_slow->arena != ret) {
|
||||||
tcache_arena_reassociate(tsd_tsdn(tsd),
|
tcache_arena_reassociate(tsd_tsdn(tsd),
|
||||||
tcache_slow, tcache, ret);
|
tcache_slow, tcache, ret);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tcache_arena_associate(tsd_tsdn(tsd),
|
tcache_arena_associate(
|
||||||
tcache_slow, tcache, ret);
|
tsd_tsdn(tsd), tcache_slow, tcache, ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,10 +71,10 @@ arena_choose_impl(tsd_t *tsd, arena_t *arena, bool internal) {
|
|||||||
* auto percpu arena range, (i.e. thread is assigned to a manually
|
* auto percpu arena range, (i.e. thread is assigned to a manually
|
||||||
* managed arena), then percpu arena is skipped.
|
* managed arena), then percpu arena is skipped.
|
||||||
*/
|
*/
|
||||||
if (have_percpu_arena && PERCPU_ARENA_ENABLED(opt_percpu_arena) &&
|
if (have_percpu_arena && PERCPU_ARENA_ENABLED(opt_percpu_arena)
|
||||||
!internal && (arena_ind_get(ret) <
|
&& !internal
|
||||||
percpu_arena_ind_limit(opt_percpu_arena)) && (ret->last_thd !=
|
&& (arena_ind_get(ret) < percpu_arena_ind_limit(opt_percpu_arena))
|
||||||
tsd_tsdn(tsd))) {
|
&& (ret->last_thd != tsd_tsdn(tsd))) {
|
||||||
unsigned ind = percpu_arena_choose();
|
unsigned ind = percpu_arena_choose();
|
||||||
if (arena_ind_get(ret) != ind) {
|
if (arena_ind_get(ret) != ind) {
|
||||||
percpu_arena_update(tsd, ind);
|
percpu_arena_update(tsd, ind);
|
||||||
|
|||||||
@@ -63,11 +63,12 @@ iallocztm_explicit_slab(tsdn_t *tsdn, size_t size, szind_t ind, bool zero,
|
|||||||
assert(!is_internal || tcache == NULL);
|
assert(!is_internal || tcache == NULL);
|
||||||
assert(!is_internal || arena == NULL || arena_is_auto(arena));
|
assert(!is_internal || arena == NULL || arena_is_auto(arena));
|
||||||
if (!tsdn_null(tsdn) && tsd_reentrancy_level_get(tsdn_tsd(tsdn)) == 0) {
|
if (!tsdn_null(tsdn) && tsd_reentrancy_level_get(tsdn_tsd(tsdn)) == 0) {
|
||||||
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
witness_assert_depth_to_rank(
|
||||||
WITNESS_RANK_CORE, 0);
|
tsdn_witness_tsdp_get(tsdn), WITNESS_RANK_CORE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = arena_malloc(tsdn, arena, size, ind, zero, slab, tcache, slow_path);
|
ret = arena_malloc(
|
||||||
|
tsdn, arena, size, ind, zero, slab, tcache, slow_path);
|
||||||
if (config_stats && is_internal && likely(ret != NULL)) {
|
if (config_stats && is_internal && likely(ret != NULL)) {
|
||||||
arena_internal_add(iaalloc(tsdn, ret), isalloc(tsdn, ret));
|
arena_internal_add(iaalloc(tsdn, ret), isalloc(tsdn, ret));
|
||||||
}
|
}
|
||||||
@@ -78,8 +79,8 @@ JEMALLOC_ALWAYS_INLINE void *
|
|||||||
iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache,
|
iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache,
|
||||||
bool is_internal, arena_t *arena, bool slow_path) {
|
bool is_internal, arena_t *arena, bool slow_path) {
|
||||||
bool slab = sz_can_use_slab(size);
|
bool slab = sz_can_use_slab(size);
|
||||||
return iallocztm_explicit_slab(tsdn, size, ind, zero, slab, tcache,
|
return iallocztm_explicit_slab(
|
||||||
is_internal, arena, slow_path);
|
tsdn, size, ind, zero, slab, tcache, is_internal, arena, slow_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void *
|
JEMALLOC_ALWAYS_INLINE void *
|
||||||
@@ -89,8 +90,8 @@ ialloc(tsd_t *tsd, size_t size, szind_t ind, bool zero, bool slow_path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void *
|
JEMALLOC_ALWAYS_INLINE void *
|
||||||
ipallocztm_explicit_slab(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero,
|
ipallocztm_explicit_slab(tsdn_t *tsdn, size_t usize, size_t alignment,
|
||||||
bool slab, tcache_t *tcache, bool is_internal, arena_t *arena) {
|
bool zero, bool slab, tcache_t *tcache, bool is_internal, arena_t *arena) {
|
||||||
void *ret;
|
void *ret;
|
||||||
|
|
||||||
assert(!slab || sz_can_use_slab(usize)); /* slab && large is illegal */
|
assert(!slab || sz_can_use_slab(usize)); /* slab && large is illegal */
|
||||||
@@ -98,8 +99,8 @@ ipallocztm_explicit_slab(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero
|
|||||||
assert(usize == sz_sa2u(usize, alignment));
|
assert(usize == sz_sa2u(usize, alignment));
|
||||||
assert(!is_internal || tcache == NULL);
|
assert(!is_internal || tcache == NULL);
|
||||||
assert(!is_internal || arena == NULL || arena_is_auto(arena));
|
assert(!is_internal || arena == NULL || arena_is_auto(arena));
|
||||||
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
witness_assert_depth_to_rank(
|
||||||
WITNESS_RANK_CORE, 0);
|
tsdn_witness_tsdp_get(tsdn), WITNESS_RANK_CORE, 0);
|
||||||
|
|
||||||
ret = arena_palloc(tsdn, arena, usize, alignment, zero, slab, tcache);
|
ret = arena_palloc(tsdn, arena, usize, alignment, zero, slab, tcache);
|
||||||
assert(ALIGNMENT_ADDR2BASE(ret, alignment) == ret);
|
assert(ALIGNMENT_ADDR2BASE(ret, alignment) == ret);
|
||||||
@@ -123,10 +124,10 @@ ipalloct(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero,
|
|||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void *
|
JEMALLOC_ALWAYS_INLINE void *
|
||||||
ipalloct_explicit_slab(tsdn_t *tsdn, size_t usize, size_t alignment,
|
ipalloct_explicit_slab(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero,
|
||||||
bool zero, bool slab, tcache_t *tcache, arena_t *arena) {
|
bool slab, tcache_t *tcache, arena_t *arena) {
|
||||||
return ipallocztm_explicit_slab(tsdn, usize, alignment, zero, slab,
|
return ipallocztm_explicit_slab(
|
||||||
tcache, false, arena);
|
tsdn, usize, alignment, zero, slab, tcache, false, arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void *
|
JEMALLOC_ALWAYS_INLINE void *
|
||||||
@@ -146,13 +147,13 @@ idalloctm(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
|
|||||||
assert(ptr != NULL);
|
assert(ptr != NULL);
|
||||||
assert(!is_internal || tcache == NULL);
|
assert(!is_internal || tcache == NULL);
|
||||||
assert(!is_internal || arena_is_auto(iaalloc(tsdn, ptr)));
|
assert(!is_internal || arena_is_auto(iaalloc(tsdn, ptr)));
|
||||||
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
witness_assert_depth_to_rank(
|
||||||
WITNESS_RANK_CORE, 0);
|
tsdn_witness_tsdp_get(tsdn), WITNESS_RANK_CORE, 0);
|
||||||
if (config_stats && is_internal) {
|
if (config_stats && is_internal) {
|
||||||
arena_internal_sub(iaalloc(tsdn, ptr), isalloc(tsdn, ptr));
|
arena_internal_sub(iaalloc(tsdn, ptr), isalloc(tsdn, ptr));
|
||||||
}
|
}
|
||||||
if (!is_internal && !tsdn_null(tsdn) &&
|
if (!is_internal && !tsdn_null(tsdn)
|
||||||
tsd_reentrancy_level_get(tsdn_tsd(tsdn)) != 0) {
|
&& tsd_reentrancy_level_get(tsdn_tsd(tsdn)) != 0) {
|
||||||
assert(tcache == NULL);
|
assert(tcache == NULL);
|
||||||
}
|
}
|
||||||
arena_dalloc(tsdn, ptr, tcache, alloc_ctx, slow_path);
|
arena_dalloc(tsdn, ptr, tcache, alloc_ctx, slow_path);
|
||||||
@@ -166,8 +167,8 @@ idalloc(tsd_t *tsd, void *ptr) {
|
|||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
|
isdalloct(tsdn_t *tsdn, void *ptr, size_t size, tcache_t *tcache,
|
||||||
emap_alloc_ctx_t *alloc_ctx, bool slow_path) {
|
emap_alloc_ctx_t *alloc_ctx, bool slow_path) {
|
||||||
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
witness_assert_depth_to_rank(
|
||||||
WITNESS_RANK_CORE, 0);
|
tsdn_witness_tsdp_get(tsdn), WITNESS_RANK_CORE, 0);
|
||||||
arena_sdalloc(tsdn, ptr, size, tcache, alloc_ctx, slow_path);
|
arena_sdalloc(tsdn, ptr, size, tcache, alloc_ctx, slow_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,8 +176,8 @@ JEMALLOC_ALWAYS_INLINE void *
|
|||||||
iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
||||||
size_t alignment, bool zero, bool slab, tcache_t *tcache, arena_t *arena,
|
size_t alignment, bool zero, bool slab, tcache_t *tcache, arena_t *arena,
|
||||||
hook_ralloc_args_t *hook_args) {
|
hook_ralloc_args_t *hook_args) {
|
||||||
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
witness_assert_depth_to_rank(
|
||||||
WITNESS_RANK_CORE, 0);
|
tsdn_witness_tsdp_get(tsdn), WITNESS_RANK_CORE, 0);
|
||||||
void *p;
|
void *p;
|
||||||
size_t usize, copysize;
|
size_t usize, copysize;
|
||||||
|
|
||||||
@@ -184,8 +185,8 @@ iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
|||||||
if (unlikely(usize == 0 || usize > SC_LARGE_MAXCLASS)) {
|
if (unlikely(usize == 0 || usize > SC_LARGE_MAXCLASS)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
p = ipalloct_explicit_slab(tsdn, usize, alignment, zero, slab,
|
p = ipalloct_explicit_slab(
|
||||||
tcache, arena);
|
tsdn, usize, alignment, zero, slab, tcache, arena);
|
||||||
if (p == NULL) {
|
if (p == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -195,11 +196,12 @@ iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
|||||||
*/
|
*/
|
||||||
copysize = (size < oldsize) ? size : oldsize;
|
copysize = (size < oldsize) ? size : oldsize;
|
||||||
memcpy(p, ptr, copysize);
|
memcpy(p, ptr, copysize);
|
||||||
hook_invoke_alloc(hook_args->is_realloc
|
hook_invoke_alloc(
|
||||||
? hook_alloc_realloc : hook_alloc_rallocx, p, (uintptr_t)p,
|
hook_args->is_realloc ? hook_alloc_realloc : hook_alloc_rallocx, p,
|
||||||
hook_args->args);
|
(uintptr_t)p, hook_args->args);
|
||||||
hook_invoke_dalloc(hook_args->is_realloc
|
hook_invoke_dalloc(
|
||||||
? hook_dalloc_realloc : hook_dalloc_rallocx, ptr, hook_args->args);
|
hook_args->is_realloc ? hook_dalloc_realloc : hook_dalloc_rallocx,
|
||||||
|
ptr, hook_args->args);
|
||||||
isdalloct(tsdn, ptr, oldsize, tcache, NULL, true);
|
isdalloct(tsdn, ptr, oldsize, tcache, NULL, true);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@@ -214,15 +216,14 @@ iralloct_realign(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
|||||||
JEMALLOC_ALWAYS_INLINE void *
|
JEMALLOC_ALWAYS_INLINE void *
|
||||||
iralloct_explicit_slab(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
iralloct_explicit_slab(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
||||||
size_t alignment, bool zero, bool slab, tcache_t *tcache, arena_t *arena,
|
size_t alignment, bool zero, bool slab, tcache_t *tcache, arena_t *arena,
|
||||||
hook_ralloc_args_t *hook_args)
|
hook_ralloc_args_t *hook_args) {
|
||||||
{
|
|
||||||
assert(ptr != NULL);
|
assert(ptr != NULL);
|
||||||
assert(size != 0);
|
assert(size != 0);
|
||||||
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
witness_assert_depth_to_rank(
|
||||||
WITNESS_RANK_CORE, 0);
|
tsdn_witness_tsdp_get(tsdn), WITNESS_RANK_CORE, 0);
|
||||||
|
|
||||||
if (alignment != 0 && ((uintptr_t)ptr & ((uintptr_t)alignment-1))
|
if (alignment != 0
|
||||||
!= 0) {
|
&& ((uintptr_t)ptr & ((uintptr_t)alignment - 1)) != 0) {
|
||||||
/*
|
/*
|
||||||
* Existing object alignment is inadequate; allocate new space
|
* Existing object alignment is inadequate; allocate new space
|
||||||
* and copy.
|
* and copy.
|
||||||
@@ -238,8 +239,7 @@ iralloct_explicit_slab(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
|||||||
JEMALLOC_ALWAYS_INLINE void *
|
JEMALLOC_ALWAYS_INLINE void *
|
||||||
iralloct(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t alignment,
|
iralloct(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t alignment,
|
||||||
size_t usize, bool zero, tcache_t *tcache, arena_t *arena,
|
size_t usize, bool zero, tcache_t *tcache, arena_t *arena,
|
||||||
hook_ralloc_args_t *hook_args)
|
hook_ralloc_args_t *hook_args) {
|
||||||
{
|
|
||||||
bool slab = sz_can_use_slab(usize);
|
bool slab = sz_can_use_slab(usize);
|
||||||
return iralloct_explicit_slab(tsdn, ptr, oldsize, size, alignment, zero,
|
return iralloct_explicit_slab(tsdn, ptr, oldsize, size, alignment, zero,
|
||||||
slab, tcache, arena, hook_args);
|
slab, tcache, arena, hook_args);
|
||||||
@@ -257,23 +257,23 @@ ixalloc(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size, size_t extra,
|
|||||||
size_t alignment, bool zero, size_t *newsize) {
|
size_t alignment, bool zero, size_t *newsize) {
|
||||||
assert(ptr != NULL);
|
assert(ptr != NULL);
|
||||||
assert(size != 0);
|
assert(size != 0);
|
||||||
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
witness_assert_depth_to_rank(
|
||||||
WITNESS_RANK_CORE, 0);
|
tsdn_witness_tsdp_get(tsdn), WITNESS_RANK_CORE, 0);
|
||||||
|
|
||||||
if (alignment != 0 && ((uintptr_t)ptr & ((uintptr_t)alignment-1))
|
if (alignment != 0
|
||||||
!= 0) {
|
&& ((uintptr_t)ptr & ((uintptr_t)alignment - 1)) != 0) {
|
||||||
/* Existing object alignment is inadequate. */
|
/* Existing object alignment is inadequate. */
|
||||||
*newsize = oldsize;
|
*newsize = oldsize;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return arena_ralloc_no_move(tsdn, ptr, oldsize, size, extra, zero,
|
return arena_ralloc_no_move(
|
||||||
newsize);
|
tsdn, ptr, oldsize, size, extra, zero, newsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
fastpath_success_finish(tsd_t *tsd, uint64_t allocated_after,
|
fastpath_success_finish(
|
||||||
cache_bin_t *bin, void *ret) {
|
tsd_t *tsd, uint64_t allocated_after, cache_bin_t *bin, void *ret) {
|
||||||
thread_allocated_set(tsd, allocated_after);
|
thread_allocated_set(tsd, allocated_after);
|
||||||
if (config_stats) {
|
if (config_stats) {
|
||||||
bin->tstats.nrequests++;
|
bin->tstats.nrequests++;
|
||||||
@@ -331,8 +331,8 @@ imalloc_fastpath(size_t size, void *(fallback_alloc)(size_t)) {
|
|||||||
sz_size2index_usize_fastpath(size, &ind, &usize);
|
sz_size2index_usize_fastpath(size, &ind, &usize);
|
||||||
/* Fast path relies on size being a bin. */
|
/* Fast path relies on size being a bin. */
|
||||||
assert(ind < SC_NBINS);
|
assert(ind < SC_NBINS);
|
||||||
assert((SC_LOOKUP_MAXCLASS < SC_SMALL_MAXCLASS) &&
|
assert((SC_LOOKUP_MAXCLASS < SC_SMALL_MAXCLASS)
|
||||||
(size <= SC_SMALL_MAXCLASS));
|
&& (size <= SC_SMALL_MAXCLASS));
|
||||||
|
|
||||||
uint64_t allocated, threshold;
|
uint64_t allocated, threshold;
|
||||||
te_malloc_fastpath_ctx(tsd, &allocated, &threshold);
|
te_malloc_fastpath_ctx(tsd, &allocated, &threshold);
|
||||||
@@ -394,8 +394,8 @@ tcache_get_from_ind(tsd_t *tsd, unsigned tcache_ind, bool slow, bool is_alloc) {
|
|||||||
/* Getting tcache ptr unconditionally. */
|
/* Getting tcache ptr unconditionally. */
|
||||||
tcache = tsd_tcachep_get(tsd);
|
tcache = tsd_tcachep_get(tsd);
|
||||||
assert(tcache == tcache_get(tsd));
|
assert(tcache == tcache_get(tsd));
|
||||||
} else if (is_alloc ||
|
} else if (is_alloc
|
||||||
likely(tsd_reentrancy_level_get(tsd) == 0)) {
|
|| likely(tsd_reentrancy_level_get(tsd) == 0)) {
|
||||||
tcache = tcache_get(tsd);
|
tcache = tcache_get(tsd);
|
||||||
} else {
|
} else {
|
||||||
tcache = NULL;
|
tcache = NULL;
|
||||||
@@ -405,8 +405,8 @@ tcache_get_from_ind(tsd_t *tsd, unsigned tcache_ind, bool slow, bool is_alloc) {
|
|||||||
* Should not specify tcache on deallocation path when being
|
* Should not specify tcache on deallocation path when being
|
||||||
* reentrant.
|
* reentrant.
|
||||||
*/
|
*/
|
||||||
assert(is_alloc || tsd_reentrancy_level_get(tsd) == 0 ||
|
assert(is_alloc || tsd_reentrancy_level_get(tsd) == 0
|
||||||
tsd_state_nocleanup(tsd));
|
|| tsd_state_nocleanup(tsd));
|
||||||
if (tcache_ind == TCACHE_IND_NONE) {
|
if (tcache_ind == TCACHE_IND_NONE) {
|
||||||
tcache = NULL;
|
tcache = NULL;
|
||||||
} else {
|
} else {
|
||||||
@@ -420,14 +420,14 @@ JEMALLOC_ALWAYS_INLINE bool
|
|||||||
maybe_check_alloc_ctx(tsd_t *tsd, void *ptr, emap_alloc_ctx_t *alloc_ctx) {
|
maybe_check_alloc_ctx(tsd_t *tsd, void *ptr, emap_alloc_ctx_t *alloc_ctx) {
|
||||||
if (config_opt_size_checks) {
|
if (config_opt_size_checks) {
|
||||||
emap_alloc_ctx_t dbg_ctx;
|
emap_alloc_ctx_t dbg_ctx;
|
||||||
emap_alloc_ctx_lookup(tsd_tsdn(tsd), &arena_emap_global, ptr,
|
emap_alloc_ctx_lookup(
|
||||||
&dbg_ctx);
|
tsd_tsdn(tsd), &arena_emap_global, ptr, &dbg_ctx);
|
||||||
if (alloc_ctx->szind != dbg_ctx.szind) {
|
if (alloc_ctx->szind != dbg_ctx.szind) {
|
||||||
safety_check_fail_sized_dealloc(
|
safety_check_fail_sized_dealloc(
|
||||||
/* current_dealloc */ true, ptr,
|
/* current_dealloc */ true, ptr,
|
||||||
/* true_size */ emap_alloc_ctx_usize_get(&dbg_ctx),
|
/* true_size */ emap_alloc_ctx_usize_get(&dbg_ctx),
|
||||||
/* input_size */ emap_alloc_ctx_usize_get(
|
/* input_size */
|
||||||
alloc_ctx));
|
emap_alloc_ctx_usize_get(alloc_ctx));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (alloc_ctx->slab != dbg_ctx.slab) {
|
if (alloc_ctx->slab != dbg_ctx.slab) {
|
||||||
@@ -482,7 +482,8 @@ free_fastpath_nonfast_aligned(void *ptr, bool check_prof) {
|
|||||||
|
|
||||||
/* Returns whether or not the free attempt was successful. */
|
/* Returns whether or not the free attempt was successful. */
|
||||||
JEMALLOC_ALWAYS_INLINE
|
JEMALLOC_ALWAYS_INLINE
|
||||||
bool free_fastpath(void *ptr, size_t size, bool size_hint) {
|
bool
|
||||||
|
free_fastpath(void *ptr, size_t size, bool size_hint) {
|
||||||
tsd_t *tsd = tsd_get(false);
|
tsd_t *tsd = tsd_get(false);
|
||||||
/* The branch gets optimized away unless tsd_get_allocates(). */
|
/* The branch gets optimized away unless tsd_get_allocates(). */
|
||||||
if (unlikely(tsd == NULL)) {
|
if (unlikely(tsd == NULL)) {
|
||||||
@@ -493,18 +494,18 @@ bool free_fastpath(void *ptr, size_t size, bool size_hint) {
|
|||||||
* testing (deallocated_after >= threshold) later in this function.
|
* testing (deallocated_after >= threshold) later in this function.
|
||||||
* The threshold will be set to 0 when !tsd_fast.
|
* The threshold will be set to 0 when !tsd_fast.
|
||||||
*/
|
*/
|
||||||
assert(tsd_fast(tsd) ||
|
assert(tsd_fast(tsd)
|
||||||
*tsd_thread_deallocated_next_event_fastp_get_unsafe(tsd) == 0);
|
|| *tsd_thread_deallocated_next_event_fastp_get_unsafe(tsd) == 0);
|
||||||
|
|
||||||
emap_alloc_ctx_t alloc_ctx JEMALLOC_CC_SILENCE_INIT({0, 0, false});
|
emap_alloc_ctx_t alloc_ctx JEMALLOC_CC_SILENCE_INIT({0, 0, false});
|
||||||
size_t usize;
|
size_t usize;
|
||||||
if (!size_hint) {
|
if (!size_hint) {
|
||||||
bool err = emap_alloc_ctx_try_lookup_fast(tsd,
|
bool err = emap_alloc_ctx_try_lookup_fast(
|
||||||
&arena_emap_global, ptr, &alloc_ctx);
|
tsd, &arena_emap_global, ptr, &alloc_ctx);
|
||||||
|
|
||||||
/* Note: profiled objects will have alloc_ctx.slab set */
|
/* Note: profiled objects will have alloc_ctx.slab set */
|
||||||
if (unlikely(err || !alloc_ctx.slab ||
|
if (unlikely(err || !alloc_ctx.slab
|
||||||
free_fastpath_nonfast_aligned(ptr,
|
|| free_fastpath_nonfast_aligned(ptr,
|
||||||
/* check_prof */ false))) {
|
/* check_prof */ false))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -516,8 +517,8 @@ bool free_fastpath(void *ptr, size_t size, bool size_hint) {
|
|||||||
* special aligned objects. The alignment check will also check
|
* special aligned objects. The alignment check will also check
|
||||||
* for null ptr.
|
* for null ptr.
|
||||||
*/
|
*/
|
||||||
if (unlikely(size > SC_LOOKUP_MAXCLASS ||
|
if (unlikely(size > SC_LOOKUP_MAXCLASS
|
||||||
free_fastpath_nonfast_aligned(ptr,
|
|| free_fastpath_nonfast_aligned(ptr,
|
||||||
/* check_prof */ true))) {
|
/* check_prof */ true))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
# ifdef _MSC_VER
|
# ifdef _MSC_VER
|
||||||
# define JEMALLOC_ALWAYS_INLINE static __forceinline
|
# define JEMALLOC_ALWAYS_INLINE static __forceinline
|
||||||
# else
|
# else
|
||||||
# define JEMALLOC_ALWAYS_INLINE JEMALLOC_ATTR(always_inline) static inline
|
# define JEMALLOC_ALWAYS_INLINE \
|
||||||
|
JEMALLOC_ATTR(always_inline) static inline
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
@@ -58,8 +59,9 @@
|
|||||||
# define JEMALLOC_DIAGNOSTIC_IGNORE_DEPRECATED
|
# define JEMALLOC_DIAGNOSTIC_IGNORE_DEPRECATED
|
||||||
# define JEMALLOC_DIAGNOSTIC_DISABLE_SPURIOUS
|
# define JEMALLOC_DIAGNOSTIC_DISABLE_SPURIOUS
|
||||||
/* #pragma GCC diagnostic first appeared in gcc 4.6. */
|
/* #pragma GCC diagnostic first appeared in gcc 4.6. */
|
||||||
#elif (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && \
|
#elif (defined(__GNUC__) \
|
||||||
(__GNUC_MINOR__ > 5)))) || defined(__clang__)
|
&& ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) \
|
||||||
|
|| defined(__clang__)
|
||||||
/*
|
/*
|
||||||
* The JEMALLOC_PRAGMA__ macro is an implementation detail of the GCC and Clang
|
* The JEMALLOC_PRAGMA__ macro is an implementation detail of the GCC and Clang
|
||||||
* diagnostic suppression macros and should not be used anywhere else.
|
* diagnostic suppression macros and should not be used anywhere else.
|
||||||
@@ -75,10 +77,11 @@
|
|||||||
* all clang versions up to version 7 (currently trunk, unreleased). This macro
|
* all clang versions up to version 7 (currently trunk, unreleased). This macro
|
||||||
* suppresses the warning for the affected compiler versions only.
|
* suppresses the warning for the affected compiler versions only.
|
||||||
*/
|
*/
|
||||||
# if ((defined(__GNUC__) && !defined(__clang__)) && (__GNUC__ < 5)) || \
|
# if ((defined(__GNUC__) && !defined(__clang__)) && (__GNUC__ < 5)) \
|
||||||
defined(__clang__)
|
|| defined(__clang__)
|
||||||
# define JEMALLOC_DIAGNOSTIC_IGNORE_MISSING_STRUCT_FIELD_INITIALIZERS \
|
# define JEMALLOC_DIAGNOSTIC_IGNORE_MISSING_STRUCT_FIELD_INITIALIZERS \
|
||||||
JEMALLOC_DIAGNOSTIC_IGNORE("-Wmissing-field-initializers")
|
JEMALLOC_DIAGNOSTIC_IGNORE( \
|
||||||
|
"-Wmissing-field-initializers")
|
||||||
# else
|
# else
|
||||||
# define JEMALLOC_DIAGNOSTIC_IGNORE_MISSING_STRUCT_FIELD_INITIALIZERS
|
# define JEMALLOC_DIAGNOSTIC_IGNORE_MISSING_STRUCT_FIELD_INITIALIZERS
|
||||||
# endif
|
# endif
|
||||||
|
|||||||
@@ -15,7 +15,8 @@
|
|||||||
|
|
||||||
#ifdef JEMALLOC_OVERRIDE_JEMALLOC_CONFIG_MALLOC_CONF
|
#ifdef JEMALLOC_OVERRIDE_JEMALLOC_CONFIG_MALLOC_CONF
|
||||||
# undef JEMALLOC_CONFIG_MALLOC_CONF
|
# undef JEMALLOC_CONFIG_MALLOC_CONF
|
||||||
#define JEMALLOC_CONFIG_MALLOC_CONF JEMALLOC_OVERRIDE_JEMALLOC_CONFIG_MALLOC_CONF
|
# define JEMALLOC_CONFIG_MALLOC_CONF \
|
||||||
|
JEMALLOC_OVERRIDE_JEMALLOC_CONFIG_MALLOC_CONF
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_OVERRIDES_H */
|
#endif /* JEMALLOC_INTERNAL_OVERRIDES_H */
|
||||||
|
|||||||
@@ -57,11 +57,11 @@ typedef enum malloc_init_e malloc_init_t;
|
|||||||
(ZU(1) << (flags & MALLOCX_LG_ALIGN_MASK))
|
(ZU(1) << (flags & MALLOCX_LG_ALIGN_MASK))
|
||||||
#define MALLOCX_ALIGN_GET(flags) \
|
#define MALLOCX_ALIGN_GET(flags) \
|
||||||
(MALLOCX_ALIGN_GET_SPECIFIED(flags) & (SIZE_T_MAX - 1))
|
(MALLOCX_ALIGN_GET_SPECIFIED(flags) & (SIZE_T_MAX - 1))
|
||||||
#define MALLOCX_ZERO_GET(flags) \
|
#define MALLOCX_ZERO_GET(flags) ((bool)(flags & MALLOCX_ZERO))
|
||||||
((bool)(flags & MALLOCX_ZERO))
|
|
||||||
|
|
||||||
#define MALLOCX_TCACHE_GET(flags) \
|
#define MALLOCX_TCACHE_GET(flags) \
|
||||||
(((unsigned)((flags & MALLOCX_TCACHE_MASK) >> MALLOCX_TCACHE_SHIFT)) - 2)
|
(((unsigned)((flags & MALLOCX_TCACHE_MASK) >> MALLOCX_TCACHE_SHIFT)) \
|
||||||
|
- 2)
|
||||||
#define MALLOCX_ARENA_GET(flags) \
|
#define MALLOCX_ARENA_GET(flags) \
|
||||||
(((unsigned)(((unsigned)flags) >> MALLOCX_ARENA_SHIFT)) - 1)
|
(((unsigned)(((unsigned)flags) >> MALLOCX_ARENA_SHIFT)) - 1)
|
||||||
|
|
||||||
@@ -72,15 +72,13 @@ typedef enum malloc_init_e malloc_init_t;
|
|||||||
#define LONG_MASK (LONG - 1)
|
#define LONG_MASK (LONG - 1)
|
||||||
|
|
||||||
/* Return the smallest long multiple that is >= a. */
|
/* Return the smallest long multiple that is >= a. */
|
||||||
#define LONG_CEILING(a) \
|
#define LONG_CEILING(a) (((a) + LONG_MASK) & ~LONG_MASK)
|
||||||
(((a) + LONG_MASK) & ~LONG_MASK)
|
|
||||||
|
|
||||||
#define SIZEOF_PTR (1U << LG_SIZEOF_PTR)
|
#define SIZEOF_PTR (1U << LG_SIZEOF_PTR)
|
||||||
#define PTR_MASK (SIZEOF_PTR - 1)
|
#define PTR_MASK (SIZEOF_PTR - 1)
|
||||||
|
|
||||||
/* Return the smallest (void *) multiple that is >= a. */
|
/* Return the smallest (void *) multiple that is >= a. */
|
||||||
#define PTR_CEILING(a) \
|
#define PTR_CEILING(a) (((a) + PTR_MASK) & ~PTR_MASK)
|
||||||
(((a) + PTR_MASK) & ~PTR_MASK)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Maximum size of L1 cache line. This is used to avoid cache line aliasing.
|
* Maximum size of L1 cache line. This is used to avoid cache line aliasing.
|
||||||
@@ -94,13 +92,12 @@ typedef enum malloc_init_e malloc_init_t;
|
|||||||
#define CACHELINE_MASK (CACHELINE - 1)
|
#define CACHELINE_MASK (CACHELINE - 1)
|
||||||
|
|
||||||
/* Return the smallest cacheline multiple that is >= s. */
|
/* Return the smallest cacheline multiple that is >= s. */
|
||||||
#define CACHELINE_CEILING(s) \
|
#define CACHELINE_CEILING(s) (((s) + CACHELINE_MASK) & ~CACHELINE_MASK)
|
||||||
(((s) + CACHELINE_MASK) & ~CACHELINE_MASK)
|
|
||||||
|
|
||||||
/* Return the nearest aligned address at or below a. */
|
/* Return the nearest aligned address at or below a. */
|
||||||
#define ALIGNMENT_ADDR2BASE(a, alignment) \
|
#define ALIGNMENT_ADDR2BASE(a, alignment) \
|
||||||
((void *)(((byte_t *)(a)) - (((uintptr_t)(a)) - \
|
((void *)(((byte_t *)(a)) \
|
||||||
((uintptr_t)(a) & ((~(alignment)) + 1)))))
|
- (((uintptr_t)(a)) - ((uintptr_t)(a) & ((~(alignment)) + 1)))))
|
||||||
|
|
||||||
/* Return the offset between a and the nearest aligned address at or below a. */
|
/* Return the offset between a and the nearest aligned address at or below a. */
|
||||||
#define ALIGNMENT_ADDR2OFFSET(a, alignment) \
|
#define ALIGNMENT_ADDR2OFFSET(a, alignment) \
|
||||||
@@ -120,8 +117,9 @@ typedef enum malloc_init_e malloc_init_t;
|
|||||||
* definition of `byte_t` for more details.
|
* definition of `byte_t` for more details.
|
||||||
*/
|
*/
|
||||||
#define ALIGNMENT_ADDR2CEILING(a, alignment) \
|
#define ALIGNMENT_ADDR2CEILING(a, alignment) \
|
||||||
((void *)(((byte_t *)(a)) + (((((uintptr_t)(a)) + \
|
((void *)(((byte_t *)(a)) \
|
||||||
(alignment - 1)) & ((~(alignment)) + 1)) - ((uintptr_t)(a)))))
|
+ (((((uintptr_t)(a)) + (alignment - 1)) & ((~(alignment)) + 1)) \
|
||||||
|
- ((uintptr_t)(a)))))
|
||||||
|
|
||||||
/* Declare a variable-length array. */
|
/* Declare a variable-length array. */
|
||||||
#if __STDC_VERSION__ < 199901L || defined(__STDC_NO_VLA__)
|
#if __STDC_VERSION__ < 199901L || defined(__STDC_NO_VLA__)
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
#include "jemalloc/internal/hook.h"
|
#include "jemalloc/internal/hook.h"
|
||||||
|
|
||||||
void *large_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero);
|
void *large_malloc(tsdn_t *tsdn, arena_t *arena, size_t usize, bool zero);
|
||||||
void *large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment,
|
void *large_palloc(
|
||||||
bool zero);
|
tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool zero);
|
||||||
bool large_ralloc_no_move(tsdn_t *tsdn, edata_t *edata, size_t usize_min,
|
bool large_ralloc_no_move(tsdn_t *tsdn, edata_t *edata, size_t usize_min,
|
||||||
size_t usize_max, bool zero);
|
size_t usize_max, bool zero);
|
||||||
void *large_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t usize,
|
void *large_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t usize,
|
||||||
@@ -18,8 +18,8 @@ void large_dalloc_prep_locked(tsdn_t *tsdn, edata_t *edata);
|
|||||||
void large_dalloc_finish(tsdn_t *tsdn, edata_t *edata);
|
void large_dalloc_finish(tsdn_t *tsdn, edata_t *edata);
|
||||||
void large_dalloc(tsdn_t *tsdn, edata_t *edata);
|
void large_dalloc(tsdn_t *tsdn, edata_t *edata);
|
||||||
size_t large_salloc(tsdn_t *tsdn, const edata_t *edata);
|
size_t large_salloc(tsdn_t *tsdn, const edata_t *edata);
|
||||||
void large_prof_info_get(tsd_t *tsd, edata_t *edata, prof_info_t *prof_info,
|
void large_prof_info_get(
|
||||||
bool reset_recent);
|
tsd_t *tsd, edata_t *edata, prof_info_t *prof_info, bool reset_recent);
|
||||||
void large_prof_tctx_reset(edata_t *edata);
|
void large_prof_tctx_reset(edata_t *edata);
|
||||||
void large_prof_info_set(edata_t *edata, prof_tctx_t *tctx, size_t size);
|
void large_prof_info_set(edata_t *edata, prof_tctx_t *tctx, size_t size);
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ struct locked_zu_s {
|
|||||||
# define LOCKEDINT_MTX(mtx) (&(mtx))
|
# define LOCKEDINT_MTX(mtx) (&(mtx))
|
||||||
# define LOCKEDINT_MTX_LOCK(tsdn, mu) malloc_mutex_lock(tsdn, &(mu))
|
# define LOCKEDINT_MTX_LOCK(tsdn, mu) malloc_mutex_lock(tsdn, &(mu))
|
||||||
# define LOCKEDINT_MTX_UNLOCK(tsdn, mu) malloc_mutex_unlock(tsdn, &(mu))
|
# define LOCKEDINT_MTX_UNLOCK(tsdn, mu) malloc_mutex_unlock(tsdn, &(mu))
|
||||||
# define LOCKEDINT_MTX_PREFORK(tsdn, mu) malloc_mutex_prefork(tsdn, &(mu))
|
# define LOCKEDINT_MTX_PREFORK(tsdn, mu) \
|
||||||
|
malloc_mutex_prefork(tsdn, &(mu))
|
||||||
# define LOCKEDINT_MTX_POSTFORK_PARENT(tsdn, mu) \
|
# define LOCKEDINT_MTX_POSTFORK_PARENT(tsdn, mu) \
|
||||||
malloc_mutex_postfork_parent(tsdn, &(mu))
|
malloc_mutex_postfork_parent(tsdn, &(mu))
|
||||||
# define LOCKEDINT_MTX_POSTFORK_CHILD(tsdn, mu) \
|
# define LOCKEDINT_MTX_POSTFORK_CHILD(tsdn, mu) \
|
||||||
@@ -70,8 +71,7 @@ locked_read_u64(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_u64_t *p) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
locked_inc_u64(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_u64_t *p,
|
locked_inc_u64(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_u64_t *p, uint64_t x) {
|
||||||
uint64_t x) {
|
|
||||||
LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx);
|
LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx);
|
||||||
#ifdef JEMALLOC_ATOMIC_U64
|
#ifdef JEMALLOC_ATOMIC_U64
|
||||||
atomic_fetch_add_u64(&p->val, x, ATOMIC_RELAXED);
|
atomic_fetch_add_u64(&p->val, x, ATOMIC_RELAXED);
|
||||||
@@ -81,8 +81,7 @@ locked_inc_u64(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_u64_t *p,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
locked_dec_u64(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_u64_t *p,
|
locked_dec_u64(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_u64_t *p, uint64_t x) {
|
||||||
uint64_t x) {
|
|
||||||
LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx);
|
LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx);
|
||||||
#ifdef JEMALLOC_ATOMIC_U64
|
#ifdef JEMALLOC_ATOMIC_U64
|
||||||
uint64_t r = atomic_fetch_sub_u64(&p->val, x, ATOMIC_RELAXED);
|
uint64_t r = atomic_fetch_sub_u64(&p->val, x, ATOMIC_RELAXED);
|
||||||
@@ -109,8 +108,8 @@ locked_inc_mod_u64(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_u64_t *p,
|
|||||||
if (overflow) {
|
if (overflow) {
|
||||||
after %= modulus;
|
after %= modulus;
|
||||||
}
|
}
|
||||||
} while (!atomic_compare_exchange_weak_u64(&p->val, &before, after,
|
} while (!atomic_compare_exchange_weak_u64(
|
||||||
ATOMIC_RELAXED, ATOMIC_RELAXED));
|
&p->val, &before, after, ATOMIC_RELAXED, ATOMIC_RELAXED));
|
||||||
#else
|
#else
|
||||||
before = p->val;
|
before = p->val;
|
||||||
after = before + x;
|
after = before + x;
|
||||||
@@ -167,8 +166,7 @@ locked_read_zu(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_zu_t *p) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
locked_inc_zu(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_zu_t *p,
|
locked_inc_zu(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_zu_t *p, size_t x) {
|
||||||
size_t x) {
|
|
||||||
LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx);
|
LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx);
|
||||||
#ifdef JEMALLOC_ATOMIC_U64
|
#ifdef JEMALLOC_ATOMIC_U64
|
||||||
atomic_fetch_add_zu(&p->val, x, ATOMIC_RELAXED);
|
atomic_fetch_add_zu(&p->val, x, ATOMIC_RELAXED);
|
||||||
@@ -179,8 +177,7 @@ locked_inc_zu(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_zu_t *p,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
locked_dec_zu(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_zu_t *p,
|
locked_dec_zu(tsdn_t *tsdn, malloc_mutex_t *mtx, locked_zu_t *p, size_t x) {
|
||||||
size_t x) {
|
|
||||||
LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx);
|
LOCKEDINT_MTX_ASSERT_INTERNAL(tsdn, mtx);
|
||||||
#ifdef JEMALLOC_ATOMIC_U64
|
#ifdef JEMALLOC_ATOMIC_U64
|
||||||
size_t r = atomic_fetch_sub_zu(&p->val, x, ATOMIC_RELAXED);
|
size_t r = atomic_fetch_sub_zu(&p->val, x, ATOMIC_RELAXED);
|
||||||
|
|||||||
@@ -53,7 +53,8 @@ struct log_var_s {
|
|||||||
#define LOG_INITIALIZED_NOT_ENABLED 1U
|
#define LOG_INITIALIZED_NOT_ENABLED 1U
|
||||||
#define LOG_ENABLED 2U
|
#define LOG_ENABLED 2U
|
||||||
|
|
||||||
#define LOG_VAR_INIT(name_str) {ATOMIC_INIT(LOG_NOT_INITIALIZED), name_str}
|
#define LOG_VAR_INIT(name_str) \
|
||||||
|
{ ATOMIC_INIT(LOG_NOT_INITIALIZED), name_str }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the value we should assume for state (which is not necessarily
|
* Returns the value we should assume for state (which is not necessarily
|
||||||
@@ -65,8 +66,8 @@ unsigned log_var_update_state(log_var_t *log_var);
|
|||||||
/* We factor out the metadata management to allow us to test more easily. */
|
/* We factor out the metadata management to allow us to test more easily. */
|
||||||
#define log_do_begin(log_var) \
|
#define log_do_begin(log_var) \
|
||||||
if (config_log) { \
|
if (config_log) { \
|
||||||
unsigned log_state = atomic_load_u(&(log_var).state, \
|
unsigned log_state = atomic_load_u( \
|
||||||
ATOMIC_RELAXED); \
|
&(log_var).state, ATOMIC_RELAXED); \
|
||||||
if (unlikely(log_state == LOG_NOT_INITIALIZED)) { \
|
if (unlikely(log_state == LOG_NOT_INITIALIZED)) { \
|
||||||
log_state = log_var_update_state(&(log_var)); \
|
log_state = log_var_update_state(&(log_var)); \
|
||||||
assert(log_state != LOG_NOT_INITIALIZED); \
|
assert(log_state != LOG_NOT_INITIALIZED); \
|
||||||
@@ -95,9 +96,10 @@ log_impl_varargs(const char *name, ...) {
|
|||||||
const char *format = va_arg(ap, const char *);
|
const char *format = va_arg(ap, const char *);
|
||||||
size_t dst_offset = 0;
|
size_t dst_offset = 0;
|
||||||
dst_offset += malloc_snprintf(buf, JEMALLOC_LOG_BUFSIZE, "%s: ", name);
|
dst_offset += malloc_snprintf(buf, JEMALLOC_LOG_BUFSIZE, "%s: ", name);
|
||||||
dst_offset += malloc_vsnprintf(buf + dst_offset,
|
dst_offset += malloc_vsnprintf(
|
||||||
JEMALLOC_LOG_BUFSIZE - dst_offset, format, ap);
|
buf + dst_offset, JEMALLOC_LOG_BUFSIZE - dst_offset, format, ap);
|
||||||
malloc_snprintf(buf + dst_offset, JEMALLOC_LOG_BUFSIZE - dst_offset, "\n");
|
malloc_snprintf(
|
||||||
|
buf + dst_offset, JEMALLOC_LOG_BUFSIZE - dst_offset, "\n");
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
malloc_write(buf);
|
malloc_write(buf);
|
||||||
|
|||||||
@@ -45,24 +45,23 @@
|
|||||||
|
|
||||||
write_cb_t wrtmessage;
|
write_cb_t wrtmessage;
|
||||||
int buferror(int err, char *buf, size_t buflen);
|
int buferror(int err, char *buf, size_t buflen);
|
||||||
uintmax_t malloc_strtoumax(const char *restrict nptr, char **restrict endptr,
|
uintmax_t malloc_strtoumax(
|
||||||
int base);
|
const char *restrict nptr, char **restrict endptr, int base);
|
||||||
void malloc_write(const char *s);
|
void malloc_write(const char *s);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* malloc_vsnprintf() supports a subset of snprintf(3) that avoids floating
|
* malloc_vsnprintf() supports a subset of snprintf(3) that avoids floating
|
||||||
* point math.
|
* point math.
|
||||||
*/
|
*/
|
||||||
size_t malloc_vsnprintf(char *str, size_t size, const char *format,
|
size_t malloc_vsnprintf(char *str, size_t size, const char *format, va_list ap);
|
||||||
va_list ap);
|
|
||||||
size_t malloc_snprintf(char *str, size_t size, const char *format, ...)
|
size_t malloc_snprintf(char *str, size_t size, const char *format, ...)
|
||||||
JEMALLOC_FORMAT_PRINTF(3, 4);
|
JEMALLOC_FORMAT_PRINTF(3, 4);
|
||||||
/*
|
/*
|
||||||
* The caller can set write_cb to null to choose to print with the
|
* The caller can set write_cb to null to choose to print with the
|
||||||
* je_malloc_message hook.
|
* je_malloc_message hook.
|
||||||
*/
|
*/
|
||||||
void malloc_vcprintf(write_cb_t *write_cb, void *cbopaque, const char *format,
|
void malloc_vcprintf(
|
||||||
va_list ap);
|
write_cb_t *write_cb, void *cbopaque, const char *format, va_list ap);
|
||||||
void malloc_cprintf(write_cb_t *write_cb, void *cbopaque, const char *format,
|
void malloc_cprintf(write_cb_t *write_cb, void *cbopaque, const char *format,
|
||||||
...) JEMALLOC_FORMAT_PRINTF(3, 4);
|
...) JEMALLOC_FORMAT_PRINTF(3, 4);
|
||||||
void malloc_printf(const char *format, ...) JEMALLOC_FORMAT_PRINTF(1, 2);
|
void malloc_printf(const char *format, ...) JEMALLOC_FORMAT_PRINTF(1, 2);
|
||||||
@@ -122,8 +121,8 @@ static inline ssize_t
|
|||||||
malloc_read_fd(int fd, void *buf, size_t count) {
|
malloc_read_fd(int fd, void *buf, size_t count) {
|
||||||
size_t bytes_read = 0;
|
size_t bytes_read = 0;
|
||||||
do {
|
do {
|
||||||
ssize_t result = malloc_read_fd_syscall(fd,
|
ssize_t result = malloc_read_fd_syscall(
|
||||||
&((byte_t *)buf)[bytes_read], count - bytes_read);
|
fd, &((byte_t *)buf)[bytes_read], count - bytes_read);
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
return result;
|
return result;
|
||||||
} else if (result == 0) {
|
} else if (result == 0) {
|
||||||
@@ -134,7 +133,8 @@ malloc_read_fd(int fd, void *buf, size_t count) {
|
|||||||
return bytes_read;
|
return bytes_read;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int malloc_open(const char *path, int flags) {
|
static inline int
|
||||||
|
malloc_open(const char *path, int flags) {
|
||||||
int fd;
|
int fd;
|
||||||
#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_open)
|
#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_open)
|
||||||
fd = (int)syscall(SYS_open, path, flags);
|
fd = (int)syscall(SYS_open, path, flags);
|
||||||
@@ -146,7 +146,8 @@ static inline int malloc_open(const char *path, int flags) {
|
|||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int malloc_close(int fd) {
|
static inline int
|
||||||
|
malloc_close(int fd) {
|
||||||
#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_close)
|
#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_close)
|
||||||
return (int)syscall(SYS_close, fd);
|
return (int)syscall(SYS_close, fd);
|
||||||
#else
|
#else
|
||||||
@@ -154,7 +155,8 @@ static inline int malloc_close(int fd) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline off_t malloc_lseek(int fd, off_t offset, int whence) {
|
static inline off_t
|
||||||
|
malloc_lseek(int fd, off_t offset, int whence) {
|
||||||
#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_lseek)
|
#if defined(JEMALLOC_USE_SYSCALL) && defined(SYS_lseek)
|
||||||
return (off_t)syscall(SYS_lseek, fd, offset, whence);
|
return (off_t)syscall(SYS_lseek, fd, offset, whence);
|
||||||
#else
|
#else
|
||||||
|
|||||||
@@ -76,12 +76,15 @@ struct malloc_mutex_s {
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# if _WIN32_WINNT >= 0x0600
|
# if _WIN32_WINNT >= 0x0600
|
||||||
# define MALLOC_MUTEX_LOCK(m) AcquireSRWLockExclusive(&(m)->lock)
|
# define MALLOC_MUTEX_LOCK(m) AcquireSRWLockExclusive(&(m)->lock)
|
||||||
# define MALLOC_MUTEX_UNLOCK(m) ReleaseSRWLockExclusive(&(m)->lock)
|
# define MALLOC_MUTEX_UNLOCK(m) \
|
||||||
# define MALLOC_MUTEX_TRYLOCK(m) (!TryAcquireSRWLockExclusive(&(m)->lock))
|
ReleaseSRWLockExclusive(&(m)->lock)
|
||||||
|
# define MALLOC_MUTEX_TRYLOCK(m) \
|
||||||
|
(!TryAcquireSRWLockExclusive(&(m)->lock))
|
||||||
# else
|
# else
|
||||||
# define MALLOC_MUTEX_LOCK(m) EnterCriticalSection(&(m)->lock)
|
# define MALLOC_MUTEX_LOCK(m) EnterCriticalSection(&(m)->lock)
|
||||||
# define MALLOC_MUTEX_UNLOCK(m) LeaveCriticalSection(&(m)->lock)
|
# define MALLOC_MUTEX_UNLOCK(m) LeaveCriticalSection(&(m)->lock)
|
||||||
# define MALLOC_MUTEX_TRYLOCK(m) (!TryEnterCriticalSection(&(m)->lock))
|
# define MALLOC_MUTEX_TRYLOCK(m) \
|
||||||
|
(!TryEnterCriticalSection(&(m)->lock))
|
||||||
# endif
|
# endif
|
||||||
#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
|
#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
|
||||||
# define MALLOC_MUTEX_LOCK(m) os_unfair_lock_lock(&(m)->lock)
|
# define MALLOC_MUTEX_LOCK(m) os_unfair_lock_lock(&(m)->lock)
|
||||||
@@ -94,42 +97,75 @@ struct malloc_mutex_s {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LOCK_PROF_DATA_INITIALIZER \
|
#define LOCK_PROF_DATA_INITIALIZER \
|
||||||
{NSTIME_ZERO_INITIALIZER, NSTIME_ZERO_INITIALIZER, 0, 0, 0, \
|
{ \
|
||||||
ATOMIC_INIT(0), 0, NULL, 0}
|
NSTIME_ZERO_INITIALIZER, NSTIME_ZERO_INITIALIZER, 0, 0, 0, \
|
||||||
|
ATOMIC_INIT(0), 0, NULL, 0 \
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# define MALLOC_MUTEX_INITIALIZER
|
# define MALLOC_MUTEX_INITIALIZER
|
||||||
#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
|
#elif (defined(JEMALLOC_OS_UNFAIR_LOCK))
|
||||||
# if defined(JEMALLOC_DEBUG)
|
# if defined(JEMALLOC_DEBUG)
|
||||||
# define MALLOC_MUTEX_INITIALIZER \
|
# define MALLOC_MUTEX_INITIALIZER \
|
||||||
{{{LOCK_PROF_DATA_INITIALIZER, ATOMIC_INIT(false), OS_UNFAIR_LOCK_INIT}}, \
|
{ \
|
||||||
WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT), 0}
|
{{LOCK_PROF_DATA_INITIALIZER, \
|
||||||
|
ATOMIC_INIT(false), OS_UNFAIR_LOCK_INIT}}, \
|
||||||
|
WITNESS_INITIALIZER( \
|
||||||
|
"mutex", WITNESS_RANK_OMIT), \
|
||||||
|
0 \
|
||||||
|
}
|
||||||
# else
|
# else
|
||||||
# define MALLOC_MUTEX_INITIALIZER \
|
# define MALLOC_MUTEX_INITIALIZER \
|
||||||
{{{LOCK_PROF_DATA_INITIALIZER, ATOMIC_INIT(false), OS_UNFAIR_LOCK_INIT}}, \
|
{ \
|
||||||
WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)}
|
{{LOCK_PROF_DATA_INITIALIZER, \
|
||||||
|
ATOMIC_INIT(false), OS_UNFAIR_LOCK_INIT}}, \
|
||||||
|
WITNESS_INITIALIZER( \
|
||||||
|
"mutex", WITNESS_RANK_OMIT) \
|
||||||
|
}
|
||||||
# endif
|
# endif
|
||||||
#elif (defined(JEMALLOC_MUTEX_INIT_CB))
|
#elif (defined(JEMALLOC_MUTEX_INIT_CB))
|
||||||
# if (defined(JEMALLOC_DEBUG))
|
# if (defined(JEMALLOC_DEBUG))
|
||||||
# define MALLOC_MUTEX_INITIALIZER \
|
# define MALLOC_MUTEX_INITIALIZER \
|
||||||
{{{LOCK_PROF_DATA_INITIALIZER, ATOMIC_INIT(false), PTHREAD_MUTEX_INITIALIZER, NULL}}, \
|
{ \
|
||||||
WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT), 0}
|
{{LOCK_PROF_DATA_INITIALIZER, \
|
||||||
|
ATOMIC_INIT(false), \
|
||||||
|
PTHREAD_MUTEX_INITIALIZER, NULL}}, \
|
||||||
|
WITNESS_INITIALIZER( \
|
||||||
|
"mutex", WITNESS_RANK_OMIT), \
|
||||||
|
0 \
|
||||||
|
}
|
||||||
# else
|
# else
|
||||||
# define MALLOC_MUTEX_INITIALIZER \
|
# define MALLOC_MUTEX_INITIALIZER \
|
||||||
{{{LOCK_PROF_DATA_INITIALIZER, ATOMIC_INIT(false), PTHREAD_MUTEX_INITIALIZER, NULL}}, \
|
{ \
|
||||||
WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)}
|
{{LOCK_PROF_DATA_INITIALIZER, \
|
||||||
|
ATOMIC_INIT(false), \
|
||||||
|
PTHREAD_MUTEX_INITIALIZER, NULL}}, \
|
||||||
|
WITNESS_INITIALIZER( \
|
||||||
|
"mutex", WITNESS_RANK_OMIT) \
|
||||||
|
}
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
# define MALLOC_MUTEX_TYPE PTHREAD_MUTEX_DEFAULT
|
# define MALLOC_MUTEX_TYPE PTHREAD_MUTEX_DEFAULT
|
||||||
# if defined(JEMALLOC_DEBUG)
|
# if defined(JEMALLOC_DEBUG)
|
||||||
# define MALLOC_MUTEX_INITIALIZER \
|
# define MALLOC_MUTEX_INITIALIZER \
|
||||||
{{{LOCK_PROF_DATA_INITIALIZER, ATOMIC_INIT(false), PTHREAD_MUTEX_INITIALIZER}}, \
|
{ \
|
||||||
WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT), 0}
|
{{LOCK_PROF_DATA_INITIALIZER, \
|
||||||
|
ATOMIC_INIT(false), \
|
||||||
|
PTHREAD_MUTEX_INITIALIZER}}, \
|
||||||
|
WITNESS_INITIALIZER( \
|
||||||
|
"mutex", WITNESS_RANK_OMIT), \
|
||||||
|
0 \
|
||||||
|
}
|
||||||
# else
|
# else
|
||||||
# define MALLOC_MUTEX_INITIALIZER \
|
# define MALLOC_MUTEX_INITIALIZER \
|
||||||
{{{LOCK_PROF_DATA_INITIALIZER, ATOMIC_INIT(false), PTHREAD_MUTEX_INITIALIZER}}, \
|
{ \
|
||||||
WITNESS_INITIALIZER("mutex", WITNESS_RANK_OMIT)}
|
{{LOCK_PROF_DATA_INITIALIZER, \
|
||||||
|
ATOMIC_INIT(false), \
|
||||||
|
PTHREAD_MUTEX_INITIALIZER}}, \
|
||||||
|
WITNESS_INITIALIZER( \
|
||||||
|
"mutex", WITNESS_RANK_OMIT) \
|
||||||
|
}
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -214,12 +250,12 @@ malloc_mutex_prof_merge(mutex_prof_data_t *sum, mutex_prof_data_t *data) {
|
|||||||
if (sum->max_n_thds < data->max_n_thds) {
|
if (sum->max_n_thds < data->max_n_thds) {
|
||||||
sum->max_n_thds = data->max_n_thds;
|
sum->max_n_thds = data->max_n_thds;
|
||||||
}
|
}
|
||||||
uint32_t cur_n_waiting_thds = atomic_load_u32(&sum->n_waiting_thds,
|
uint32_t cur_n_waiting_thds = atomic_load_u32(
|
||||||
ATOMIC_RELAXED);
|
&sum->n_waiting_thds, ATOMIC_RELAXED);
|
||||||
uint32_t new_n_waiting_thds = cur_n_waiting_thds + atomic_load_u32(
|
uint32_t new_n_waiting_thds = cur_n_waiting_thds
|
||||||
&data->n_waiting_thds, ATOMIC_RELAXED);
|
+ atomic_load_u32(&data->n_waiting_thds, ATOMIC_RELAXED);
|
||||||
atomic_store_u32(&sum->n_waiting_thds, new_n_waiting_thds,
|
atomic_store_u32(
|
||||||
ATOMIC_RELAXED);
|
&sum->n_waiting_thds, new_n_waiting_thds, ATOMIC_RELAXED);
|
||||||
sum->n_owner_switches += data->n_owner_switches;
|
sum->n_owner_switches += data->n_owner_switches;
|
||||||
sum->n_lock_ops += data->n_lock_ops;
|
sum->n_lock_ops += data->n_lock_ops;
|
||||||
}
|
}
|
||||||
@@ -274,16 +310,16 @@ malloc_mutex_prof_copy(mutex_prof_data_t *dst, mutex_prof_data_t *source) {
|
|||||||
|
|
||||||
/* Copy the prof data from mutex for processing. */
|
/* Copy the prof data from mutex for processing. */
|
||||||
static inline void
|
static inline void
|
||||||
malloc_mutex_prof_read(tsdn_t *tsdn, mutex_prof_data_t *data,
|
malloc_mutex_prof_read(
|
||||||
malloc_mutex_t *mutex) {
|
tsdn_t *tsdn, mutex_prof_data_t *data, malloc_mutex_t *mutex) {
|
||||||
/* Can only read holding the mutex. */
|
/* Can only read holding the mutex. */
|
||||||
malloc_mutex_assert_owner(tsdn, mutex);
|
malloc_mutex_assert_owner(tsdn, mutex);
|
||||||
malloc_mutex_prof_copy(data, &mutex->prof_data);
|
malloc_mutex_prof_copy(data, &mutex->prof_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
malloc_mutex_prof_accum(tsdn_t *tsdn, mutex_prof_data_t *data,
|
malloc_mutex_prof_accum(
|
||||||
malloc_mutex_t *mutex) {
|
tsdn_t *tsdn, mutex_prof_data_t *data, malloc_mutex_t *mutex) {
|
||||||
mutex_prof_data_t *source = &mutex->prof_data;
|
mutex_prof_data_t *source = &mutex->prof_data;
|
||||||
/* Can only read holding the mutex. */
|
/* Can only read holding the mutex. */
|
||||||
malloc_mutex_assert_owner(tsdn, mutex);
|
malloc_mutex_assert_owner(tsdn, mutex);
|
||||||
@@ -305,8 +341,8 @@ malloc_mutex_prof_accum(tsdn_t *tsdn, mutex_prof_data_t *data,
|
|||||||
|
|
||||||
/* Compare the prof data and update to the maximum. */
|
/* Compare the prof data and update to the maximum. */
|
||||||
static inline void
|
static inline void
|
||||||
malloc_mutex_prof_max_update(tsdn_t *tsdn, mutex_prof_data_t *data,
|
malloc_mutex_prof_max_update(
|
||||||
malloc_mutex_t *mutex) {
|
tsdn_t *tsdn, mutex_prof_data_t *data, malloc_mutex_t *mutex) {
|
||||||
mutex_prof_data_t *source = &mutex->prof_data;
|
mutex_prof_data_t *source = &mutex->prof_data;
|
||||||
/* Can only read holding the mutex. */
|
/* Can only read holding the mutex. */
|
||||||
malloc_mutex_assert_owner(tsdn, mutex);
|
malloc_mutex_assert_owner(tsdn, mutex);
|
||||||
|
|||||||
@@ -56,7 +56,8 @@ typedef enum {
|
|||||||
OP(num_wait_ps, uint64_t, "(#/sec)", true, num_wait) \
|
OP(num_wait_ps, uint64_t, "(#/sec)", true, num_wait) \
|
||||||
OP(num_spin_acq, uint64_t, "n_spin_acq", false, num_spin_acq) \
|
OP(num_spin_acq, uint64_t, "n_spin_acq", false, num_spin_acq) \
|
||||||
OP(num_spin_acq_ps, uint64_t, "(#/sec)", true, num_spin_acq) \
|
OP(num_spin_acq_ps, uint64_t, "(#/sec)", true, num_spin_acq) \
|
||||||
OP(num_owner_switch, uint64_t, "n_owner_switch", false, num_owner_switch) \
|
OP(num_owner_switch, uint64_t, "n_owner_switch", false, \
|
||||||
|
num_owner_switch) \
|
||||||
OP(num_owner_switch_ps, uint64_t, "(#/sec)", true, num_owner_switch) \
|
OP(num_owner_switch_ps, uint64_t, "(#/sec)", true, num_owner_switch) \
|
||||||
OP(total_wait_time, uint64_t, "total_wait_ns", false, total_wait_time) \
|
OP(total_wait_time, uint64_t, "total_wait_ns", false, total_wait_time) \
|
||||||
OP(total_wait_time_ps, uint64_t, "(#/sec)", true, total_wait_time) \
|
OP(total_wait_time_ps, uint64_t, "(#/sec)", true, total_wait_time) \
|
||||||
@@ -73,8 +74,7 @@ typedef enum {
|
|||||||
|
|
||||||
#define COUNTER_ENUM(counter_list, t) \
|
#define COUNTER_ENUM(counter_list, t) \
|
||||||
typedef enum { \
|
typedef enum { \
|
||||||
counter_list \
|
counter_list mutex_prof_num_##t##_counters \
|
||||||
mutex_prof_num_##t##_counters \
|
|
||||||
} mutex_prof_##t##_counter_ind_t;
|
} mutex_prof_##t##_counter_ind_t;
|
||||||
|
|
||||||
COUNTER_ENUM(MUTEX_PROF_UINT64_COUNTERS, uint64_t)
|
COUNTER_ENUM(MUTEX_PROF_UINT64_COUNTERS, uint64_t)
|
||||||
|
|||||||
@@ -9,9 +9,11 @@
|
|||||||
|
|
||||||
#define NSTIME_MAGIC ((uint32_t)0xb8a9ce37)
|
#define NSTIME_MAGIC ((uint32_t)0xb8a9ce37)
|
||||||
#ifdef JEMALLOC_DEBUG
|
#ifdef JEMALLOC_DEBUG
|
||||||
# define NSTIME_ZERO_INITIALIZER {0, NSTIME_MAGIC}
|
# define NSTIME_ZERO_INITIALIZER \
|
||||||
|
{ 0, NSTIME_MAGIC }
|
||||||
#else
|
#else
|
||||||
# define NSTIME_ZERO_INITIALIZER {0}
|
# define NSTIME_ZERO_INITIALIZER \
|
||||||
|
{ 0 }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -53,10 +55,7 @@ extern nstime_prof_update_t *JET_MUTABLE nstime_prof_update;
|
|||||||
void nstime_init_update(nstime_t *time);
|
void nstime_init_update(nstime_t *time);
|
||||||
void nstime_prof_init_update(nstime_t *time);
|
void nstime_prof_init_update(nstime_t *time);
|
||||||
|
|
||||||
enum prof_time_res_e {
|
enum prof_time_res_e { prof_time_res_default = 0, prof_time_res_high = 1 };
|
||||||
prof_time_res_default = 0,
|
|
||||||
prof_time_res_high = 1
|
|
||||||
};
|
|
||||||
typedef enum prof_time_res_e prof_time_res_t;
|
typedef enum prof_time_res_e prof_time_res_t;
|
||||||
|
|
||||||
extern prof_time_res_t opt_prof_time_res;
|
extern prof_time_res_t opt_prof_time_res;
|
||||||
|
|||||||
@@ -121,8 +121,8 @@ struct pa_shard_s {
|
|||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
pa_shard_dont_decay_muzzy(pa_shard_t *shard) {
|
pa_shard_dont_decay_muzzy(pa_shard_t *shard) {
|
||||||
return ecache_npages_get(&shard->pac.ecache_muzzy) == 0 &&
|
return ecache_npages_get(&shard->pac.ecache_muzzy) == 0
|
||||||
pac_decay_ms_get(&shard->pac, extent_state_muzzy) <= 0;
|
&& pac_decay_ms_get(&shard->pac, extent_state_muzzy) <= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline ehooks_t *
|
static inline ehooks_t *
|
||||||
@@ -199,8 +199,8 @@ ssize_t pa_decay_ms_get(pa_shard_t *shard, extent_state_t state);
|
|||||||
* though, the arena, background thread, and PAC modules are tightly interwoven
|
* though, the arena, background thread, and PAC modules are tightly interwoven
|
||||||
* in a way that's tricky to extricate, so we only do the HPA-specific parts.
|
* in a way that's tricky to extricate, so we only do the HPA-specific parts.
|
||||||
*/
|
*/
|
||||||
void pa_shard_set_deferral_allowed(tsdn_t *tsdn, pa_shard_t *shard,
|
void pa_shard_set_deferral_allowed(
|
||||||
bool deferral_allowed);
|
tsdn_t *tsdn, pa_shard_t *shard, bool deferral_allowed);
|
||||||
void pa_shard_do_deferred_work(tsdn_t *tsdn, pa_shard_t *shard);
|
void pa_shard_do_deferred_work(tsdn_t *tsdn, pa_shard_t *shard);
|
||||||
void pa_shard_try_deferred_work(tsdn_t *tsdn, pa_shard_t *shard);
|
void pa_shard_try_deferred_work(tsdn_t *tsdn, pa_shard_t *shard);
|
||||||
uint64_t pa_shard_time_until_deferred_work(tsdn_t *tsdn, pa_shard_t *shard);
|
uint64_t pa_shard_time_until_deferred_work(tsdn_t *tsdn, pa_shard_t *shard);
|
||||||
@@ -228,8 +228,8 @@ size_t pa_shard_nactive(pa_shard_t *shard);
|
|||||||
size_t pa_shard_ndirty(pa_shard_t *shard);
|
size_t pa_shard_ndirty(pa_shard_t *shard);
|
||||||
size_t pa_shard_nmuzzy(pa_shard_t *shard);
|
size_t pa_shard_nmuzzy(pa_shard_t *shard);
|
||||||
|
|
||||||
void pa_shard_basic_stats_merge(pa_shard_t *shard, size_t *nactive,
|
void pa_shard_basic_stats_merge(
|
||||||
size_t *ndirty, size_t *nmuzzy);
|
pa_shard_t *shard, size_t *nactive, size_t *ndirty, size_t *nmuzzy);
|
||||||
|
|
||||||
void pa_shard_stats_merge(tsdn_t *tsdn, pa_shard_t *shard,
|
void pa_shard_stats_merge(tsdn_t *tsdn, pa_shard_t *shard,
|
||||||
pa_shard_stats_t *pa_shard_stats_out, pac_estats_t *estats_out,
|
pa_shard_stats_t *pa_shard_stats_out, pac_estats_t *estats_out,
|
||||||
|
|||||||
@@ -195,8 +195,8 @@ bool pac_maybe_decay_purge(tsdn_t *tsdn, pac_t *pac, decay_t *decay,
|
|||||||
*
|
*
|
||||||
* Returns true on error (if the new limit is not valid).
|
* Returns true on error (if the new limit is not valid).
|
||||||
*/
|
*/
|
||||||
bool pac_retain_grow_limit_get_set(tsdn_t *tsdn, pac_t *pac, size_t *old_limit,
|
bool pac_retain_grow_limit_get_set(
|
||||||
size_t *new_limit);
|
tsdn_t *tsdn, pac_t *pac, size_t *old_limit, size_t *new_limit);
|
||||||
|
|
||||||
bool pac_decay_ms_set(tsdn_t *tsdn, pac_t *pac, extent_state_t state,
|
bool pac_decay_ms_set(tsdn_t *tsdn, pac_t *pac, extent_state_t state,
|
||||||
ssize_t decay_ms, pac_purge_eagerness_t eagerness);
|
ssize_t decay_ms, pac_purge_eagerness_t eagerness);
|
||||||
|
|||||||
@@ -14,14 +14,11 @@ extern size_t os_page;
|
|||||||
#define PAGE ((size_t)(1U << LG_PAGE))
|
#define PAGE ((size_t)(1U << LG_PAGE))
|
||||||
#define PAGE_MASK ((size_t)(PAGE - 1))
|
#define PAGE_MASK ((size_t)(PAGE - 1))
|
||||||
/* Return the page base address for the page containing address a. */
|
/* Return the page base address for the page containing address a. */
|
||||||
#define PAGE_ADDR2BASE(a) \
|
#define PAGE_ADDR2BASE(a) ALIGNMENT_ADDR2BASE(a, PAGE)
|
||||||
ALIGNMENT_ADDR2BASE(a, PAGE)
|
|
||||||
/* Return the smallest pagesize multiple that is >= s. */
|
/* Return the smallest pagesize multiple that is >= s. */
|
||||||
#define PAGE_CEILING(s) \
|
#define PAGE_CEILING(s) (((s) + PAGE_MASK) & ~PAGE_MASK)
|
||||||
(((s) + PAGE_MASK) & ~PAGE_MASK)
|
|
||||||
/* Return the largest pagesize multiple that is <=s. */
|
/* Return the largest pagesize multiple that is <=s. */
|
||||||
#define PAGE_FLOOR(s) \
|
#define PAGE_FLOOR(s) ((s) & ~PAGE_MASK)
|
||||||
((s) & ~PAGE_MASK)
|
|
||||||
|
|
||||||
/* Huge page size. LG_HUGEPAGE is determined by the configure script. */
|
/* Huge page size. LG_HUGEPAGE is determined by the configure script. */
|
||||||
#define HUGEPAGE ((size_t)(1U << LG_HUGEPAGE))
|
#define HUGEPAGE ((size_t)(1U << LG_HUGEPAGE))
|
||||||
@@ -49,11 +46,9 @@ extern size_t os_page;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Return the huge page base address for the huge page containing address a. */
|
/* Return the huge page base address for the huge page containing address a. */
|
||||||
#define HUGEPAGE_ADDR2BASE(a) \
|
#define HUGEPAGE_ADDR2BASE(a) ALIGNMENT_ADDR2BASE(a, HUGEPAGE)
|
||||||
ALIGNMENT_ADDR2BASE(a, HUGEPAGE)
|
|
||||||
/* Return the smallest pagesize multiple that is >= s. */
|
/* Return the smallest pagesize multiple that is >= s. */
|
||||||
#define HUGEPAGE_CEILING(s) \
|
#define HUGEPAGE_CEILING(s) (((s) + HUGEPAGE_MASK) & ~HUGEPAGE_MASK)
|
||||||
(((s) + HUGEPAGE_MASK) & ~HUGEPAGE_MASK)
|
|
||||||
|
|
||||||
/* PAGES_CAN_PURGE_LAZY is defined if lazy purging is supported. */
|
/* PAGES_CAN_PURGE_LAZY is defined if lazy purging is supported. */
|
||||||
#if defined(_WIN32) || defined(JEMALLOC_PURGE_MADVISE_FREE)
|
#if defined(_WIN32) || defined(JEMALLOC_PURGE_MADVISE_FREE)
|
||||||
@@ -68,9 +63,10 @@ extern size_t os_page;
|
|||||||
* next step after purging on Windows anyway, there's no point in adding such
|
* next step after purging on Windows anyway, there's no point in adding such
|
||||||
* complexity.
|
* complexity.
|
||||||
*/
|
*/
|
||||||
#if !defined(_WIN32) && ((defined(JEMALLOC_PURGE_MADVISE_DONTNEED) && \
|
#if !defined(_WIN32) \
|
||||||
defined(JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS)) || \
|
&& ((defined(JEMALLOC_PURGE_MADVISE_DONTNEED) \
|
||||||
defined(JEMALLOC_MAPS_COALESCE))
|
&& defined(JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS)) \
|
||||||
|
|| defined(JEMALLOC_MAPS_COALESCE))
|
||||||
# define PAGES_CAN_PURGE_FORCED
|
# define PAGES_CAN_PURGE_FORCED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -41,9 +41,8 @@ struct pai_s {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static inline edata_t *
|
static inline edata_t *
|
||||||
pai_alloc(tsdn_t *tsdn, pai_t *self, size_t size, size_t alignment,
|
pai_alloc(tsdn_t *tsdn, pai_t *self, size_t size, size_t alignment, bool zero,
|
||||||
bool zero, bool guarded, bool frequent_reuse,
|
bool guarded, bool frequent_reuse, bool *deferred_work_generated) {
|
||||||
bool *deferred_work_generated) {
|
|
||||||
return self->alloc(tsdn, self, size, alignment, zero, guarded,
|
return self->alloc(tsdn, self, size, alignment, zero, guarded,
|
||||||
frequent_reuse, deferred_work_generated);
|
frequent_reuse, deferred_work_generated);
|
||||||
}
|
}
|
||||||
@@ -66,13 +65,13 @@ pai_expand(tsdn_t *tsdn, pai_t *self, edata_t *edata, size_t old_size,
|
|||||||
static inline bool
|
static inline bool
|
||||||
pai_shrink(tsdn_t *tsdn, pai_t *self, edata_t *edata, size_t old_size,
|
pai_shrink(tsdn_t *tsdn, pai_t *self, edata_t *edata, size_t old_size,
|
||||||
size_t new_size, bool *deferred_work_generated) {
|
size_t new_size, bool *deferred_work_generated) {
|
||||||
return self->shrink(tsdn, self, edata, old_size, new_size,
|
return self->shrink(
|
||||||
deferred_work_generated);
|
tsdn, self, edata, old_size, new_size, deferred_work_generated);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
pai_dalloc(tsdn_t *tsdn, pai_t *self, edata_t *edata,
|
pai_dalloc(
|
||||||
bool *deferred_work_generated) {
|
tsdn_t *tsdn, pai_t *self, edata_t *edata, bool *deferred_work_generated) {
|
||||||
self->dalloc(tsdn, self, edata, deferred_work_generated);
|
self->dalloc(tsdn, self, edata, deferred_work_generated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ struct peak_s {
|
|||||||
uint64_t adjustment;
|
uint64_t adjustment;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PEAK_INITIALIZER {0, 0}
|
#define PEAK_INITIALIZER \
|
||||||
|
{ 0, 0 }
|
||||||
|
|
||||||
static inline uint64_t
|
static inline uint64_t
|
||||||
peak_max(peak_t *peak) {
|
peak_max(peak_t *peak) {
|
||||||
|
|||||||
@@ -129,8 +129,7 @@ phn_prev_set(void *phn, void *prev, size_t offset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
phn_merge_ordered(void *phn0, void *phn1, size_t offset,
|
phn_merge_ordered(void *phn0, void *phn1, size_t offset, ph_cmp_t cmp) {
|
||||||
ph_cmp_t cmp) {
|
|
||||||
void *phn0child;
|
void *phn0child;
|
||||||
|
|
||||||
assert(phn0 != NULL);
|
assert(phn0 != NULL);
|
||||||
@@ -361,8 +360,7 @@ ph_insert(ph_t *ph, void *phn, size_t offset, ph_cmp_t cmp) {
|
|||||||
|
|
||||||
phn_next_set(phn, phn_next_get(ph->root, offset), offset);
|
phn_next_set(phn, phn_next_get(ph->root, offset), offset);
|
||||||
if (phn_next_get(ph->root, offset) != NULL) {
|
if (phn_next_get(ph->root, offset) != NULL) {
|
||||||
phn_prev_set(phn_next_get(ph->root, offset), phn,
|
phn_prev_set(phn_next_get(ph->root, offset), phn, offset);
|
||||||
offset);
|
|
||||||
}
|
}
|
||||||
phn_prev_set(phn, ph->root, offset);
|
phn_prev_set(phn, ph->root, offset);
|
||||||
phn_next_set(ph->root, phn, offset);
|
phn_next_set(ph->root, phn, offset);
|
||||||
@@ -387,7 +385,6 @@ ph_remove_first(ph_t *ph, size_t offset, ph_cmp_t cmp) {
|
|||||||
ph->root = ph_merge_children(ph->root, offset, cmp);
|
ph->root = ph_merge_children(ph->root, offset, cmp);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
@@ -442,8 +439,8 @@ ph_enumerate_vars_init(ph_enumerate_vars_t *vars, uint16_t max_visit_num,
|
|||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
ph_enumerate_queue_push(void *phn, void **bfs_queue,
|
ph_enumerate_queue_push(
|
||||||
ph_enumerate_vars_t *vars) {
|
void *phn, void **bfs_queue, ph_enumerate_vars_t *vars) {
|
||||||
assert(vars->queue_size < vars->max_queue_size);
|
assert(vars->queue_size < vars->max_queue_size);
|
||||||
bfs_queue[vars->rear] = phn;
|
bfs_queue[vars->rear] = phn;
|
||||||
vars->rear = (vars->rear + 1) % vars->max_queue_size;
|
vars->rear = (vars->rear + 1) % vars->max_queue_size;
|
||||||
@@ -460,7 +457,6 @@ ph_enumerate_queue_pop(void **bfs_queue, ph_enumerate_vars_t *vars) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The two functions below offer a solution to enumerate the pairing heap.
|
* The two functions below offer a solution to enumerate the pairing heap.
|
||||||
* Whe enumerating, always call ph_enumerate_prepare first to prepare the queue
|
* Whe enumerating, always call ph_enumerate_prepare first to prepare the queue
|
||||||
@@ -478,8 +474,8 @@ ph_enumerate_prepare(ph_t *ph, void **bfs_queue, ph_enumerate_vars_t *vars,
|
|||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void *
|
JEMALLOC_ALWAYS_INLINE void *
|
||||||
ph_enumerate_next(ph_t *ph, size_t offset, void **bfs_queue,
|
ph_enumerate_next(
|
||||||
ph_enumerate_vars_t *vars) {
|
ph_t *ph, size_t offset, void **bfs_queue, ph_enumerate_vars_t *vars) {
|
||||||
if (vars->queue_size == 0) {
|
if (vars->queue_size == 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -516,7 +512,6 @@ typedef struct { \
|
|||||||
ph_enumerate_vars_t vars; \
|
ph_enumerate_vars_t vars; \
|
||||||
} a_prefix##_enumerate_helper_t;
|
} a_prefix##_enumerate_helper_t;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The ph_proto() macro generates function prototypes that correspond to the
|
* The ph_proto() macro generates function prototypes that correspond to the
|
||||||
* functions generated by an equivalently parameterized call to ph_gen().
|
* functions generated by an equivalently parameterized call to ph_gen().
|
||||||
@@ -534,57 +529,48 @@ a_attr a_type *a_prefix##_remove_any(a_prefix##_t *ph); \
|
|||||||
a_attr void a_prefix##_enumerate_prepare(a_prefix##_t *ph, \
|
a_attr void a_prefix##_enumerate_prepare(a_prefix##_t *ph, \
|
||||||
a_prefix##_enumerate_helper_t *helper, uint16_t max_visit_num, \
|
a_prefix##_enumerate_helper_t *helper, uint16_t max_visit_num, \
|
||||||
uint16_t max_queue_size); \
|
uint16_t max_queue_size); \
|
||||||
a_attr a_type *a_prefix##_enumerate_next(a_prefix##_t *ph, \
|
a_attr a_type *a_prefix##_enumerate_next( \
|
||||||
a_prefix##_enumerate_helper_t *helper);
|
a_prefix##_t *ph, a_prefix##_enumerate_helper_t *helper);
|
||||||
|
|
||||||
/* The ph_gen() macro generates a type-specific pairing heap implementation. */
|
/* The ph_gen() macro generates a type-specific pairing heap implementation. */
|
||||||
#define ph_gen(a_attr, a_prefix, a_type, a_field, a_cmp) \
|
#define ph_gen(a_attr, a_prefix, a_type, a_field, a_cmp) \
|
||||||
JEMALLOC_ALWAYS_INLINE int \
|
JEMALLOC_ALWAYS_INLINE int a_prefix##_ph_cmp(void *a, void *b) { \
|
||||||
a_prefix##_ph_cmp(void *a, void *b) { \
|
|
||||||
return a_cmp((a_type *)a, (a_type *)b); \
|
return a_cmp((a_type *)a, (a_type *)b); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
a_attr void \
|
a_attr void a_prefix##_new(a_prefix##_t *ph) { \
|
||||||
a_prefix##_new(a_prefix##_t *ph) { \
|
|
||||||
ph_new(&ph->ph); \
|
ph_new(&ph->ph); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
a_attr bool \
|
a_attr bool a_prefix##_empty(a_prefix##_t *ph) { \
|
||||||
a_prefix##_empty(a_prefix##_t *ph) { \
|
|
||||||
return ph_empty(&ph->ph); \
|
return ph_empty(&ph->ph); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
a_attr a_type * \
|
a_attr a_type *a_prefix##_first(a_prefix##_t *ph) { \
|
||||||
a_prefix##_first(a_prefix##_t *ph) { \
|
return ph_first( \
|
||||||
return ph_first(&ph->ph, offsetof(a_type, a_field), \
|
&ph->ph, offsetof(a_type, a_field), &a_prefix##_ph_cmp); \
|
||||||
&a_prefix##_ph_cmp); \
|
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
a_attr a_type * \
|
a_attr a_type *a_prefix##_any(a_prefix##_t *ph) { \
|
||||||
a_prefix##_any(a_prefix##_t *ph) { \
|
|
||||||
return ph_any(&ph->ph, offsetof(a_type, a_field)); \
|
return ph_any(&ph->ph, offsetof(a_type, a_field)); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
a_attr void \
|
a_attr void a_prefix##_insert(a_prefix##_t *ph, a_type *phn) { \
|
||||||
a_prefix##_insert(a_prefix##_t *ph, a_type *phn) { \
|
|
||||||
ph_insert(&ph->ph, phn, offsetof(a_type, a_field), \
|
ph_insert(&ph->ph, phn, offsetof(a_type, a_field), \
|
||||||
a_prefix##_ph_cmp); \
|
a_prefix##_ph_cmp); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
a_attr a_type * \
|
a_attr a_type *a_prefix##_remove_first(a_prefix##_t *ph) { \
|
||||||
a_prefix##_remove_first(a_prefix##_t *ph) { \
|
return ph_remove_first( \
|
||||||
return ph_remove_first(&ph->ph, offsetof(a_type, a_field), \
|
&ph->ph, offsetof(a_type, a_field), a_prefix##_ph_cmp); \
|
||||||
a_prefix##_ph_cmp); \
|
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
a_attr void \
|
a_attr void a_prefix##_remove(a_prefix##_t *ph, a_type *phn) { \
|
||||||
a_prefix##_remove(a_prefix##_t *ph, a_type *phn) { \
|
|
||||||
ph_remove(&ph->ph, phn, offsetof(a_type, a_field), \
|
ph_remove(&ph->ph, phn, offsetof(a_type, a_field), \
|
||||||
a_prefix##_ph_cmp); \
|
a_prefix##_ph_cmp); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
a_attr a_type * \
|
a_attr a_type *a_prefix##_remove_any(a_prefix##_t *ph) { \
|
||||||
a_prefix##_remove_any(a_prefix##_t *ph) { \
|
|
||||||
a_type *ret = a_prefix##_any(ph); \
|
a_type *ret = a_prefix##_any(ph); \
|
||||||
if (ret != NULL) { \
|
if (ret != NULL) { \
|
||||||
a_prefix##_remove(ph, ret); \
|
a_prefix##_remove(ph, ret); \
|
||||||
@@ -592,17 +578,15 @@ a_prefix##_remove_any(a_prefix##_t *ph) { \
|
|||||||
return ret; \
|
return ret; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
a_attr void \
|
a_attr void a_prefix##_enumerate_prepare(a_prefix##_t *ph, \
|
||||||
a_prefix##_enumerate_prepare(a_prefix##_t *ph, \
|
|
||||||
a_prefix##_enumerate_helper_t *helper, uint16_t max_visit_num, \
|
a_prefix##_enumerate_helper_t *helper, uint16_t max_visit_num, \
|
||||||
uint16_t max_queue_size) { \
|
uint16_t max_queue_size) { \
|
||||||
ph_enumerate_prepare(&ph->ph, helper->bfs_queue, &helper->vars, \
|
ph_enumerate_prepare(&ph->ph, helper->bfs_queue, \
|
||||||
max_visit_num, max_queue_size); \
|
&helper->vars, max_visit_num, max_queue_size); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
a_attr a_type * \
|
a_attr a_type *a_prefix##_enumerate_next( \
|
||||||
a_prefix##_enumerate_next(a_prefix##_t *ph, \
|
a_prefix##_t *ph, a_prefix##_enumerate_helper_t *helper) { \
|
||||||
a_prefix##_enumerate_helper_t *helper) { \
|
|
||||||
return ph_enumerate_next(&ph->ph, offsetof(a_type, a_field), \
|
return ph_enumerate_next(&ph->ph, offsetof(a_type, a_field), \
|
||||||
helper->bfs_queue, &helper->vars); \
|
helper->bfs_queue, &helper->vars); \
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ extern bool opt_prof_active;
|
|||||||
extern bool opt_prof_thread_active_init;
|
extern bool opt_prof_thread_active_init;
|
||||||
extern unsigned opt_prof_bt_max;
|
extern unsigned opt_prof_bt_max;
|
||||||
extern size_t opt_lg_prof_sample; /* Mean bytes between samples. */
|
extern size_t opt_lg_prof_sample; /* Mean bytes between samples. */
|
||||||
extern size_t opt_experimental_lg_prof_threshold; /* Mean bytes between thresholds. */
|
extern size_t
|
||||||
|
opt_experimental_lg_prof_threshold; /* Mean bytes between thresholds. */
|
||||||
extern ssize_t opt_lg_prof_interval; /* lg(prof_interval). */
|
extern ssize_t opt_lg_prof_interval; /* lg(prof_interval). */
|
||||||
extern bool opt_prof_gdump; /* High-water memory dumping. */
|
extern bool opt_prof_gdump; /* High-water memory dumping. */
|
||||||
extern bool opt_prof_final; /* Final profile dumping. */
|
extern bool opt_prof_final; /* Final profile dumping. */
|
||||||
@@ -77,10 +78,10 @@ prof_tdata_t *prof_tdata_init(tsd_t *tsd);
|
|||||||
prof_tdata_t *prof_tdata_reinit(tsd_t *tsd, prof_tdata_t *tdata);
|
prof_tdata_t *prof_tdata_reinit(tsd_t *tsd, prof_tdata_t *tdata);
|
||||||
|
|
||||||
void prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx);
|
void prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx);
|
||||||
void prof_malloc_sample_object(tsd_t *tsd, const void *ptr, size_t size,
|
void prof_malloc_sample_object(
|
||||||
size_t usize, prof_tctx_t *tctx);
|
tsd_t *tsd, const void *ptr, size_t size, size_t usize, prof_tctx_t *tctx);
|
||||||
void prof_free_sampled_object(tsd_t *tsd, const void *ptr, size_t usize,
|
void prof_free_sampled_object(
|
||||||
prof_info_t *prof_info);
|
tsd_t *tsd, const void *ptr, size_t usize, prof_info_t *prof_info);
|
||||||
prof_tctx_t *prof_tctx_create(tsd_t *tsd);
|
prof_tctx_t *prof_tctx_create(tsd_t *tsd);
|
||||||
void prof_idump(tsdn_t *tsdn);
|
void prof_idump(tsdn_t *tsdn);
|
||||||
bool prof_mdump(tsd_t *tsd, const char *filename);
|
bool prof_mdump(tsd_t *tsd, const char *filename);
|
||||||
@@ -130,8 +131,8 @@ uint64_t tsd_prof_sample_event_wait_get(tsd_t *tsd);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE bool
|
JEMALLOC_ALWAYS_INLINE bool
|
||||||
te_prof_sample_event_lookahead_surplus(tsd_t *tsd, size_t usize,
|
te_prof_sample_event_lookahead_surplus(
|
||||||
size_t *surplus) {
|
tsd_t *tsd, size_t usize, size_t *surplus) {
|
||||||
if (surplus != NULL) {
|
if (surplus != NULL) {
|
||||||
/*
|
/*
|
||||||
* This is a dead store: the surplus will be overwritten before
|
* This is a dead store: the surplus will be overwritten before
|
||||||
@@ -146,8 +147,8 @@ te_prof_sample_event_lookahead_surplus(tsd_t *tsd, size_t usize,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* The subtraction is intentionally susceptible to underflow. */
|
/* The subtraction is intentionally susceptible to underflow. */
|
||||||
uint64_t accumbytes = tsd_thread_allocated_get(tsd) + usize -
|
uint64_t accumbytes = tsd_thread_allocated_get(tsd) + usize
|
||||||
tsd_thread_allocated_last_event_get(tsd);
|
- tsd_thread_allocated_last_event_get(tsd);
|
||||||
uint64_t sample_wait = tsd_prof_sample_event_wait_get(tsd);
|
uint64_t sample_wait = tsd_prof_sample_event_wait_get(tsd);
|
||||||
if (accumbytes < sample_wait) {
|
if (accumbytes < sample_wait) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ typedef void (*prof_backtrace_hook_t)(void **, unsigned *, unsigned);
|
|||||||
typedef void (*prof_dump_hook_t)(const char *filename);
|
typedef void (*prof_dump_hook_t)(const char *filename);
|
||||||
|
|
||||||
/* ptr, size, backtrace vector, backtrace vector length, usize */
|
/* ptr, size, backtrace vector, backtrace vector length, usize */
|
||||||
typedef void (*prof_sample_hook_t)(const void *ptr, size_t size, void **backtrace, unsigned backtrace_length, size_t usize);
|
typedef void (*prof_sample_hook_t)(const void *ptr, size_t size,
|
||||||
|
void **backtrace, unsigned backtrace_length, size_t usize);
|
||||||
|
|
||||||
/* ptr, size */
|
/* ptr, size */
|
||||||
typedef void (*prof_sample_free_hook_t)(const void *, size_t);
|
typedef void (*prof_sample_free_hook_t)(const void *, size_t);
|
||||||
@@ -29,6 +30,7 @@ typedef void (*prof_sample_free_hook_t)(const void *, size_t);
|
|||||||
/*
|
/*
|
||||||
* A callback hook that notifies when an allocation threshold has been crossed.
|
* A callback hook that notifies when an allocation threshold has been crossed.
|
||||||
*/
|
*/
|
||||||
typedef void (*prof_threshold_hook_t)(uint64_t alloc, uint64_t dealloc, uint64_t peak);
|
typedef void (*prof_threshold_hook_t)(
|
||||||
|
uint64_t alloc, uint64_t dealloc, uint64_t peak);
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_PROF_HOOK_H */
|
#endif /* JEMALLOC_INTERNAL_PROF_HOOK_H */
|
||||||
|
|||||||
@@ -164,8 +164,8 @@ JEMALLOC_ALWAYS_INLINE prof_tctx_t *
|
|||||||
prof_alloc_prep(tsd_t *tsd, bool prof_active, bool sample_event) {
|
prof_alloc_prep(tsd_t *tsd, bool prof_active, bool sample_event) {
|
||||||
prof_tctx_t *ret;
|
prof_tctx_t *ret;
|
||||||
|
|
||||||
if (!prof_active ||
|
if (!prof_active
|
||||||
likely(prof_sample_should_skip(tsd, sample_event))) {
|
|| likely(prof_sample_should_skip(tsd, sample_event))) {
|
||||||
ret = PROF_TCTX_SENTINEL;
|
ret = PROF_TCTX_SENTINEL;
|
||||||
} else {
|
} else {
|
||||||
ret = prof_tctx_create(tsd);
|
ret = prof_tctx_create(tsd);
|
||||||
@@ -242,8 +242,8 @@ prof_realloc(tsd_t *tsd, const void *ptr, size_t size, size_t usize,
|
|||||||
* counters.
|
* counters.
|
||||||
*/
|
*/
|
||||||
if (unlikely(old_sampled)) {
|
if (unlikely(old_sampled)) {
|
||||||
prof_free_sampled_object(tsd, old_ptr, old_usize,
|
prof_free_sampled_object(
|
||||||
old_prof_info);
|
tsd, old_ptr, old_usize, old_prof_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,9 +254,10 @@ prof_sample_align(size_t usize, size_t orig_align) {
|
|||||||
* w/o metadata lookup.
|
* w/o metadata lookup.
|
||||||
*/
|
*/
|
||||||
assert(opt_prof);
|
assert(opt_prof);
|
||||||
return (orig_align < PROF_SAMPLE_ALIGNMENT &&
|
return (orig_align < PROF_SAMPLE_ALIGNMENT
|
||||||
(sz_can_use_slab(usize) || opt_cache_oblivious)) ?
|
&& (sz_can_use_slab(usize) || opt_cache_oblivious))
|
||||||
PROF_SAMPLE_ALIGNMENT : orig_align;
|
? PROF_SAMPLE_ALIGNMENT
|
||||||
|
: orig_align;
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE bool
|
JEMALLOC_ALWAYS_INLINE bool
|
||||||
@@ -271,8 +272,8 @@ prof_sampled(tsd_t *tsd, const void *ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
prof_free(tsd_t *tsd, const void *ptr, size_t usize,
|
prof_free(
|
||||||
emap_alloc_ctx_t *alloc_ctx) {
|
tsd_t *tsd, const void *ptr, size_t usize, emap_alloc_ctx_t *alloc_ctx) {
|
||||||
prof_info_t prof_info;
|
prof_info_t prof_info;
|
||||||
prof_info_get_and_reset_recent(tsd, ptr, alloc_ctx, &prof_info);
|
prof_info_get_and_reset_recent(tsd, ptr, alloc_ctx, &prof_info);
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ struct { \
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Static initializer for an empty list. */
|
/* Static initializer for an empty list. */
|
||||||
#define ql_head_initializer(a_head) {NULL}
|
#define ql_head_initializer(a_head) \
|
||||||
|
{ NULL }
|
||||||
|
|
||||||
/* The field definition. */
|
/* The field definition. */
|
||||||
#define ql_elm(a_type) qr(a_type)
|
#define ql_elm(a_type) qr(a_type)
|
||||||
@@ -43,7 +44,8 @@ struct { \
|
|||||||
#define ql_first(a_head) ((a_head)->qlh_first)
|
#define ql_first(a_head) ((a_head)->qlh_first)
|
||||||
|
|
||||||
/* Dynamically initializes a list. */
|
/* Dynamically initializes a list. */
|
||||||
#define ql_new(a_head) do { \
|
#define ql_new(a_head) \
|
||||||
|
do { \
|
||||||
ql_first(a_head) = NULL; \
|
ql_first(a_head) = NULL; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
@@ -51,7 +53,8 @@ struct { \
|
|||||||
* Sets dest to be the contents of src (overwriting any elements there), leaving
|
* Sets dest to be the contents of src (overwriting any elements there), leaving
|
||||||
* src empty.
|
* src empty.
|
||||||
*/
|
*/
|
||||||
#define ql_move(a_head_dest, a_head_src) do { \
|
#define ql_move(a_head_dest, a_head_src) \
|
||||||
|
do { \
|
||||||
ql_first(a_head_dest) = ql_first(a_head_src); \
|
ql_first(a_head_dest) = ql_first(a_head_src); \
|
||||||
ql_new(a_head_src); \
|
ql_new(a_head_src); \
|
||||||
} while (0)
|
} while (0)
|
||||||
@@ -76,14 +79,14 @@ struct { \
|
|||||||
* the end or retreat before the beginning of the list returns NULL.
|
* the end or retreat before the beginning of the list returns NULL.
|
||||||
*/
|
*/
|
||||||
#define ql_next(a_head, a_elm, a_field) \
|
#define ql_next(a_head, a_elm, a_field) \
|
||||||
((ql_last(a_head, a_field) != (a_elm)) \
|
((ql_last(a_head, a_field) != (a_elm)) ? qr_next((a_elm), a_field) \
|
||||||
? qr_next((a_elm), a_field) : NULL)
|
|
||||||
#define ql_prev(a_head, a_elm, a_field) \
|
|
||||||
((ql_first(a_head) != (a_elm)) ? qr_prev((a_elm), a_field) \
|
|
||||||
: NULL)
|
: NULL)
|
||||||
|
#define ql_prev(a_head, a_elm, a_field) \
|
||||||
|
((ql_first(a_head) != (a_elm)) ? qr_prev((a_elm), a_field) : NULL)
|
||||||
|
|
||||||
/* Inserts a_elm before a_qlelm in the list. */
|
/* Inserts a_elm before a_qlelm in the list. */
|
||||||
#define ql_before_insert(a_head, a_qlelm, a_elm, a_field) do { \
|
#define ql_before_insert(a_head, a_qlelm, a_elm, a_field) \
|
||||||
|
do { \
|
||||||
qr_before_insert((a_qlelm), (a_elm), a_field); \
|
qr_before_insert((a_qlelm), (a_elm), a_field); \
|
||||||
if (ql_first(a_head) == (a_qlelm)) { \
|
if (ql_first(a_head) == (a_qlelm)) { \
|
||||||
ql_first(a_head) = (a_elm); \
|
ql_first(a_head) = (a_elm); \
|
||||||
@@ -95,7 +98,8 @@ struct { \
|
|||||||
qr_after_insert((a_qlelm), (a_elm), a_field)
|
qr_after_insert((a_qlelm), (a_elm), a_field)
|
||||||
|
|
||||||
/* Inserts a_elm as the first item in the list. */
|
/* Inserts a_elm as the first item in the list. */
|
||||||
#define ql_head_insert(a_head, a_elm, a_field) do { \
|
#define ql_head_insert(a_head, a_elm, a_field) \
|
||||||
|
do { \
|
||||||
if (!ql_empty(a_head)) { \
|
if (!ql_empty(a_head)) { \
|
||||||
qr_before_insert(ql_first(a_head), (a_elm), a_field); \
|
qr_before_insert(ql_first(a_head), (a_elm), a_field); \
|
||||||
} \
|
} \
|
||||||
@@ -103,7 +107,8 @@ struct { \
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* Inserts a_elm as the last item in the list. */
|
/* Inserts a_elm as the last item in the list. */
|
||||||
#define ql_tail_insert(a_head, a_elm, a_field) do { \
|
#define ql_tail_insert(a_head, a_elm, a_field) \
|
||||||
|
do { \
|
||||||
if (!ql_empty(a_head)) { \
|
if (!ql_empty(a_head)) { \
|
||||||
qr_before_insert(ql_first(a_head), (a_elm), a_field); \
|
qr_before_insert(ql_first(a_head), (a_elm), a_field); \
|
||||||
} \
|
} \
|
||||||
@@ -114,18 +119,20 @@ struct { \
|
|||||||
* Given lists a = [a_1, ..., a_n] and [b_1, ..., b_n], results in:
|
* Given lists a = [a_1, ..., a_n] and [b_1, ..., b_n], results in:
|
||||||
* a = [a1, ..., a_n, b_1, ..., b_n] and b = [].
|
* a = [a1, ..., a_n, b_1, ..., b_n] and b = [].
|
||||||
*/
|
*/
|
||||||
#define ql_concat(a_head_a, a_head_b, a_field) do { \
|
#define ql_concat(a_head_a, a_head_b, a_field) \
|
||||||
|
do { \
|
||||||
if (ql_empty(a_head_a)) { \
|
if (ql_empty(a_head_a)) { \
|
||||||
ql_move(a_head_a, a_head_b); \
|
ql_move(a_head_a, a_head_b); \
|
||||||
} else if (!ql_empty(a_head_b)) { \
|
} else if (!ql_empty(a_head_b)) { \
|
||||||
qr_meld(ql_first(a_head_a), ql_first(a_head_b), \
|
qr_meld( \
|
||||||
a_field); \
|
ql_first(a_head_a), ql_first(a_head_b), a_field); \
|
||||||
ql_new(a_head_b); \
|
ql_new(a_head_b); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* Removes a_elm from the list. */
|
/* Removes a_elm from the list. */
|
||||||
#define ql_remove(a_head, a_elm, a_field) do { \
|
#define ql_remove(a_head, a_elm, a_field) \
|
||||||
|
do { \
|
||||||
if (ql_first(a_head) == (a_elm)) { \
|
if (ql_first(a_head) == (a_elm)) { \
|
||||||
ql_first(a_head) = qr_next(ql_first(a_head), a_field); \
|
ql_first(a_head) = qr_next(ql_first(a_head), a_field); \
|
||||||
} \
|
} \
|
||||||
@@ -137,13 +144,15 @@ struct { \
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* Removes the first item in the list. */
|
/* Removes the first item in the list. */
|
||||||
#define ql_head_remove(a_head, a_type, a_field) do { \
|
#define ql_head_remove(a_head, a_type, a_field) \
|
||||||
|
do { \
|
||||||
a_type *t = ql_first(a_head); \
|
a_type *t = ql_first(a_head); \
|
||||||
ql_remove((a_head), t, a_field); \
|
ql_remove((a_head), t, a_field); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* Removes the last item in the list. */
|
/* Removes the last item in the list. */
|
||||||
#define ql_tail_remove(a_head, a_type, a_field) do { \
|
#define ql_tail_remove(a_head, a_type, a_field) \
|
||||||
|
do { \
|
||||||
a_type *t = ql_last(a_head, a_field); \
|
a_type *t = ql_last(a_head, a_field); \
|
||||||
ql_remove((a_head), t, a_field); \
|
ql_remove((a_head), t, a_field); \
|
||||||
} while (0)
|
} while (0)
|
||||||
@@ -155,7 +164,8 @@ struct { \
|
|||||||
* and replaces b's contents with:
|
* and replaces b's contents with:
|
||||||
* b = [a_n, a_n+1, ...]
|
* b = [a_n, a_n+1, ...]
|
||||||
*/
|
*/
|
||||||
#define ql_split(a_head_a, a_elm, a_head_b, a_field) do { \
|
#define ql_split(a_head_a, a_elm, a_head_b, a_field) \
|
||||||
|
do { \
|
||||||
if (ql_first(a_head_a) == (a_elm)) { \
|
if (ql_first(a_head_a) == (a_elm)) { \
|
||||||
ql_move(a_head_b, a_head_a); \
|
ql_move(a_head_b, a_head_a); \
|
||||||
} else { \
|
} else { \
|
||||||
@@ -170,7 +180,8 @@ struct { \
|
|||||||
* ql_remove((a_head), t, a_field);
|
* ql_remove((a_head), t, a_field);
|
||||||
* ql_tail_insert((a_head), t, a_field);
|
* ql_tail_insert((a_head), t, a_field);
|
||||||
*/
|
*/
|
||||||
#define ql_rotate(a_head, a_field) do { \
|
#define ql_rotate(a_head, a_field) \
|
||||||
|
do { \
|
||||||
ql_first(a_head) = qr_next(ql_first(a_head), a_field); \
|
ql_first(a_head) = qr_next(ql_first(a_head), a_field); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ struct { \
|
|||||||
* if that initialization is going to be immediately overwritten (say, by being
|
* if that initialization is going to be immediately overwritten (say, by being
|
||||||
* passed into an insertion macro).
|
* passed into an insertion macro).
|
||||||
*/
|
*/
|
||||||
#define qr_new(a_qr, a_field) do { \
|
#define qr_new(a_qr, a_field) \
|
||||||
|
do { \
|
||||||
(a_qr)->a_field.qre_next = (a_qr); \
|
(a_qr)->a_field.qre_next = (a_qr); \
|
||||||
(a_qr)->a_field.qre_prev = (a_qr); \
|
(a_qr)->a_field.qre_prev = (a_qr); \
|
||||||
} while (0)
|
} while (0)
|
||||||
@@ -58,7 +59,8 @@ struct { \
|
|||||||
*
|
*
|
||||||
* a_qr_a can directly be a qr_next() macro, but a_qr_b cannot.
|
* a_qr_a can directly be a qr_next() macro, but a_qr_b cannot.
|
||||||
*/
|
*/
|
||||||
#define qr_meld(a_qr_a, a_qr_b, a_field) do { \
|
#define qr_meld(a_qr_a, a_qr_b, a_field) \
|
||||||
|
do { \
|
||||||
(a_qr_b)->a_field.qre_prev->a_field.qre_next = \
|
(a_qr_b)->a_field.qre_prev->a_field.qre_next = \
|
||||||
(a_qr_a)->a_field.qre_prev; \
|
(a_qr_a)->a_field.qre_prev; \
|
||||||
(a_qr_a)->a_field.qre_prev = (a_qr_b)->a_field.qre_prev; \
|
(a_qr_a)->a_field.qre_prev = (a_qr_b)->a_field.qre_prev; \
|
||||||
@@ -98,8 +100,7 @@ struct { \
|
|||||||
* qr_meld() and qr_split() are functionally equivalent, so there's no need to
|
* qr_meld() and qr_split() are functionally equivalent, so there's no need to
|
||||||
* have two copies of the code.
|
* have two copies of the code.
|
||||||
*/
|
*/
|
||||||
#define qr_split(a_qr_a, a_qr_b, a_field) \
|
#define qr_split(a_qr_a, a_qr_b, a_field) qr_meld((a_qr_a), (a_qr_b), a_field)
|
||||||
qr_meld((a_qr_a), (a_qr_b), a_field)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Splits off a_qr from the rest of its ring, so that it becomes a
|
* Splits off a_qr from the rest of its ring, so that it becomes a
|
||||||
@@ -122,10 +123,10 @@ struct { \
|
|||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
#define qr_foreach(var, a_qr, a_field) \
|
#define qr_foreach(var, a_qr, a_field) \
|
||||||
for ((var) = (a_qr); \
|
for ((var) = (a_qr); (var) != NULL; \
|
||||||
(var) != NULL; \
|
|
||||||
(var) = (((var)->a_field.qre_next != (a_qr)) \
|
(var) = (((var)->a_field.qre_next != (a_qr)) \
|
||||||
? (var)->a_field.qre_next : NULL))
|
? (var)->a_field.qre_next \
|
||||||
|
: NULL))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The same (and with the same usage) as qr_foreach, but in the opposite order,
|
* The same (and with the same usage) as qr_foreach, but in the opposite order,
|
||||||
@@ -134,7 +135,6 @@ struct { \
|
|||||||
#define qr_reverse_foreach(var, a_qr, a_field) \
|
#define qr_reverse_foreach(var, a_qr, a_field) \
|
||||||
for ((var) = ((a_qr) != NULL) ? qr_prev(a_qr, a_field) : NULL; \
|
for ((var) = ((a_qr) != NULL) ? qr_prev(a_qr, a_field) : NULL; \
|
||||||
(var) != NULL; \
|
(var) != NULL; \
|
||||||
(var) = (((var) != (a_qr)) \
|
(var) = (((var) != (a_qr)) ? (var)->a_field.qre_prev : NULL))
|
||||||
? (var)->a_field.qre_prev : NULL))
|
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_QR_H */
|
#endif /* JEMALLOC_INTERNAL_QR_H */
|
||||||
|
|||||||
@@ -15,7 +15,8 @@
|
|||||||
# ifdef __alpha__
|
# ifdef __alpha__
|
||||||
# define LG_QUANTUM 4
|
# define LG_QUANTUM 4
|
||||||
# endif
|
# endif
|
||||||
# if (defined(__sparc64__) || defined(__sparcv9) || defined(__sparc_v9__))
|
# if (defined(__sparc64__) || defined(__sparcv9) \
|
||||||
|
|| defined(__sparc_v9__))
|
||||||
# define LG_QUANTUM 4
|
# define LG_QUANTUM 4
|
||||||
# endif
|
# endif
|
||||||
# if (defined(__amd64__) || defined(__x86_64__) || defined(_M_X64))
|
# if (defined(__amd64__) || defined(__x86_64__) || defined(_M_X64))
|
||||||
@@ -49,7 +50,8 @@
|
|||||||
# ifdef __or1k__
|
# ifdef __or1k__
|
||||||
# define LG_QUANTUM 3
|
# define LG_QUANTUM 3
|
||||||
# endif
|
# endif
|
||||||
# if defined(__powerpc__) || defined(__ppc__) || defined(__powerpc64__) || defined(__ppc64__)
|
# if defined(__powerpc__) || defined(__ppc__) || defined(__powerpc64__) \
|
||||||
|
|| defined(__ppc64__)
|
||||||
# define LG_QUANTUM 4
|
# define LG_QUANTUM 4
|
||||||
# endif
|
# endif
|
||||||
# if defined(__riscv) || defined(__riscv__)
|
# if defined(__riscv) || defined(__riscv__)
|
||||||
@@ -58,8 +60,8 @@
|
|||||||
# ifdef __s390__
|
# ifdef __s390__
|
||||||
# define LG_QUANTUM 4
|
# define LG_QUANTUM 4
|
||||||
# endif
|
# endif
|
||||||
# if (defined (__SH3E__) || defined(__SH4_SINGLE__) || defined(__SH4__) || \
|
# if (defined(__SH3E__) || defined(__SH4_SINGLE__) || defined(__SH4__) \
|
||||||
defined(__SH4_SINGLE_ONLY__))
|
|| defined(__SH4_SINGLE_ONLY__))
|
||||||
# define LG_QUANTUM 4
|
# define LG_QUANTUM 4
|
||||||
# endif
|
# endif
|
||||||
# ifdef __tile__
|
# ifdef __tile__
|
||||||
@@ -72,7 +74,8 @@
|
|||||||
# define LG_QUANTUM 3
|
# define LG_QUANTUM 3
|
||||||
# endif
|
# endif
|
||||||
# ifndef LG_QUANTUM
|
# ifndef LG_QUANTUM
|
||||||
# error "Unknown minimum alignment for architecture; specify via "
|
# error \
|
||||||
|
"Unknown minimum alignment for architecture; specify via "
|
||||||
"--with-lg-quantum"
|
"--with-lg-quantum"
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
@@ -81,7 +84,6 @@
|
|||||||
#define QUANTUM_MASK (QUANTUM - 1)
|
#define QUANTUM_MASK (QUANTUM - 1)
|
||||||
|
|
||||||
/* Return the smallest quantum multiple that is >= a. */
|
/* Return the smallest quantum multiple that is >= a. */
|
||||||
#define QUANTUM_CEILING(a) \
|
#define QUANTUM_CEILING(a) (((a) + QUANTUM_MASK) & ~QUANTUM_MASK)
|
||||||
(((a) + QUANTUM_MASK) & ~QUANTUM_MASK)
|
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_QUANTUM_H */
|
#endif /* JEMALLOC_INTERNAL_QUANTUM_H */
|
||||||
|
|||||||
@@ -59,7 +59,8 @@ struct rtree_contents_s {
|
|||||||
|
|
||||||
#define RTREE_LEAF_STATE_WIDTH EDATA_BITS_STATE_WIDTH
|
#define RTREE_LEAF_STATE_WIDTH EDATA_BITS_STATE_WIDTH
|
||||||
#define RTREE_LEAF_STATE_SHIFT 2
|
#define RTREE_LEAF_STATE_SHIFT 2
|
||||||
#define RTREE_LEAF_STATE_MASK MASK(RTREE_LEAF_STATE_WIDTH, RTREE_LEAF_STATE_SHIFT)
|
#define RTREE_LEAF_STATE_MASK \
|
||||||
|
MASK(RTREE_LEAF_STATE_WIDTH, RTREE_LEAF_STATE_SHIFT)
|
||||||
|
|
||||||
struct rtree_leaf_elm_s {
|
struct rtree_leaf_elm_s {
|
||||||
#ifdef RTREE_LEAF_COMPACT
|
#ifdef RTREE_LEAF_COMPACT
|
||||||
@@ -140,8 +141,8 @@ rtree_leaf_elm_t *rtree_leaf_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree,
|
|||||||
JEMALLOC_ALWAYS_INLINE unsigned
|
JEMALLOC_ALWAYS_INLINE unsigned
|
||||||
rtree_leaf_maskbits(void) {
|
rtree_leaf_maskbits(void) {
|
||||||
unsigned ptrbits = ZU(1) << (LG_SIZEOF_PTR + 3);
|
unsigned ptrbits = ZU(1) << (LG_SIZEOF_PTR + 3);
|
||||||
unsigned cumbits = (rtree_levels[RTREE_HEIGHT-1].cumbits -
|
unsigned cumbits = (rtree_levels[RTREE_HEIGHT - 1].cumbits
|
||||||
rtree_levels[RTREE_HEIGHT-1].bits);
|
- rtree_levels[RTREE_HEIGHT - 1].bits);
|
||||||
return ptrbits - cumbits;
|
return ptrbits - cumbits;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,8 +154,8 @@ rtree_leafkey(uintptr_t key) {
|
|||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE size_t
|
JEMALLOC_ALWAYS_INLINE size_t
|
||||||
rtree_cache_direct_map(uintptr_t key) {
|
rtree_cache_direct_map(uintptr_t key) {
|
||||||
return (size_t)((key >> rtree_leaf_maskbits()) &
|
return (
|
||||||
(RTREE_CTX_NCACHE - 1));
|
size_t)((key >> rtree_leaf_maskbits()) & (RTREE_CTX_NCACHE - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE uintptr_t
|
JEMALLOC_ALWAYS_INLINE uintptr_t
|
||||||
@@ -180,10 +181,10 @@ rtree_subkey(uintptr_t key, unsigned level) {
|
|||||||
*/
|
*/
|
||||||
#ifdef RTREE_LEAF_COMPACT
|
#ifdef RTREE_LEAF_COMPACT
|
||||||
JEMALLOC_ALWAYS_INLINE uintptr_t
|
JEMALLOC_ALWAYS_INLINE uintptr_t
|
||||||
rtree_leaf_elm_bits_read(tsdn_t *tsdn, rtree_t *rtree,
|
rtree_leaf_elm_bits_read(
|
||||||
rtree_leaf_elm_t *elm, bool dependent) {
|
tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, bool dependent) {
|
||||||
return (uintptr_t)atomic_load_p(&elm->le_bits, dependent
|
return (uintptr_t)atomic_load_p(
|
||||||
? ATOMIC_RELAXED : ATOMIC_ACQUIRE);
|
&elm->le_bits, dependent ? ATOMIC_RELAXED : ATOMIC_ACQUIRE);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE uintptr_t
|
JEMALLOC_ALWAYS_INLINE uintptr_t
|
||||||
@@ -195,10 +196,10 @@ rtree_leaf_elm_bits_encode(rtree_contents_t contents) {
|
|||||||
uintptr_t szind_bits = (uintptr_t)contents.metadata.szind << LG_VADDR;
|
uintptr_t szind_bits = (uintptr_t)contents.metadata.szind << LG_VADDR;
|
||||||
uintptr_t slab_bits = (uintptr_t)contents.metadata.slab;
|
uintptr_t slab_bits = (uintptr_t)contents.metadata.slab;
|
||||||
uintptr_t is_head_bits = (uintptr_t)contents.metadata.is_head << 1;
|
uintptr_t is_head_bits = (uintptr_t)contents.metadata.is_head << 1;
|
||||||
uintptr_t state_bits = (uintptr_t)contents.metadata.state <<
|
uintptr_t state_bits = (uintptr_t)contents.metadata.state
|
||||||
RTREE_LEAF_STATE_SHIFT;
|
<< RTREE_LEAF_STATE_SHIFT;
|
||||||
uintptr_t metadata_bits = szind_bits | state_bits | is_head_bits |
|
uintptr_t metadata_bits = szind_bits | state_bits | is_head_bits
|
||||||
slab_bits;
|
| slab_bits;
|
||||||
assert((edata_bits & metadata_bits) == 0);
|
assert((edata_bits & metadata_bits) == 0);
|
||||||
|
|
||||||
return edata_bits | metadata_bits;
|
return edata_bits | metadata_bits;
|
||||||
@@ -212,8 +213,8 @@ rtree_leaf_elm_bits_decode(uintptr_t bits) {
|
|||||||
contents.metadata.slab = (bool)(bits & 1);
|
contents.metadata.slab = (bool)(bits & 1);
|
||||||
contents.metadata.is_head = (bool)(bits & (1 << 1));
|
contents.metadata.is_head = (bool)(bits & (1 << 1));
|
||||||
|
|
||||||
uintptr_t state_bits = (bits & RTREE_LEAF_STATE_MASK) >>
|
uintptr_t state_bits = (bits & RTREE_LEAF_STATE_MASK)
|
||||||
RTREE_LEAF_STATE_SHIFT;
|
>> RTREE_LEAF_STATE_SHIFT;
|
||||||
assert(state_bits <= extent_state_max);
|
assert(state_bits <= extent_state_max);
|
||||||
contents.metadata.state = (extent_state_t)state_bits;
|
contents.metadata.state = (extent_state_t)state_bits;
|
||||||
|
|
||||||
@@ -232,7 +233,8 @@ rtree_leaf_elm_bits_decode(uintptr_t bits) {
|
|||||||
/* Restore sign-extended high bits, mask metadata bits. */
|
/* Restore sign-extended high bits, mask metadata bits. */
|
||||||
/* NOLINTNEXTLINE(performance-no-int-to-ptr) */
|
/* NOLINTNEXTLINE(performance-no-int-to-ptr) */
|
||||||
contents.edata = (edata_t *)((uintptr_t)((intptr_t)(bits << RTREE_NHIB)
|
contents.edata = (edata_t *)((uintptr_t)((intptr_t)(bits << RTREE_NHIB)
|
||||||
>> RTREE_NHIB) & low_bit_mask);
|
>> RTREE_NHIB)
|
||||||
|
& low_bit_mask);
|
||||||
# endif
|
# endif
|
||||||
assert((uintptr_t)contents.edata % (uintptr_t)EDATA_ALIGNMENT == 0);
|
assert((uintptr_t)contents.edata % (uintptr_t)EDATA_ALIGNMENT == 0);
|
||||||
return contents;
|
return contents;
|
||||||
@@ -241,36 +243,36 @@ rtree_leaf_elm_bits_decode(uintptr_t bits) {
|
|||||||
#endif /* RTREE_LEAF_COMPACT */
|
#endif /* RTREE_LEAF_COMPACT */
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE rtree_contents_t
|
JEMALLOC_ALWAYS_INLINE rtree_contents_t
|
||||||
rtree_leaf_elm_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm,
|
rtree_leaf_elm_read(
|
||||||
bool dependent) {
|
tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm, bool dependent) {
|
||||||
#ifdef RTREE_LEAF_COMPACT
|
#ifdef RTREE_LEAF_COMPACT
|
||||||
uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, dependent);
|
uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, dependent);
|
||||||
rtree_contents_t contents = rtree_leaf_elm_bits_decode(bits);
|
rtree_contents_t contents = rtree_leaf_elm_bits_decode(bits);
|
||||||
return contents;
|
return contents;
|
||||||
#else
|
#else
|
||||||
rtree_contents_t contents;
|
rtree_contents_t contents;
|
||||||
unsigned metadata_bits = atomic_load_u(&elm->le_metadata, dependent
|
unsigned metadata_bits = atomic_load_u(
|
||||||
? ATOMIC_RELAXED : ATOMIC_ACQUIRE);
|
&elm->le_metadata, dependent ? ATOMIC_RELAXED : ATOMIC_ACQUIRE);
|
||||||
contents.metadata.slab = (bool)(metadata_bits & 1);
|
contents.metadata.slab = (bool)(metadata_bits & 1);
|
||||||
contents.metadata.is_head = (bool)(metadata_bits & (1 << 1));
|
contents.metadata.is_head = (bool)(metadata_bits & (1 << 1));
|
||||||
|
|
||||||
uintptr_t state_bits = (metadata_bits & RTREE_LEAF_STATE_MASK) >>
|
uintptr_t state_bits = (metadata_bits & RTREE_LEAF_STATE_MASK)
|
||||||
RTREE_LEAF_STATE_SHIFT;
|
>> RTREE_LEAF_STATE_SHIFT;
|
||||||
assert(state_bits <= extent_state_max);
|
assert(state_bits <= extent_state_max);
|
||||||
contents.metadata.state = (extent_state_t)state_bits;
|
contents.metadata.state = (extent_state_t)state_bits;
|
||||||
contents.metadata.szind = metadata_bits >> (RTREE_LEAF_STATE_SHIFT +
|
contents.metadata.szind = metadata_bits
|
||||||
RTREE_LEAF_STATE_WIDTH);
|
>> (RTREE_LEAF_STATE_SHIFT + RTREE_LEAF_STATE_WIDTH);
|
||||||
|
|
||||||
contents.edata = (edata_t *)atomic_load_p(&elm->le_edata, dependent
|
contents.edata = (edata_t *)atomic_load_p(
|
||||||
? ATOMIC_RELAXED : ATOMIC_ACQUIRE);
|
&elm->le_edata, dependent ? ATOMIC_RELAXED : ATOMIC_ACQUIRE);
|
||||||
|
|
||||||
return contents;
|
return contents;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
rtree_contents_encode(rtree_contents_t contents, void **bits,
|
rtree_contents_encode(
|
||||||
unsigned *additional) {
|
rtree_contents_t contents, void **bits, unsigned *additional) {
|
||||||
#ifdef RTREE_LEAF_COMPACT
|
#ifdef RTREE_LEAF_COMPACT
|
||||||
/* NOLINTNEXTLINE(performance-no-int-to-ptr) */
|
/* NOLINTNEXTLINE(performance-no-int-to-ptr) */
|
||||||
*bits = (void *)rtree_leaf_elm_bits_encode(contents);
|
*bits = (void *)rtree_leaf_elm_bits_encode(contents);
|
||||||
@@ -282,15 +284,15 @@ rtree_contents_encode(rtree_contents_t contents, void **bits,
|
|||||||
*additional = (unsigned)contents.metadata.slab
|
*additional = (unsigned)contents.metadata.slab
|
||||||
| ((unsigned)contents.metadata.is_head << 1)
|
| ((unsigned)contents.metadata.is_head << 1)
|
||||||
| ((unsigned)contents.metadata.state << RTREE_LEAF_STATE_SHIFT)
|
| ((unsigned)contents.metadata.state << RTREE_LEAF_STATE_SHIFT)
|
||||||
| ((unsigned)contents.metadata.szind << (RTREE_LEAF_STATE_SHIFT +
|
| ((unsigned)contents.metadata.szind
|
||||||
RTREE_LEAF_STATE_WIDTH));
|
<< (RTREE_LEAF_STATE_SHIFT + RTREE_LEAF_STATE_WIDTH));
|
||||||
*bits = contents.edata;
|
*bits = contents.edata;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
rtree_leaf_elm_write_commit(tsdn_t *tsdn, rtree_t *rtree,
|
rtree_leaf_elm_write_commit(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm,
|
||||||
rtree_leaf_elm_t *elm, void *bits, unsigned additional) {
|
void *bits, unsigned additional) {
|
||||||
#ifdef RTREE_LEAF_COMPACT
|
#ifdef RTREE_LEAF_COMPACT
|
||||||
atomic_store_p(&elm->le_bits, bits, ATOMIC_RELEASE);
|
atomic_store_p(&elm->le_bits, bits, ATOMIC_RELEASE);
|
||||||
#else
|
#else
|
||||||
@@ -304,8 +306,8 @@ rtree_leaf_elm_write_commit(tsdn_t *tsdn, rtree_t *rtree,
|
|||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree,
|
rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm,
|
||||||
rtree_leaf_elm_t *elm, rtree_contents_t contents) {
|
rtree_contents_t contents) {
|
||||||
assert((uintptr_t)contents.edata % EDATA_ALIGNMENT == 0);
|
assert((uintptr_t)contents.edata % EDATA_ALIGNMENT == 0);
|
||||||
void *bits;
|
void *bits;
|
||||||
unsigned additional;
|
unsigned additional;
|
||||||
@@ -385,7 +387,8 @@ rtree_leaf_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
|||||||
* Search the L2 LRU cache. On hit, swap the matching element into the
|
* Search the L2 LRU cache. On hit, swap the matching element into the
|
||||||
* slot in L1 cache, and move the position in L2 up by 1.
|
* slot in L1 cache, and move the position in L2 up by 1.
|
||||||
*/
|
*/
|
||||||
#define RTREE_CACHE_CHECK_L2(i) do { \
|
#define RTREE_CACHE_CHECK_L2(i) \
|
||||||
|
do { \
|
||||||
if (likely(rtree_ctx->l2_cache[i].leafkey == leafkey)) { \
|
if (likely(rtree_ctx->l2_cache[i].leafkey == leafkey)) { \
|
||||||
rtree_leaf_elm_t *leaf = rtree_ctx->l2_cache[i].leaf; \
|
rtree_leaf_elm_t *leaf = rtree_ctx->l2_cache[i].leaf; \
|
||||||
assert(leaf != NULL); \
|
assert(leaf != NULL); \
|
||||||
@@ -407,7 +410,8 @@ rtree_leaf_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
|||||||
} \
|
} \
|
||||||
rtree_ctx->cache[slot].leafkey = leafkey; \
|
rtree_ctx->cache[slot].leafkey = leafkey; \
|
||||||
rtree_ctx->cache[slot].leaf = leaf; \
|
rtree_ctx->cache[slot].leaf = leaf; \
|
||||||
uintptr_t subkey = rtree_subkey(key, RTREE_HEIGHT-1); \
|
uintptr_t subkey = rtree_subkey( \
|
||||||
|
key, RTREE_HEIGHT - 1); \
|
||||||
return &leaf[subkey]; \
|
return &leaf[subkey]; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
@@ -419,8 +423,8 @@ rtree_leaf_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
|||||||
}
|
}
|
||||||
#undef RTREE_CACHE_CHECK_L2
|
#undef RTREE_CACHE_CHECK_L2
|
||||||
|
|
||||||
return rtree_leaf_elm_lookup_hard(tsdn, rtree, rtree_ctx, key,
|
return rtree_leaf_elm_lookup_hard(
|
||||||
dependent, init_missing);
|
tsdn, rtree, rtree_ctx, key, dependent, init_missing);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -440,8 +444,8 @@ rtree_read_independent(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline rtree_contents_t
|
static inline rtree_contents_t
|
||||||
rtree_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
rtree_read(
|
||||||
uintptr_t key) {
|
tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key) {
|
||||||
rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx,
|
rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx,
|
||||||
key, /* dependent */ true, /* init_missing */ false);
|
key, /* dependent */ true, /* init_missing */ false);
|
||||||
assert(elm != NULL);
|
assert(elm != NULL);
|
||||||
@@ -449,21 +453,22 @@ rtree_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline rtree_metadata_t
|
static inline rtree_metadata_t
|
||||||
rtree_metadata_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
rtree_metadata_read(
|
||||||
uintptr_t key) {
|
tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key) {
|
||||||
rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx,
|
rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx,
|
||||||
key, /* dependent */ true, /* init_missing */ false);
|
key, /* dependent */ true, /* init_missing */ false);
|
||||||
assert(elm != NULL);
|
assert(elm != NULL);
|
||||||
return rtree_leaf_elm_read(tsdn, rtree, elm,
|
return rtree_leaf_elm_read(tsdn, rtree, elm,
|
||||||
/* dependent */ true).metadata;
|
/* dependent */ true)
|
||||||
|
.metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns true when the request cannot be fulfilled by fastpath.
|
* Returns true when the request cannot be fulfilled by fastpath.
|
||||||
*/
|
*/
|
||||||
static inline bool
|
static inline bool
|
||||||
rtree_metadata_try_read_fast(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
rtree_metadata_try_read_fast(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
uintptr_t key, rtree_metadata_t *r_rtree_metadata) {
|
rtree_ctx_t *rtree_ctx, uintptr_t key, rtree_metadata_t *r_rtree_metadata) {
|
||||||
rtree_leaf_elm_t *elm;
|
rtree_leaf_elm_t *elm;
|
||||||
/*
|
/*
|
||||||
* Should check the bool return value (lookup success or not) instead of
|
* Should check the bool return value (lookup success or not) instead of
|
||||||
@@ -476,7 +481,8 @@ rtree_metadata_try_read_fast(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ct
|
|||||||
}
|
}
|
||||||
assert(elm != NULL);
|
assert(elm != NULL);
|
||||||
*r_rtree_metadata = rtree_leaf_elm_read(tsdn, rtree, elm,
|
*r_rtree_metadata = rtree_leaf_elm_read(tsdn, rtree, elm,
|
||||||
/* dependent */ true).metadata;
|
/* dependent */ true)
|
||||||
|
.metadata;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -496,16 +502,21 @@ rtree_write_range_impl(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
|||||||
|
|
||||||
rtree_leaf_elm_t *elm = NULL; /* Dead store. */
|
rtree_leaf_elm_t *elm = NULL; /* Dead store. */
|
||||||
for (uintptr_t addr = base; addr <= end; addr += PAGE) {
|
for (uintptr_t addr = base; addr <= end; addr += PAGE) {
|
||||||
if (addr == base ||
|
if (addr == base
|
||||||
(addr & ((ZU(1) << rtree_leaf_maskbits()) - 1)) == 0) {
|
|| (addr & ((ZU(1) << rtree_leaf_maskbits()) - 1)) == 0) {
|
||||||
elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx, addr,
|
elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx,
|
||||||
|
addr,
|
||||||
/* dependent */ true, /* init_missing */ false);
|
/* dependent */ true, /* init_missing */ false);
|
||||||
assert(elm != NULL);
|
assert(elm != NULL);
|
||||||
}
|
}
|
||||||
assert(elm == rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx, addr,
|
assert(elm
|
||||||
|
== rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx, addr,
|
||||||
/* dependent */ true, /* init_missing */ false));
|
/* dependent */ true, /* init_missing */ false));
|
||||||
assert(!clearing || rtree_leaf_elm_read(tsdn, rtree, elm,
|
assert(!clearing
|
||||||
/* dependent */ true).edata != NULL);
|
|| rtree_leaf_elm_read(tsdn, rtree, elm,
|
||||||
|
/* dependent */ true)
|
||||||
|
.edata
|
||||||
|
!= NULL);
|
||||||
rtree_leaf_elm_write_commit(tsdn, rtree, elm, bits, additional);
|
rtree_leaf_elm_write_commit(tsdn, rtree, elm, bits, additional);
|
||||||
elm++;
|
elm++;
|
||||||
}
|
}
|
||||||
@@ -533,13 +544,15 @@ rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
rtree_clear(
|
||||||
uintptr_t key) {
|
tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key) {
|
||||||
rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx,
|
rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx,
|
||||||
key, /* dependent */ true, /* init_missing */ false);
|
key, /* dependent */ true, /* init_missing */ false);
|
||||||
assert(elm != NULL);
|
assert(elm != NULL);
|
||||||
assert(rtree_leaf_elm_read(tsdn, rtree, elm,
|
assert(rtree_leaf_elm_read(tsdn, rtree, elm,
|
||||||
/* dependent */ true).edata != NULL);
|
/* dependent */ true)
|
||||||
|
.edata
|
||||||
|
!= NULL);
|
||||||
rtree_contents_t contents;
|
rtree_contents_t contents;
|
||||||
contents.edata = NULL;
|
contents.edata = NULL;
|
||||||
contents.metadata.szind = SC_NSIZES;
|
contents.metadata.szind = SC_NSIZES;
|
||||||
|
|||||||
@@ -25,7 +25,8 @@
|
|||||||
|
|
||||||
/* Needed for initialization only. */
|
/* Needed for initialization only. */
|
||||||
#define RTREE_LEAFKEY_INVALID ((uintptr_t)1)
|
#define RTREE_LEAFKEY_INVALID ((uintptr_t)1)
|
||||||
#define RTREE_CTX_CACHE_ELM_INVALID {RTREE_LEAFKEY_INVALID, NULL}
|
#define RTREE_CTX_CACHE_ELM_INVALID \
|
||||||
|
{ RTREE_LEAFKEY_INVALID, NULL }
|
||||||
|
|
||||||
#define RTREE_CTX_INIT_ELM_1 RTREE_CTX_CACHE_ELM_INVALID
|
#define RTREE_CTX_INIT_ELM_1 RTREE_CTX_CACHE_ELM_INVALID
|
||||||
#define RTREE_CTX_INIT_ELM_2 RTREE_CTX_INIT_ELM_1, RTREE_CTX_INIT_ELM_1
|
#define RTREE_CTX_INIT_ELM_2 RTREE_CTX_INIT_ELM_1, RTREE_CTX_INIT_ELM_1
|
||||||
@@ -40,8 +41,12 @@
|
|||||||
* Static initializer (to invalidate the cache entries) is required because the
|
* Static initializer (to invalidate the cache entries) is required because the
|
||||||
* free fastpath may access the rtree cache before a full tsd initialization.
|
* free fastpath may access the rtree cache before a full tsd initialization.
|
||||||
*/
|
*/
|
||||||
#define RTREE_CTX_INITIALIZER {{RTREE_CTX_INIT_ELM_DATA(RTREE_CTX_NCACHE)}, \
|
#define RTREE_CTX_INITIALIZER \
|
||||||
{RTREE_CTX_INIT_ELM_DATA(RTREE_CTX_NCACHE_L2)}}
|
{ \
|
||||||
|
{RTREE_CTX_INIT_ELM_DATA(RTREE_CTX_NCACHE)}, { \
|
||||||
|
RTREE_CTX_INIT_ELM_DATA(RTREE_CTX_NCACHE_L2) \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct rtree_leaf_elm_s rtree_leaf_elm_t;
|
typedef struct rtree_leaf_elm_s rtree_leaf_elm_t;
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
|
|
||||||
#define SAFETY_CHECK_DOUBLE_FREE_MAX_SCAN_DEFAULT 32
|
#define SAFETY_CHECK_DOUBLE_FREE_MAX_SCAN_DEFAULT 32
|
||||||
|
|
||||||
void safety_check_fail_sized_dealloc(bool current_dealloc, const void *ptr,
|
void safety_check_fail_sized_dealloc(
|
||||||
size_t true_size, size_t input_size);
|
bool current_dealloc, const void *ptr, size_t true_size, size_t input_size);
|
||||||
void safety_check_fail(const char *format, ...);
|
void safety_check_fail(const char *format, ...);
|
||||||
|
|
||||||
typedef void (*safety_check_abort_hook_t)(const char *message);
|
typedef void (*safety_check_abort_hook_t)(const char *message);
|
||||||
@@ -28,8 +28,9 @@ void safety_check_set_abort(safety_check_abort_hook_t abort_fn);
|
|||||||
JEMALLOC_ALWAYS_INLINE const unsigned char *
|
JEMALLOC_ALWAYS_INLINE const unsigned char *
|
||||||
compute_redzone_end(const void *_ptr, size_t usize, size_t bumped_usize) {
|
compute_redzone_end(const void *_ptr, size_t usize, size_t bumped_usize) {
|
||||||
const unsigned char *ptr = (const unsigned char *)_ptr;
|
const unsigned char *ptr = (const unsigned char *)_ptr;
|
||||||
const unsigned char *redzone_end = usize + REDZONE_SIZE < bumped_usize ?
|
const unsigned char *redzone_end = usize + REDZONE_SIZE < bumped_usize
|
||||||
&ptr[usize + REDZONE_SIZE] : &ptr[bumped_usize];
|
? &ptr[usize + REDZONE_SIZE]
|
||||||
|
: &ptr[bumped_usize];
|
||||||
const unsigned char *page_end = (const unsigned char *)
|
const unsigned char *page_end = (const unsigned char *)
|
||||||
ALIGNMENT_ADDR2CEILING(&ptr[usize], os_page);
|
ALIGNMENT_ADDR2CEILING(&ptr[usize], os_page);
|
||||||
return redzone_end < page_end ? redzone_end : page_end;
|
return redzone_end < page_end ? redzone_end : page_end;
|
||||||
@@ -38,8 +39,8 @@ compute_redzone_end(const void *_ptr, size_t usize, size_t bumped_usize) {
|
|||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
safety_check_set_redzone(void *ptr, size_t usize, size_t bumped_usize) {
|
safety_check_set_redzone(void *ptr, size_t usize, size_t bumped_usize) {
|
||||||
assert(usize <= bumped_usize);
|
assert(usize <= bumped_usize);
|
||||||
const unsigned char *redzone_end =
|
const unsigned char *redzone_end = compute_redzone_end(
|
||||||
compute_redzone_end(ptr, usize, bumped_usize);
|
ptr, usize, bumped_usize);
|
||||||
for (unsigned char *curr = &((unsigned char *)ptr)[usize];
|
for (unsigned char *curr = &((unsigned char *)ptr)[usize];
|
||||||
curr < redzone_end; curr++) {
|
curr < redzone_end; curr++) {
|
||||||
*curr = REDZONE_FILL_VALUE;
|
*curr = REDZONE_FILL_VALUE;
|
||||||
@@ -47,10 +48,10 @@ safety_check_set_redzone(void *ptr, size_t usize, size_t bumped_usize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
safety_check_verify_redzone(const void *ptr, size_t usize, size_t bumped_usize)
|
safety_check_verify_redzone(
|
||||||
{
|
const void *ptr, size_t usize, size_t bumped_usize) {
|
||||||
const unsigned char *redzone_end =
|
const unsigned char *redzone_end = compute_redzone_end(
|
||||||
compute_redzone_end(ptr, usize, bumped_usize);
|
ptr, usize, bumped_usize);
|
||||||
for (const unsigned char *curr = &((const unsigned char *)ptr)[usize];
|
for (const unsigned char *curr = &((const unsigned char *)ptr)[usize];
|
||||||
curr < redzone_end; curr++) {
|
curr < redzone_end; curr++) {
|
||||||
if (unlikely(*curr != REDZONE_FILL_VALUE)) {
|
if (unlikely(*curr != REDZONE_FILL_VALUE)) {
|
||||||
|
|||||||
@@ -32,22 +32,22 @@ void san_unguard_pages(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
|
|||||||
* Unguard the extent, but don't modify emap boundaries. Must be called on an
|
* Unguard the extent, but don't modify emap boundaries. Must be called on an
|
||||||
* extent that has been erased from emap and shouldn't be placed back.
|
* extent that has been erased from emap and shouldn't be placed back.
|
||||||
*/
|
*/
|
||||||
void san_unguard_pages_pre_destroy(tsdn_t *tsdn, ehooks_t *ehooks,
|
void san_unguard_pages_pre_destroy(
|
||||||
edata_t *edata, emap_t *emap);
|
tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata, emap_t *emap);
|
||||||
void san_check_stashed_ptrs(void **ptrs, size_t nstashed, size_t usize);
|
void san_check_stashed_ptrs(void **ptrs, size_t nstashed, size_t usize);
|
||||||
|
|
||||||
void tsd_san_init(tsd_t *tsd);
|
void tsd_san_init(tsd_t *tsd);
|
||||||
void san_init(ssize_t lg_san_uaf_align);
|
void san_init(ssize_t lg_san_uaf_align);
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
san_guard_pages_two_sided(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
|
san_guard_pages_two_sided(
|
||||||
emap_t *emap, bool remap) {
|
tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata, emap_t *emap, bool remap) {
|
||||||
san_guard_pages(tsdn, ehooks, edata, emap, true, true, remap);
|
san_guard_pages(tsdn, ehooks, edata, emap, true, true, remap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
san_unguard_pages_two_sided(tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata,
|
san_unguard_pages_two_sided(
|
||||||
emap_t *emap) {
|
tsdn_t *tsdn, ehooks_t *ehooks, edata_t *edata, emap_t *emap) {
|
||||||
san_unguard_pages(tsdn, ehooks, edata, emap, true, true);
|
san_unguard_pages(tsdn, ehooks, edata, emap, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,10 +83,10 @@ san_guard_enabled(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
san_large_extent_decide_guard(tsdn_t *tsdn, ehooks_t *ehooks, size_t size,
|
san_large_extent_decide_guard(
|
||||||
size_t alignment) {
|
tsdn_t *tsdn, ehooks_t *ehooks, size_t size, size_t alignment) {
|
||||||
if (opt_san_guard_large == 0 || ehooks_guard_will_fail(ehooks) ||
|
if (opt_san_guard_large == 0 || ehooks_guard_will_fail(ehooks)
|
||||||
tsdn_null(tsdn)) {
|
|| tsdn_null(tsdn)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,10 +101,10 @@ san_large_extent_decide_guard(tsdn_t *tsdn, ehooks_t *ehooks, size_t size,
|
|||||||
*tsd_san_extents_until_guard_largep_get(tsd) = n - 1;
|
*tsd_san_extents_until_guard_largep_get(tsd) = n - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n == 1 && (alignment <= PAGE) &&
|
if (n == 1 && (alignment <= PAGE)
|
||||||
(san_two_side_guarded_sz(size) <= SC_LARGE_MAXCLASS)) {
|
&& (san_two_side_guarded_sz(size) <= SC_LARGE_MAXCLASS)) {
|
||||||
*tsd_san_extents_until_guard_largep_get(tsd) =
|
*tsd_san_extents_until_guard_largep_get(
|
||||||
opt_san_guard_large;
|
tsd) = opt_san_guard_large;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
assert(tsd_san_extents_until_guard_large_get(tsd) >= 1);
|
assert(tsd_san_extents_until_guard_large_get(tsd) >= 1);
|
||||||
@@ -114,8 +114,8 @@ san_large_extent_decide_guard(tsdn_t *tsdn, ehooks_t *ehooks, size_t size,
|
|||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
san_slab_extent_decide_guard(tsdn_t *tsdn, ehooks_t *ehooks) {
|
san_slab_extent_decide_guard(tsdn_t *tsdn, ehooks_t *ehooks) {
|
||||||
if (opt_san_guard_small == 0 || ehooks_guard_will_fail(ehooks) ||
|
if (opt_san_guard_small == 0 || ehooks_guard_will_fail(ehooks)
|
||||||
tsdn_null(tsdn)) {
|
|| tsdn_null(tsdn)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,8 +123,8 @@ san_slab_extent_decide_guard(tsdn_t *tsdn, ehooks_t *ehooks) {
|
|||||||
uint64_t n = tsd_san_extents_until_guard_small_get(tsd);
|
uint64_t n = tsd_san_extents_until_guard_small_get(tsd);
|
||||||
assert(n >= 1);
|
assert(n >= 1);
|
||||||
if (n == 1) {
|
if (n == 1) {
|
||||||
*tsd_san_extents_until_guard_smallp_get(tsd) =
|
*tsd_san_extents_until_guard_smallp_get(
|
||||||
opt_san_guard_small;
|
tsd) = opt_san_guard_small;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
*tsd_san_extents_until_guard_smallp_get(tsd) = n - 1;
|
*tsd_san_extents_until_guard_smallp_get(tsd) = n - 1;
|
||||||
@@ -134,8 +134,8 @@ san_slab_extent_decide_guard(tsdn_t *tsdn, ehooks_t *ehooks) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
san_junk_ptr_locations(void *ptr, size_t usize, void **first, void **mid,
|
san_junk_ptr_locations(
|
||||||
void **last) {
|
void *ptr, size_t usize, void **first, void **mid, void **last) {
|
||||||
size_t ptr_sz = sizeof(void *);
|
size_t ptr_sz = sizeof(void *);
|
||||||
|
|
||||||
*first = ptr;
|
*first = ptr;
|
||||||
@@ -184,8 +184,8 @@ static inline bool
|
|||||||
san_uaf_detection_enabled(void) {
|
san_uaf_detection_enabled(void) {
|
||||||
bool ret = config_uaf_detection && (opt_lg_san_uaf_align != -1);
|
bool ret = config_uaf_detection && (opt_lg_san_uaf_align != -1);
|
||||||
if (config_uaf_detection && ret) {
|
if (config_uaf_detection && ret) {
|
||||||
assert(san_cache_bin_nonfast_mask == ((uintptr_t)1 <<
|
assert(san_cache_bin_nonfast_mask
|
||||||
opt_lg_san_uaf_align) - 1);
|
== ((uintptr_t)1 << opt_lg_san_uaf_align) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -47,8 +47,7 @@ san_bump_alloc_init(san_bump_alloc_t* sba) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
edata_t *
|
edata_t *san_bump_alloc(tsdn_t *tsdn, san_bump_alloc_t *sba, pac_t *pac,
|
||||||
san_bump_alloc(tsdn_t *tsdn, san_bump_alloc_t* sba, pac_t *pac, ehooks_t *ehooks,
|
ehooks_t *ehooks, size_t size, bool zero);
|
||||||
size_t size, bool zero);
|
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_SAN_BUMP_H */
|
#endif /* JEMALLOC_INTERNAL_SAN_BUMP_H */
|
||||||
|
|||||||
@@ -194,8 +194,8 @@
|
|||||||
* We could probably save some space in arenas by capping this at LG_VADDR size.
|
* We could probably save some space in arenas by capping this at LG_VADDR size.
|
||||||
*/
|
*/
|
||||||
#define SC_LG_BASE_MAX (SC_PTR_BITS - 2)
|
#define SC_LG_BASE_MAX (SC_PTR_BITS - 2)
|
||||||
#define SC_NREGULAR (SC_NGROUP * \
|
#define SC_NREGULAR \
|
||||||
(SC_LG_BASE_MAX - SC_LG_FIRST_REGULAR_BASE + 1) - 1)
|
(SC_NGROUP * (SC_LG_BASE_MAX - SC_LG_FIRST_REGULAR_BASE + 1) - 1)
|
||||||
#define SC_NSIZES (SC_NTINY + SC_NPSEUDO + SC_NREGULAR)
|
#define SC_NSIZES (SC_NTINY + SC_NPSEUDO + SC_NREGULAR)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -222,21 +222,21 @@
|
|||||||
*
|
*
|
||||||
* This gives us the quantity we seek.
|
* This gives us the quantity we seek.
|
||||||
*/
|
*/
|
||||||
#define SC_NPSIZES ( \
|
#define SC_NPSIZES \
|
||||||
SC_NGROUP \
|
(SC_NGROUP + (SC_LG_BASE_MAX - (LG_PAGE + SC_LG_NGROUP)) * SC_NGROUP \
|
||||||
+ (SC_LG_BASE_MAX - (LG_PAGE + SC_LG_NGROUP)) * SC_NGROUP \
|
|
||||||
+ SC_NGROUP - 1)
|
+ SC_NGROUP - 1)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We declare a size class is binnable if size < page size * group. Or, in other
|
* We declare a size class is binnable if size < page size * group. Or, in other
|
||||||
* words, lg(size) < lg(page size) + lg(group size).
|
* words, lg(size) < lg(page size) + lg(group size).
|
||||||
*/
|
*/
|
||||||
#define SC_NBINS ( \
|
#define SC_NBINS \
|
||||||
/* Sub-regular size classes. */ \
|
(/* Sub-regular size classes. */ \
|
||||||
SC_NTINY + SC_NPSEUDO \
|
SC_NTINY \
|
||||||
/* Groups with lg_regular_min_base <= lg_base <= lg_base_max */ \
|
+ SC_NPSEUDO /* Groups with lg_regular_min_base <= lg_base <= lg_base_max */ \
|
||||||
+ SC_NGROUP * (LG_PAGE + SC_LG_NGROUP - SC_LG_FIRST_REGULAR_BASE) \
|
+ SC_NGROUP \
|
||||||
/* Last SC of the last group hits the bound exactly; exclude it. */ \
|
* (LG_PAGE + SC_LG_NGROUP \
|
||||||
|
- SC_LG_FIRST_REGULAR_BASE) /* Last SC of the last group hits the bound exactly; exclude it. */ \
|
||||||
- 1)
|
- 1)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -256,8 +256,8 @@
|
|||||||
#define SC_SMALL_MAX_DELTA (1 << (LG_PAGE - 1))
|
#define SC_SMALL_MAX_DELTA (1 << (LG_PAGE - 1))
|
||||||
|
|
||||||
/* The largest size class allocated out of a slab. */
|
/* The largest size class allocated out of a slab. */
|
||||||
#define SC_SMALL_MAXCLASS (SC_SMALL_MAX_BASE \
|
#define SC_SMALL_MAXCLASS \
|
||||||
+ (SC_NGROUP - 1) * SC_SMALL_MAX_DELTA)
|
(SC_SMALL_MAX_BASE + (SC_NGROUP - 1) * SC_SMALL_MAX_DELTA)
|
||||||
|
|
||||||
/* The fastpath assumes all lookup-able sizes are small. */
|
/* The fastpath assumes all lookup-able sizes are small. */
|
||||||
#if (SC_SMALL_MAXCLASS < SC_LOOKUP_MAXCLASS)
|
#if (SC_SMALL_MAXCLASS < SC_LOOKUP_MAXCLASS)
|
||||||
@@ -369,8 +369,8 @@ void sc_data_init(sc_data_t *data);
|
|||||||
* Updates slab sizes in [begin, end] to be pgs pages in length, if possible.
|
* Updates slab sizes in [begin, end] to be pgs pages in length, if possible.
|
||||||
* Otherwise, does its best to accommodate the request.
|
* Otherwise, does its best to accommodate the request.
|
||||||
*/
|
*/
|
||||||
void sc_data_update_slab_size(sc_data_t *data, size_t begin, size_t end,
|
void sc_data_update_slab_size(
|
||||||
int pgs);
|
sc_data_t *data, size_t begin, size_t end, int pgs);
|
||||||
void sc_boot(sc_data_t *data);
|
void sc_boot(sc_data_t *data);
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_SC_H */
|
#endif /* JEMALLOC_INTERNAL_SC_H */
|
||||||
|
|||||||
@@ -110,8 +110,8 @@ void sec_disable(tsdn_t *tsdn, sec_t *sec);
|
|||||||
* split), which simplifies the stats management.
|
* split), which simplifies the stats management.
|
||||||
*/
|
*/
|
||||||
void sec_stats_merge(tsdn_t *tsdn, sec_t *sec, sec_stats_t *stats);
|
void sec_stats_merge(tsdn_t *tsdn, sec_t *sec, sec_stats_t *stats);
|
||||||
void sec_mutex_stats_read(tsdn_t *tsdn, sec_t *sec,
|
void sec_mutex_stats_read(
|
||||||
mutex_prof_data_t *mutex_prof_data);
|
tsdn_t *tsdn, sec_t *sec, mutex_prof_data_t *mutex_prof_data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We use the arena lock ordering; these are acquired in phase 2 of forking, but
|
* We use the arena lock ordering; these are acquired in phase 2 of forking, but
|
||||||
|
|||||||
@@ -44,18 +44,14 @@ struct sec_opts_s {
|
|||||||
size_t batch_fill_extra;
|
size_t batch_fill_extra;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SEC_OPTS_DEFAULT { \
|
#define SEC_OPTS_DEFAULT \
|
||||||
|
{ \
|
||||||
/* nshards */ \
|
/* nshards */ \
|
||||||
4, \
|
4, /* max_alloc */ \
|
||||||
/* max_alloc */ \
|
(32 * 1024) < PAGE ? PAGE : (32 * 1024), /* max_bytes */ \
|
||||||
(32 * 1024) < PAGE ? PAGE : (32 * 1024), \
|
256 * 1024, /* bytes_after_flush */ \
|
||||||
/* max_bytes */ \
|
128 * 1024, /* batch_fill_extra */ \
|
||||||
256 * 1024, \
|
|
||||||
/* bytes_after_flush */ \
|
|
||||||
128 * 1024, \
|
|
||||||
/* batch_fill_extra */ \
|
|
||||||
0 \
|
0 \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_SEC_OPTS_H */
|
#endif /* JEMALLOC_INTERNAL_SEC_OPTS_H */
|
||||||
|
|||||||
@@ -227,6 +227,6 @@
|
|||||||
STEP(197, UINT64_C(0x0000000000fffdd6), 0.985, 0.999967004818750) \
|
STEP(197, UINT64_C(0x0000000000fffdd6), 0.985, 0.999967004818750) \
|
||||||
STEP(198, UINT64_C(0x0000000000ffff5a), 0.990, 0.999990149400000) \
|
STEP(198, UINT64_C(0x0000000000ffff5a), 0.990, 0.999990149400000) \
|
||||||
STEP(199, UINT64_C(0x0000000000ffffeb), 0.995, 0.999998759356250) \
|
STEP(199, UINT64_C(0x0000000000ffffeb), 0.995, 0.999998759356250) \
|
||||||
STEP( 200, UINT64_C(0x0000000001000000), 1.000, 1.000000000000000) \
|
STEP(200, UINT64_C(0x0000000001000000), 1.000, 1.000000000000000)
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_SMOOTHSTEP_H */
|
#endif /* JEMALLOC_INTERNAL_SMOOTHSTEP_H */
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
|
|
||||||
#include "jemalloc/internal/jemalloc_preamble.h"
|
#include "jemalloc/internal/jemalloc_preamble.h"
|
||||||
|
|
||||||
#define SPIN_INITIALIZER {0U}
|
#define SPIN_INITIALIZER \
|
||||||
|
{ 0U }
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned iteration;
|
unsigned iteration;
|
||||||
|
|||||||
@@ -76,8 +76,9 @@ sz_psz2ind(size_t psz) {
|
|||||||
* SC_NGROUP. off_to_first_ps_rg begins from 1, instead of 0. e.g.
|
* SC_NGROUP. off_to_first_ps_rg begins from 1, instead of 0. e.g.
|
||||||
* off_to_first_ps_rg is 1 when psz is (PAGE * SC_NGROUP + 1).
|
* off_to_first_ps_rg is 1 when psz is (PAGE * SC_NGROUP + 1).
|
||||||
*/
|
*/
|
||||||
pszind_t off_to_first_ps_rg = (x < SC_LG_NGROUP + LG_PAGE) ?
|
pszind_t off_to_first_ps_rg = (x < SC_LG_NGROUP + LG_PAGE)
|
||||||
0 : x - (SC_LG_NGROUP + LG_PAGE);
|
? 0
|
||||||
|
: x - (SC_LG_NGROUP + LG_PAGE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Same as sc_s::lg_delta.
|
* Same as sc_s::lg_delta.
|
||||||
@@ -85,8 +86,9 @@ sz_psz2ind(size_t psz) {
|
|||||||
* for each increase in offset, it's multiplied by two.
|
* for each increase in offset, it's multiplied by two.
|
||||||
* Therefore, lg_delta = LG_PAGE + (off_to_first_ps_rg - 1).
|
* Therefore, lg_delta = LG_PAGE + (off_to_first_ps_rg - 1).
|
||||||
*/
|
*/
|
||||||
pszind_t lg_delta = (off_to_first_ps_rg == 0) ?
|
pszind_t lg_delta = (off_to_first_ps_rg == 0)
|
||||||
LG_PAGE : LG_PAGE + (off_to_first_ps_rg - 1);
|
? LG_PAGE
|
||||||
|
: LG_PAGE + (off_to_first_ps_rg - 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Let's write psz in binary, e.g. 0011 for 0x3, 0111 for 0x7.
|
* Let's write psz in binary, e.g. 0011 for 0x3, 0111 for 0x7.
|
||||||
@@ -149,8 +151,9 @@ sz_psz2u(size_t psz) {
|
|||||||
return SC_LARGE_MAXCLASS + PAGE;
|
return SC_LARGE_MAXCLASS + PAGE;
|
||||||
}
|
}
|
||||||
size_t x = lg_floor((psz << 1) - 1);
|
size_t x = lg_floor((psz << 1) - 1);
|
||||||
size_t lg_delta = (x < SC_LG_NGROUP + LG_PAGE + 1) ?
|
size_t lg_delta = (x < SC_LG_NGROUP + LG_PAGE + 1)
|
||||||
LG_PAGE : x - SC_LG_NGROUP - 1;
|
? LG_PAGE
|
||||||
|
: x - SC_LG_NGROUP - 1;
|
||||||
size_t delta = ZU(1) << lg_delta;
|
size_t delta = ZU(1) << lg_delta;
|
||||||
size_t delta_mask = delta - 1;
|
size_t delta_mask = delta - 1;
|
||||||
size_t usize = (psz + delta_mask) & ~delta_mask;
|
size_t usize = (psz + delta_mask) & ~delta_mask;
|
||||||
@@ -175,16 +178,18 @@ sz_size2index_compute_inline(size_t size) {
|
|||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
szind_t x = lg_floor((size << 1) - 1);
|
szind_t x = lg_floor((size << 1) - 1);
|
||||||
szind_t shift = (x < SC_LG_NGROUP + LG_QUANTUM) ? 0 :
|
szind_t shift = (x < SC_LG_NGROUP + LG_QUANTUM)
|
||||||
x - (SC_LG_NGROUP + LG_QUANTUM);
|
? 0
|
||||||
|
: x - (SC_LG_NGROUP + LG_QUANTUM);
|
||||||
szind_t grp = shift << SC_LG_NGROUP;
|
szind_t grp = shift << SC_LG_NGROUP;
|
||||||
|
|
||||||
szind_t lg_delta = (x < SC_LG_NGROUP + LG_QUANTUM + 1)
|
szind_t lg_delta = (x < SC_LG_NGROUP + LG_QUANTUM + 1)
|
||||||
? LG_QUANTUM : x - SC_LG_NGROUP - 1;
|
? LG_QUANTUM
|
||||||
|
: x - SC_LG_NGROUP - 1;
|
||||||
|
|
||||||
size_t delta_inverse_mask = ZU(-1) << lg_delta;
|
size_t delta_inverse_mask = ZU(-1) << lg_delta;
|
||||||
szind_t mod = ((((size-1) & delta_inverse_mask) >> lg_delta)) &
|
szind_t mod = ((((size - 1) & delta_inverse_mask) >> lg_delta))
|
||||||
((ZU(1) << SC_LG_NGROUP) - 1);
|
& ((ZU(1) << SC_LG_NGROUP) - 1);
|
||||||
|
|
||||||
szind_t index = SC_NTINY + grp + mod;
|
szind_t index = SC_NTINY + grp + mod;
|
||||||
return index;
|
return index;
|
||||||
@@ -228,12 +233,12 @@ sz_index2size_compute_inline(szind_t index) {
|
|||||||
{
|
{
|
||||||
size_t reduced_index = index - SC_NTINY;
|
size_t reduced_index = index - SC_NTINY;
|
||||||
size_t grp = reduced_index >> SC_LG_NGROUP;
|
size_t grp = reduced_index >> SC_LG_NGROUP;
|
||||||
size_t mod = reduced_index & ((ZU(1) << SC_LG_NGROUP) -
|
size_t mod = reduced_index & ((ZU(1) << SC_LG_NGROUP) - 1);
|
||||||
1);
|
|
||||||
|
|
||||||
size_t grp_size_mask = ~((!!grp) - 1);
|
size_t grp_size_mask = ~((!!grp) - 1);
|
||||||
size_t grp_size = ((ZU(1) << (LG_QUANTUM +
|
size_t grp_size = ((ZU(1) << (LG_QUANTUM + (SC_LG_NGROUP - 1)))
|
||||||
(SC_LG_NGROUP-1))) << grp) & grp_size_mask;
|
<< grp)
|
||||||
|
& grp_size_mask;
|
||||||
|
|
||||||
size_t shift = (grp == 0) ? 1 : grp;
|
size_t shift = (grp == 0) ? 1 : grp;
|
||||||
size_t lg_delta = shift + (LG_QUANTUM - 1);
|
size_t lg_delta = shift + (LG_QUANTUM - 1);
|
||||||
@@ -269,8 +274,8 @@ sz_index2size_unsafe(szind_t index) {
|
|||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE size_t
|
JEMALLOC_ALWAYS_INLINE size_t
|
||||||
sz_index2size(szind_t index) {
|
sz_index2size(szind_t index) {
|
||||||
assert(!sz_large_size_classes_disabled() ||
|
assert(!sz_large_size_classes_disabled()
|
||||||
index <= sz_size2index(USIZE_GROW_SLOW_THRESHOLD));
|
|| index <= sz_size2index(USIZE_GROW_SLOW_THRESHOLD));
|
||||||
size_t size = sz_index2size_unsafe(index);
|
size_t size = sz_index2size_unsafe(index);
|
||||||
/*
|
/*
|
||||||
* With large size classes disabled, the usize above
|
* With large size classes disabled, the usize above
|
||||||
@@ -285,8 +290,8 @@ sz_index2size(szind_t index) {
|
|||||||
* the size is no larger than USIZE_GROW_SLOW_THRESHOLD here
|
* the size is no larger than USIZE_GROW_SLOW_THRESHOLD here
|
||||||
* instead of SC_LARGE_MINCLASS.
|
* instead of SC_LARGE_MINCLASS.
|
||||||
*/
|
*/
|
||||||
assert(!sz_large_size_classes_disabled() ||
|
assert(!sz_large_size_classes_disabled()
|
||||||
size <= USIZE_GROW_SLOW_THRESHOLD);
|
|| size <= USIZE_GROW_SLOW_THRESHOLD);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,7 +316,8 @@ JEMALLOC_ALWAYS_INLINE size_t
|
|||||||
sz_s2u_compute_using_delta(size_t size) {
|
sz_s2u_compute_using_delta(size_t size) {
|
||||||
size_t x = lg_floor((size << 1) - 1);
|
size_t x = lg_floor((size << 1) - 1);
|
||||||
size_t lg_delta = (x < SC_LG_NGROUP + LG_QUANTUM + 1)
|
size_t lg_delta = (x < SC_LG_NGROUP + LG_QUANTUM + 1)
|
||||||
? LG_QUANTUM : x - SC_LG_NGROUP - 1;
|
? LG_QUANTUM
|
||||||
|
: x - SC_LG_NGROUP - 1;
|
||||||
size_t delta = ZU(1) << lg_delta;
|
size_t delta = ZU(1) << lg_delta;
|
||||||
size_t delta_mask = delta - 1;
|
size_t delta_mask = delta - 1;
|
||||||
size_t usize = (size + delta_mask) & ~delta_mask;
|
size_t usize = (size + delta_mask) & ~delta_mask;
|
||||||
@@ -331,8 +337,8 @@ sz_s2u_compute(size_t size) {
|
|||||||
if (size <= (ZU(1) << SC_LG_TINY_MAXCLASS)) {
|
if (size <= (ZU(1) << SC_LG_TINY_MAXCLASS)) {
|
||||||
size_t lg_tmin = SC_LG_TINY_MAXCLASS - SC_NTINY + 1;
|
size_t lg_tmin = SC_LG_TINY_MAXCLASS - SC_NTINY + 1;
|
||||||
size_t lg_ceil = lg_floor(pow2_ceil_zu(size));
|
size_t lg_ceil = lg_floor(pow2_ceil_zu(size));
|
||||||
return (lg_ceil < lg_tmin ? (ZU(1) << lg_tmin) :
|
return (lg_ceil < lg_tmin ? (ZU(1) << lg_tmin)
|
||||||
(ZU(1) << lg_ceil));
|
: (ZU(1) << lg_ceil));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (size <= SC_SMALL_MAXCLASS || !sz_large_size_classes_disabled()) {
|
if (size <= SC_SMALL_MAXCLASS || !sz_large_size_classes_disabled()) {
|
||||||
|
|||||||
@@ -56,13 +56,13 @@ void tcache_bin_flush_large(tsd_t *tsd, tcache_t *tcache,
|
|||||||
cache_bin_t *cache_bin, szind_t binind, unsigned rem);
|
cache_bin_t *cache_bin, szind_t binind, unsigned rem);
|
||||||
void tcache_bin_flush_stashed(tsd_t *tsd, tcache_t *tcache,
|
void tcache_bin_flush_stashed(tsd_t *tsd, tcache_t *tcache,
|
||||||
cache_bin_t *cache_bin, szind_t binind, bool is_small);
|
cache_bin_t *cache_bin, szind_t binind, bool is_small);
|
||||||
bool tcache_bin_info_default_init(const char *bin_settings_segment_cur,
|
bool tcache_bin_info_default_init(
|
||||||
size_t len_left);
|
const char *bin_settings_segment_cur, size_t len_left);
|
||||||
bool tcache_bins_ncached_max_write(tsd_t *tsd, char *settings, size_t len);
|
bool tcache_bins_ncached_max_write(tsd_t *tsd, char *settings, size_t len);
|
||||||
bool tcache_bin_ncached_max_read(tsd_t *tsd, size_t bin_size,
|
bool tcache_bin_ncached_max_read(
|
||||||
cache_bin_sz_t *ncached_max);
|
tsd_t *tsd, size_t bin_size, cache_bin_sz_t *ncached_max);
|
||||||
void tcache_arena_reassociate(tsdn_t *tsdn, tcache_slow_t *tcache_slow,
|
void tcache_arena_reassociate(
|
||||||
tcache_t *tcache, arena_t *arena);
|
tsdn_t *tsdn, tcache_slow_t *tcache_slow, tcache_t *tcache, arena_t *arena);
|
||||||
tcache_t *tcache_create_explicit(tsd_t *tsd);
|
tcache_t *tcache_create_explicit(tsd_t *tsd);
|
||||||
void thread_tcache_max_set(tsd_t *tsd, size_t tcache_max);
|
void thread_tcache_max_set(tsd_t *tsd, size_t tcache_max);
|
||||||
void tcache_cleanup(tsd_t *tsd);
|
void tcache_cleanup(tsd_t *tsd);
|
||||||
@@ -71,8 +71,8 @@ bool tcaches_create(tsd_t *tsd, base_t *base, unsigned *r_ind);
|
|||||||
void tcaches_flush(tsd_t *tsd, unsigned ind);
|
void tcaches_flush(tsd_t *tsd, unsigned ind);
|
||||||
void tcaches_destroy(tsd_t *tsd, unsigned ind);
|
void tcaches_destroy(tsd_t *tsd, unsigned ind);
|
||||||
bool tcache_boot(tsdn_t *tsdn, base_t *base);
|
bool tcache_boot(tsdn_t *tsdn, base_t *base);
|
||||||
void tcache_arena_associate(tsdn_t *tsdn, tcache_slow_t *tcache_slow,
|
void tcache_arena_associate(
|
||||||
tcache_t *tcache, arena_t *arena);
|
tsdn_t *tsdn, tcache_slow_t *tcache_slow, tcache_t *tcache, arena_t *arena);
|
||||||
void tcache_prefork(tsdn_t *tsdn);
|
void tcache_prefork(tsdn_t *tsdn);
|
||||||
void tcache_postfork_parent(tsdn_t *tsdn);
|
void tcache_postfork_parent(tsdn_t *tsdn);
|
||||||
void tcache_postfork_child(tsdn_t *tsdn);
|
void tcache_postfork_child(tsdn_t *tsdn);
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ tcache_max_set(tcache_slow_t *tcache_slow, size_t tcache_max) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
tcache_bin_settings_backup(tcache_t *tcache,
|
tcache_bin_settings_backup(
|
||||||
cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX]) {
|
tcache_t *tcache, cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX]) {
|
||||||
for (unsigned i = 0; i < TCACHE_NBINS_MAX; i++) {
|
for (unsigned i = 0; i < TCACHE_NBINS_MAX; i++) {
|
||||||
cache_bin_info_init(&tcache_bin_info[i],
|
cache_bin_info_init(&tcache_bin_info[i],
|
||||||
cache_bin_ncached_max_get_unsafe(&tcache->bins[i]));
|
cache_bin_ncached_max_get_unsafe(&tcache->bins[i]));
|
||||||
@@ -51,8 +51,7 @@ tcache_bin_settings_backup(tcache_t *tcache,
|
|||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE bool
|
JEMALLOC_ALWAYS_INLINE bool
|
||||||
tcache_bin_disabled(szind_t ind, cache_bin_t *bin,
|
tcache_bin_disabled(szind_t ind, cache_bin_t *bin, tcache_slow_t *tcache_slow) {
|
||||||
tcache_slow_t *tcache_slow) {
|
|
||||||
assert(bin != NULL);
|
assert(bin != NULL);
|
||||||
assert(ind < TCACHE_NBINS_MAX);
|
assert(ind < TCACHE_NBINS_MAX);
|
||||||
bool disabled = cache_bin_disabled(bin);
|
bool disabled = cache_bin_disabled(bin);
|
||||||
@@ -88,8 +87,8 @@ tcache_bin_disabled(szind_t ind, cache_bin_t *bin,
|
|||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void *
|
JEMALLOC_ALWAYS_INLINE void *
|
||||||
tcache_alloc_small(tsd_t *tsd, arena_t *arena, tcache_t *tcache,
|
tcache_alloc_small(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size,
|
||||||
size_t size, szind_t binind, bool zero, bool slow_path) {
|
szind_t binind, bool zero, bool slow_path) {
|
||||||
void *ret;
|
void *ret;
|
||||||
bool tcache_success;
|
bool tcache_success;
|
||||||
|
|
||||||
@@ -103,8 +102,8 @@ tcache_alloc_small(tsd_t *tsd, arena_t *arena, tcache_t *tcache,
|
|||||||
if (unlikely(arena == NULL)) {
|
if (unlikely(arena == NULL)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (unlikely(tcache_bin_disabled(binind, bin,
|
if (unlikely(tcache_bin_disabled(
|
||||||
tcache->tcache_slow))) {
|
binind, bin, tcache->tcache_slow))) {
|
||||||
/* stats and zero are handled directly by the arena. */
|
/* stats and zero are handled directly by the arena. */
|
||||||
return arena_malloc_hard(tsd_tsdn(tsd), arena, size,
|
return arena_malloc_hard(tsd_tsdn(tsd), arena, size,
|
||||||
binind, zero, /* slab */ true);
|
binind, zero, /* slab */ true);
|
||||||
@@ -112,8 +111,8 @@ tcache_alloc_small(tsd_t *tsd, arena_t *arena, tcache_t *tcache,
|
|||||||
tcache_bin_flush_stashed(tsd, tcache, bin, binind,
|
tcache_bin_flush_stashed(tsd, tcache, bin, binind,
|
||||||
/* is_small */ true);
|
/* is_small */ true);
|
||||||
|
|
||||||
ret = tcache_alloc_small_hard(tsd_tsdn(tsd), arena, tcache,
|
ret = tcache_alloc_small_hard(tsd_tsdn(tsd), arena, tcache, bin,
|
||||||
bin, binind, &tcache_hard_success);
|
binind, &tcache_hard_success);
|
||||||
if (tcache_hard_success == false) {
|
if (tcache_hard_success == false) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -138,8 +137,8 @@ tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size,
|
|||||||
bool tcache_success;
|
bool tcache_success;
|
||||||
|
|
||||||
cache_bin_t *bin = &tcache->bins[binind];
|
cache_bin_t *bin = &tcache->bins[binind];
|
||||||
assert(binind >= SC_NBINS &&
|
assert(binind >= SC_NBINS
|
||||||
!tcache_bin_disabled(binind, bin, tcache->tcache_slow));
|
&& !tcache_bin_disabled(binind, bin, tcache->tcache_slow));
|
||||||
ret = cache_bin_alloc(bin, &tcache_success);
|
ret = cache_bin_alloc(bin, &tcache_success);
|
||||||
assert(tcache_success == (ret != NULL));
|
assert(tcache_success == (ret != NULL));
|
||||||
if (unlikely(!tcache_success)) {
|
if (unlikely(!tcache_success)) {
|
||||||
@@ -174,8 +173,8 @@ tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
tcache_dalloc_small(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind,
|
tcache_dalloc_small(
|
||||||
bool slow_path) {
|
tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, bool slow_path) {
|
||||||
assert(tcache_salloc(tsd_tsdn(tsd), ptr) <= SC_SMALL_MAXCLASS);
|
assert(tcache_salloc(tsd_tsdn(tsd), ptr) <= SC_SMALL_MAXCLASS);
|
||||||
|
|
||||||
cache_bin_t *bin = &tcache->bins[binind];
|
cache_bin_t *bin = &tcache->bins[binind];
|
||||||
@@ -195,8 +194,8 @@ tcache_dalloc_small(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(!cache_bin_dalloc_easy(bin, ptr))) {
|
if (unlikely(!cache_bin_dalloc_easy(bin, ptr))) {
|
||||||
if (unlikely(tcache_bin_disabled(binind, bin,
|
if (unlikely(tcache_bin_disabled(
|
||||||
tcache->tcache_slow))) {
|
binind, bin, tcache->tcache_slow))) {
|
||||||
arena_dalloc_small(tsd_tsdn(tsd), ptr);
|
arena_dalloc_small(tsd_tsdn(tsd), ptr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -209,19 +208,18 @@ tcache_dalloc_small(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind,
|
|||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
tcache_dalloc_large(tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind,
|
tcache_dalloc_large(
|
||||||
bool slow_path) {
|
tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, bool slow_path) {
|
||||||
|
|
||||||
assert(tcache_salloc(tsd_tsdn(tsd), ptr) > SC_SMALL_MAXCLASS);
|
assert(tcache_salloc(tsd_tsdn(tsd), ptr) > SC_SMALL_MAXCLASS);
|
||||||
assert(tcache_salloc(tsd_tsdn(tsd), ptr) <=
|
assert(tcache_salloc(tsd_tsdn(tsd), ptr)
|
||||||
tcache_max_get(tcache->tcache_slow));
|
<= tcache_max_get(tcache->tcache_slow));
|
||||||
assert(!tcache_bin_disabled(binind, &tcache->bins[binind],
|
assert(!tcache_bin_disabled(
|
||||||
tcache->tcache_slow));
|
binind, &tcache->bins[binind], tcache->tcache_slow));
|
||||||
|
|
||||||
cache_bin_t *bin = &tcache->bins[binind];
|
cache_bin_t *bin = &tcache->bins[binind];
|
||||||
if (unlikely(!cache_bin_dalloc_easy(bin, ptr))) {
|
if (unlikely(!cache_bin_dalloc_easy(bin, ptr))) {
|
||||||
unsigned remain = cache_bin_ncached_max_get(bin) >>
|
unsigned remain = cache_bin_ncached_max_get(bin)
|
||||||
opt_lg_tcache_flush_large_div;
|
>> opt_lg_tcache_flush_large_div;
|
||||||
tcache_bin_flush_large(tsd, tcache, bin, binind, remain);
|
tcache_bin_flush_large(tsd, tcache, bin, binind, remain);
|
||||||
bool ret = cache_bin_dalloc_easy(bin, ptr);
|
bool ret = cache_bin_dalloc_easy(bin, ptr);
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|||||||
@@ -9,8 +9,12 @@ typedef struct tcache_s tcache_t;
|
|||||||
typedef struct tcaches_s tcaches_t;
|
typedef struct tcaches_s tcaches_t;
|
||||||
|
|
||||||
/* Used in TSD static initializer only. Real init in tsd_tcache_data_init(). */
|
/* Used in TSD static initializer only. Real init in tsd_tcache_data_init(). */
|
||||||
#define TCACHE_ZERO_INITIALIZER {0}
|
#define TCACHE_ZERO_INITIALIZER \
|
||||||
#define TCACHE_SLOW_ZERO_INITIALIZER {{0}}
|
{ 0 }
|
||||||
|
#define TCACHE_SLOW_ZERO_INITIALIZER \
|
||||||
|
{ \
|
||||||
|
{ 0 } \
|
||||||
|
}
|
||||||
|
|
||||||
/* Used in TSD static initializer only. Will be initialized to opt_tcache. */
|
/* Used in TSD static initializer only. Will be initialized to opt_tcache. */
|
||||||
#define TCACHE_ENABLED_ZERO_INITIALIZER false
|
#define TCACHE_ENABLED_ZERO_INITIALIZER false
|
||||||
@@ -21,8 +25,10 @@ typedef struct tcaches_s tcaches_t;
|
|||||||
|
|
||||||
#define TCACHE_LG_MAXCLASS_LIMIT LG_USIZE_GROW_SLOW_THRESHOLD
|
#define TCACHE_LG_MAXCLASS_LIMIT LG_USIZE_GROW_SLOW_THRESHOLD
|
||||||
#define TCACHE_MAXCLASS_LIMIT ((size_t)1 << TCACHE_LG_MAXCLASS_LIMIT)
|
#define TCACHE_MAXCLASS_LIMIT ((size_t)1 << TCACHE_LG_MAXCLASS_LIMIT)
|
||||||
#define TCACHE_NBINS_MAX (SC_NBINS + SC_NGROUP * \
|
#define TCACHE_NBINS_MAX \
|
||||||
(TCACHE_LG_MAXCLASS_LIMIT - SC_LG_LARGE_MINCLASS) + 1)
|
(SC_NBINS \
|
||||||
|
+ SC_NGROUP * (TCACHE_LG_MAXCLASS_LIMIT - SC_LG_LARGE_MINCLASS) \
|
||||||
|
+ 1)
|
||||||
#define TCACHE_GC_NEIGHBOR_LIMIT ((uintptr_t)1 << 21) /* 2M */
|
#define TCACHE_GC_NEIGHBOR_LIMIT ((uintptr_t)1 << 21) /* 2M */
|
||||||
#define TCACHE_GC_INTERVAL_NS ((uint64_t)10 * KQU(1000000)) /* 10ms */
|
#define TCACHE_GC_INTERVAL_NS ((uint64_t)10 * KQU(1000000)) /* 10ms */
|
||||||
#define TCACHE_GC_SMALL_NBINS_MAX ((SC_NBINS > 8) ? (SC_NBINS >> 3) : 1)
|
#define TCACHE_GC_SMALL_NBINS_MAX ((SC_NBINS > 8) ? (SC_NBINS >> 3) : 1)
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ extern JEMALLOC_EXPORT void (*test_hooks_arena_new_hook)(void);
|
|||||||
extern JEMALLOC_EXPORT void (*test_hooks_libc_hook)(void);
|
extern JEMALLOC_EXPORT void (*test_hooks_libc_hook)(void);
|
||||||
|
|
||||||
#if defined(JEMALLOC_JET) || defined(JEMALLOC_UNIT_TEST)
|
#if defined(JEMALLOC_JET) || defined(JEMALLOC_UNIT_TEST)
|
||||||
# define JEMALLOC_TEST_HOOK(fn, hook) ((void)(hook != NULL && (hook(), 0)), fn)
|
# define JEMALLOC_TEST_HOOK(fn, hook) \
|
||||||
|
((void)(hook != NULL && (hook(), 0)), fn)
|
||||||
|
|
||||||
# define open JEMALLOC_TEST_HOOK(open, test_hooks_libc_hook)
|
# define open JEMALLOC_TEST_HOOK(open, test_hooks_libc_hook)
|
||||||
# define read JEMALLOC_TEST_HOOK(read, test_hooks_libc_hook)
|
# define read JEMALLOC_TEST_HOOK(read, test_hooks_libc_hook)
|
||||||
@@ -15,12 +16,13 @@ extern JEMALLOC_EXPORT void (*test_hooks_libc_hook)(void);
|
|||||||
# define readlink JEMALLOC_TEST_HOOK(readlink, test_hooks_libc_hook)
|
# define readlink JEMALLOC_TEST_HOOK(readlink, test_hooks_libc_hook)
|
||||||
# define close JEMALLOC_TEST_HOOK(close, test_hooks_libc_hook)
|
# define close JEMALLOC_TEST_HOOK(close, test_hooks_libc_hook)
|
||||||
# define creat JEMALLOC_TEST_HOOK(creat, test_hooks_libc_hook)
|
# define creat JEMALLOC_TEST_HOOK(creat, test_hooks_libc_hook)
|
||||||
# define secure_getenv JEMALLOC_TEST_HOOK(secure_getenv, test_hooks_libc_hook)
|
# define secure_getenv \
|
||||||
|
JEMALLOC_TEST_HOOK(secure_getenv, test_hooks_libc_hook)
|
||||||
/* Note that this is undef'd and re-define'd in src/prof.c. */
|
/* Note that this is undef'd and re-define'd in src/prof.c. */
|
||||||
# define _Unwind_Backtrace JEMALLOC_TEST_HOOK(_Unwind_Backtrace, test_hooks_libc_hook)
|
# define _Unwind_Backtrace \
|
||||||
|
JEMALLOC_TEST_HOOK(_Unwind_Backtrace, test_hooks_libc_hook)
|
||||||
#else
|
#else
|
||||||
# define JEMALLOC_TEST_HOOK(fn, hook) fn
|
# define JEMALLOC_TEST_HOOK(fn, hook) fn
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_TEST_HOOKS_H */
|
#endif /* JEMALLOC_INTERNAL_TEST_HOOKS_H */
|
||||||
|
|||||||
@@ -48,8 +48,7 @@ void te_assert_invariants_debug(tsd_t *tsd);
|
|||||||
void te_event_trigger(tsd_t *tsd, te_ctx_t *ctx);
|
void te_event_trigger(tsd_t *tsd, te_ctx_t *ctx);
|
||||||
void te_recompute_fast_threshold(tsd_t *tsd);
|
void te_recompute_fast_threshold(tsd_t *tsd);
|
||||||
void tsd_te_init(tsd_t *tsd);
|
void tsd_te_init(tsd_t *tsd);
|
||||||
void te_adjust_thresholds_helper(tsd_t *tsd, te_ctx_t *ctx,
|
void te_adjust_thresholds_helper(tsd_t *tsd, te_ctx_t *ctx, uint64_t wait);
|
||||||
uint64_t wait);
|
|
||||||
|
|
||||||
/* List of all thread event counters. */
|
/* List of all thread event counters. */
|
||||||
#define ITERATE_OVER_ALL_COUNTERS \
|
#define ITERATE_OVER_ALL_COUNTERS \
|
||||||
@@ -60,8 +59,7 @@ void te_adjust_thresholds_helper(tsd_t *tsd, te_ctx_t *ctx,
|
|||||||
|
|
||||||
/* Getters directly wrap TSD getters. */
|
/* Getters directly wrap TSD getters. */
|
||||||
#define C(counter) \
|
#define C(counter) \
|
||||||
JEMALLOC_ALWAYS_INLINE uint64_t \
|
JEMALLOC_ALWAYS_INLINE uint64_t counter##_get(tsd_t *tsd) { \
|
||||||
counter##_get(tsd_t *tsd) { \
|
|
||||||
return tsd_##counter##_get(tsd); \
|
return tsd_##counter##_get(tsd); \
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,8 +74,7 @@ ITERATE_OVER_ALL_COUNTERS
|
|||||||
* allocation call.
|
* allocation call.
|
||||||
*/
|
*/
|
||||||
#define C(counter) \
|
#define C(counter) \
|
||||||
JEMALLOC_ALWAYS_INLINE void \
|
JEMALLOC_ALWAYS_INLINE void counter##_set(tsd_t *tsd, uint64_t v) { \
|
||||||
counter##_set(tsd_t *tsd, uint64_t v) { \
|
|
||||||
*tsd_##counter##p_get(tsd) = v; \
|
*tsd_##counter##p_get(tsd) = v; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -129,7 +129,8 @@ struct ticker_geom_s {
|
|||||||
* the behavior over long periods of time rather than the exact timing of the
|
* the behavior over long periods of time rather than the exact timing of the
|
||||||
* initial ticks.
|
* initial ticks.
|
||||||
*/
|
*/
|
||||||
#define TICKER_GEOM_INIT(nticks) {nticks, nticks}
|
#define TICKER_GEOM_INIT(nticks) \
|
||||||
|
{ nticks, nticks }
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
ticker_geom_init(ticker_geom_t *ticker, int32_t nticks) {
|
ticker_geom_init(ticker_geom_t *ticker, int32_t nticks) {
|
||||||
@@ -155,17 +156,16 @@ ticker_geom_read(const ticker_geom_t *ticker) {
|
|||||||
JEMALLOC_NOINLINE
|
JEMALLOC_NOINLINE
|
||||||
#endif
|
#endif
|
||||||
static bool
|
static bool
|
||||||
ticker_geom_fixup(ticker_geom_t *ticker, uint64_t *prng_state,
|
ticker_geom_fixup(
|
||||||
bool delay_trigger) {
|
ticker_geom_t *ticker, uint64_t *prng_state, bool delay_trigger) {
|
||||||
if (delay_trigger) {
|
if (delay_trigger) {
|
||||||
ticker->tick = 0;
|
ticker->tick = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t idx = prng_lg_range_u64(prng_state, TICKER_GEOM_NBITS);
|
uint64_t idx = prng_lg_range_u64(prng_state, TICKER_GEOM_NBITS);
|
||||||
ticker->tick = (uint32_t)(
|
ticker->tick = (uint32_t)((uint64_t)ticker->nticks
|
||||||
(uint64_t)ticker->nticks * (uint64_t)ticker_geom_table[idx]
|
* (uint64_t)ticker_geom_table[idx] / (uint64_t)TICKER_GEOM_MUL);
|
||||||
/ (uint64_t)TICKER_GEOM_MUL);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -181,8 +181,8 @@ ticker_geom_ticks(ticker_geom_t *ticker, uint64_t *prng_state, int32_t nticks,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
ticker_geom_tick(ticker_geom_t *ticker, uint64_t *prng_state,
|
ticker_geom_tick(
|
||||||
bool delay_trigger) {
|
ticker_geom_t *ticker, uint64_t *prng_state, bool delay_trigger) {
|
||||||
return ticker_geom_ticks(ticker, prng_state, 1, delay_trigger);
|
return ticker_geom_ticks(ticker, prng_state, 1, delay_trigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,8 +23,7 @@
|
|||||||
* initialization and cleanup.
|
* initialization and cleanup.
|
||||||
*/
|
*/
|
||||||
#define O(n, t, nt) \
|
#define O(n, t, nt) \
|
||||||
JEMALLOC_ALWAYS_INLINE t * \
|
JEMALLOC_ALWAYS_INLINE t *tsd_##n##p_get_unsafe(tsd_t *tsd) { \
|
||||||
tsd_##n##p_get_unsafe(tsd_t *tsd) { \
|
|
||||||
return &tsd->TSD_MANGLE(n); \
|
return &tsd->TSD_MANGLE(n); \
|
||||||
}
|
}
|
||||||
TSD_DATA_SLOW
|
TSD_DATA_SLOW
|
||||||
@@ -60,8 +59,7 @@ TSD_DATA_SLOWER
|
|||||||
* isn't NULL), or NULL (if tsdn is NULL), cast to the nullable pointer type.
|
* isn't NULL), or NULL (if tsdn is NULL), cast to the nullable pointer type.
|
||||||
*/
|
*/
|
||||||
#define O(n, t, nt) \
|
#define O(n, t, nt) \
|
||||||
JEMALLOC_ALWAYS_INLINE nt * \
|
JEMALLOC_ALWAYS_INLINE nt *tsdn_##n##p_get(tsdn_t *tsdn) { \
|
||||||
tsdn_##n##p_get(tsdn_t *tsdn) { \
|
|
||||||
if (tsdn_null(tsdn)) { \
|
if (tsdn_null(tsdn)) { \
|
||||||
return NULL; \
|
return NULL; \
|
||||||
} \
|
} \
|
||||||
@@ -75,8 +73,7 @@ TSD_DATA_SLOWER
|
|||||||
|
|
||||||
/* tsd_foo_get(tsd) returns the value of the thread-local instance of foo. */
|
/* tsd_foo_get(tsd) returns the value of the thread-local instance of foo. */
|
||||||
#define O(n, t, nt) \
|
#define O(n, t, nt) \
|
||||||
JEMALLOC_ALWAYS_INLINE t \
|
JEMALLOC_ALWAYS_INLINE t tsd_##n##_get(tsd_t *tsd) { \
|
||||||
tsd_##n##_get(tsd_t *tsd) { \
|
|
||||||
return *tsd_##n##p_get(tsd); \
|
return *tsd_##n##p_get(tsd); \
|
||||||
}
|
}
|
||||||
TSD_DATA_SLOW
|
TSD_DATA_SLOW
|
||||||
@@ -86,10 +83,9 @@ TSD_DATA_SLOWER
|
|||||||
|
|
||||||
/* tsd_foo_set(tsd, val) updates the thread-local instance of foo to be val. */
|
/* tsd_foo_set(tsd, val) updates the thread-local instance of foo to be val. */
|
||||||
#define O(n, t, nt) \
|
#define O(n, t, nt) \
|
||||||
JEMALLOC_ALWAYS_INLINE void \
|
JEMALLOC_ALWAYS_INLINE void tsd_##n##_set(tsd_t *tsd, t val) { \
|
||||||
tsd_##n##_set(tsd_t *tsd, t val) { \
|
assert(tsd_state_get(tsd) != tsd_state_reincarnated \
|
||||||
assert(tsd_state_get(tsd) != tsd_state_reincarnated && \
|
&& tsd_state_get(tsd) != tsd_state_minimal_initialized); \
|
||||||
tsd_state_get(tsd) != tsd_state_minimal_initialized); \
|
|
||||||
*tsd_##n##p_get(tsd) = val; \
|
*tsd_##n##p_get(tsd) = val; \
|
||||||
}
|
}
|
||||||
TSD_DATA_SLOW
|
TSD_DATA_SLOW
|
||||||
@@ -104,8 +100,8 @@ tsd_assert_fast(tsd_t *tsd) {
|
|||||||
* counters; it's not in general possible to ensure that they won't
|
* counters; it's not in general possible to ensure that they won't
|
||||||
* change asynchronously from underneath us.
|
* change asynchronously from underneath us.
|
||||||
*/
|
*/
|
||||||
assert(!malloc_slow && tsd_tcache_enabled_get(tsd) &&
|
assert(!malloc_slow && tsd_tcache_enabled_get(tsd)
|
||||||
tsd_reentrancy_level_get(tsd) == 0);
|
&& tsd_reentrancy_level_get(tsd) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE bool
|
JEMALLOC_ALWAYS_INLINE bool
|
||||||
@@ -194,8 +190,8 @@ tsdn_rtree_ctx(tsdn_t *tsdn, rtree_ctx_t *fallback) {
|
|||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
tsd_state_nocleanup(tsd_t *tsd) {
|
tsd_state_nocleanup(tsd_t *tsd) {
|
||||||
return tsd_state_get(tsd) == tsd_state_reincarnated ||
|
return tsd_state_get(tsd) == tsd_state_reincarnated
|
||||||
tsd_state_get(tsd) == tsd_state_minimal_initialized;
|
|| tsd_state_get(tsd) == tsd_state_minimal_initialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -23,8 +23,7 @@ typedef struct {
|
|||||||
tsd_t val;
|
tsd_t val;
|
||||||
} tsd_wrapper_t;
|
} tsd_wrapper_t;
|
||||||
|
|
||||||
void *tsd_init_check_recursion(tsd_init_head_t *head,
|
void *tsd_init_check_recursion(tsd_init_head_t *head, tsd_init_block_t *block);
|
||||||
tsd_init_block_t *block);
|
|
||||||
void tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block);
|
void tsd_init_finish(tsd_init_head_t *head, tsd_init_block_t *block);
|
||||||
|
|
||||||
extern pthread_key_t tsd_tsd;
|
extern pthread_key_t tsd_tsd;
|
||||||
@@ -42,8 +41,8 @@ tsd_cleanup_wrapper(void *arg) {
|
|||||||
tsd_cleanup(&wrapper->val);
|
tsd_cleanup(&wrapper->val);
|
||||||
if (wrapper->initialized) {
|
if (wrapper->initialized) {
|
||||||
/* Trigger another cleanup round. */
|
/* Trigger another cleanup round. */
|
||||||
if (pthread_setspecific(tsd_tsd, (void *)wrapper) != 0)
|
if (pthread_setspecific(tsd_tsd, (void *)wrapper)
|
||||||
{
|
!= 0) {
|
||||||
malloc_write("<jemalloc>: Error setting TSD\n");
|
malloc_write("<jemalloc>: Error setting TSD\n");
|
||||||
if (opt_abort) {
|
if (opt_abort) {
|
||||||
abort();
|
abort();
|
||||||
@@ -78,13 +77,13 @@ tsd_wrapper_get(bool init) {
|
|||||||
|
|
||||||
if (init && unlikely(wrapper == NULL)) {
|
if (init && unlikely(wrapper == NULL)) {
|
||||||
tsd_init_block_t block;
|
tsd_init_block_t block;
|
||||||
wrapper = (tsd_wrapper_t *)
|
wrapper = (tsd_wrapper_t *)tsd_init_check_recursion(
|
||||||
tsd_init_check_recursion(&tsd_init_head, &block);
|
&tsd_init_head, &block);
|
||||||
if (wrapper) {
|
if (wrapper) {
|
||||||
return wrapper;
|
return wrapper;
|
||||||
}
|
}
|
||||||
wrapper = (tsd_wrapper_t *)
|
wrapper = (tsd_wrapper_t *)malloc_tsd_malloc(
|
||||||
malloc_tsd_malloc(sizeof(tsd_wrapper_t));
|
sizeof(tsd_wrapper_t));
|
||||||
block.data = (void *)wrapper;
|
block.data = (void *)wrapper;
|
||||||
if (wrapper == NULL) {
|
if (wrapper == NULL) {
|
||||||
malloc_write("<jemalloc>: Error allocating TSD\n");
|
malloc_write("<jemalloc>: Error allocating TSD\n");
|
||||||
@@ -108,8 +107,8 @@ tsd_boot0(void) {
|
|||||||
tsd_wrapper_t *wrapper;
|
tsd_wrapper_t *wrapper;
|
||||||
tsd_init_block_t block;
|
tsd_init_block_t block;
|
||||||
|
|
||||||
wrapper = (tsd_wrapper_t *)
|
wrapper = (tsd_wrapper_t *)tsd_init_check_recursion(
|
||||||
tsd_init_check_recursion(&tsd_init_head, &block);
|
&tsd_init_head, &block);
|
||||||
if (wrapper) {
|
if (wrapper) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,29 +91,21 @@ typedef ql_elm(tsd_t) tsd_link_t;
|
|||||||
|
|
||||||
#define TSD_DATA_SLOW_INITIALIZER \
|
#define TSD_DATA_SLOW_INITIALIZER \
|
||||||
/* tcache_enabled */ TCACHE_ENABLED_ZERO_INITIALIZER, \
|
/* tcache_enabled */ TCACHE_ENABLED_ZERO_INITIALIZER, \
|
||||||
/* reentrancy_level */ 0, \
|
/* reentrancy_level */ 0, /* min_init_state_nfetched */ 0, \
|
||||||
/* min_init_state_nfetched */ 0, \
|
|
||||||
/* thread_allocated_last_event */ 0, \
|
/* thread_allocated_last_event */ 0, \
|
||||||
/* thread_allocated_next_event */ 0, \
|
/* thread_allocated_next_event */ 0, \
|
||||||
/* thread_deallocated_last_event */ 0, \
|
/* thread_deallocated_last_event */ 0, \
|
||||||
/* thread_deallocated_next_event */ 0, \
|
/* thread_deallocated_next_event */ 0, \
|
||||||
/* te_data */ TE_DATA_INITIALIZER, \
|
/* te_data */ TE_DATA_INITIALIZER, /* prof_sample_last_event */ 0, \
|
||||||
/* prof_sample_last_event */ 0, \
|
/* stats_interval_last_event */ 0, /* prof_tdata */ NULL, \
|
||||||
/* stats_interval_last_event */ 0, \
|
/* prng_state */ 0, /* san_extents_until_guard_small */ 0, \
|
||||||
/* prof_tdata */ NULL, \
|
/* san_extents_until_guard_large */ 0, /* iarena */ NULL, \
|
||||||
/* prng_state */ 0, \
|
/* arena */ NULL, /* arena_decay_ticker */ \
|
||||||
/* san_extents_until_guard_small */ 0, \
|
|
||||||
/* san_extents_until_guard_large */ 0, \
|
|
||||||
/* iarena */ NULL, \
|
|
||||||
/* arena */ NULL, \
|
|
||||||
/* arena_decay_ticker */ \
|
|
||||||
TICKER_GEOM_INIT(ARENA_DECAY_NTICKS_PER_UPDATE), \
|
TICKER_GEOM_INIT(ARENA_DECAY_NTICKS_PER_UPDATE), \
|
||||||
/* sec_shard */ (uint8_t) - 1, \
|
/* sec_shard */ (uint8_t) - 1, \
|
||||||
/* binshards */ TSD_BINSHARDS_ZERO_INITIALIZER, \
|
/* binshards */ TSD_BINSHARDS_ZERO_INITIALIZER, \
|
||||||
/* tsd_link */ {NULL}, \
|
/* tsd_link */ {NULL}, /* in_hook */ false, \
|
||||||
/* in_hook */ false, \
|
/* peak */ PEAK_INITIALIZER, /* activity_callback_thunk */ \
|
||||||
/* peak */ PEAK_INITIALIZER, \
|
|
||||||
/* activity_callback_thunk */ \
|
|
||||||
ACTIVITY_CALLBACK_THUNK_INITIALIZER, \
|
ACTIVITY_CALLBACK_THUNK_INITIALIZER, \
|
||||||
/* tcache_slow */ TCACHE_SLOW_ZERO_INITIALIZER, \
|
/* tcache_slow */ TCACHE_SLOW_ZERO_INITIALIZER, \
|
||||||
/* rtree_ctx */ RTREE_CTX_INITIALIZER,
|
/* rtree_ctx */ RTREE_CTX_INITIALIZER,
|
||||||
@@ -127,8 +119,7 @@ typedef ql_elm(tsd_t) tsd_link_t;
|
|||||||
O(tcache, tcache_t, tcache_t)
|
O(tcache, tcache_t, tcache_t)
|
||||||
|
|
||||||
#define TSD_DATA_FAST_INITIALIZER \
|
#define TSD_DATA_FAST_INITIALIZER \
|
||||||
/* thread_allocated */ 0, \
|
/* thread_allocated */ 0, /* thread_allocated_next_event_fast */ 0, \
|
||||||
/* thread_allocated_next_event_fast */ 0, \
|
|
||||||
/* thread_deallocated */ 0, \
|
/* thread_deallocated */ 0, \
|
||||||
/* thread_deallocated_next_event_fast */ 0, \
|
/* thread_deallocated_next_event_fast */ 0, \
|
||||||
/* tcache */ TCACHE_ZERO_INITIALIZER,
|
/* tcache */ TCACHE_ZERO_INITIALIZER,
|
||||||
@@ -142,12 +133,11 @@ typedef ql_elm(tsd_t) tsd_link_t;
|
|||||||
/* witness */ WITNESS_TSD_INITIALIZER \
|
/* witness */ WITNESS_TSD_INITIALIZER \
|
||||||
/* test data */ MALLOC_TEST_TSD_INITIALIZER
|
/* test data */ MALLOC_TEST_TSD_INITIALIZER
|
||||||
|
|
||||||
|
#define TSD_INITIALIZER \
|
||||||
#define TSD_INITIALIZER { \
|
{ \
|
||||||
TSD_DATA_SLOW_INITIALIZER \
|
TSD_DATA_SLOW_INITIALIZER \
|
||||||
/* state */ ATOMIC_INIT(tsd_state_uninitialized), \
|
/* state */ ATOMIC_INIT(tsd_state_uninitialized), \
|
||||||
TSD_DATA_FAST_INITIALIZER \
|
TSD_DATA_FAST_INITIALIZER TSD_DATA_SLOWER_INITIALIZER \
|
||||||
TSD_DATA_SLOWER_INITIALIZER \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(JEMALLOC_MALLOC_THREAD_CLEANUP) || defined(_WIN32)
|
#if defined(JEMALLOC_MALLOC_THREAD_CLEANUP) || defined(_WIN32)
|
||||||
@@ -243,8 +233,7 @@ struct tsd_s {
|
|||||||
* setters below.
|
* setters below.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define O(n, t, nt) \
|
#define O(n, t, nt) t TSD_MANGLE(n);
|
||||||
t TSD_MANGLE(n);
|
|
||||||
|
|
||||||
TSD_DATA_SLOW
|
TSD_DATA_SLOW
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -78,8 +78,8 @@ tsd_wrapper_get(bool init) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (init && unlikely(wrapper == NULL)) {
|
if (init && unlikely(wrapper == NULL)) {
|
||||||
wrapper = (tsd_wrapper_t *)
|
wrapper = (tsd_wrapper_t *)malloc_tsd_malloc(
|
||||||
malloc_tsd_malloc(sizeof(tsd_wrapper_t));
|
sizeof(tsd_wrapper_t));
|
||||||
if (wrapper == NULL) {
|
if (wrapper == NULL) {
|
||||||
malloc_write("<jemalloc>: Error allocating TSD\n");
|
malloc_write("<jemalloc>: Error allocating TSD\n");
|
||||||
abort();
|
abort();
|
||||||
@@ -115,8 +115,7 @@ tsd_boot0(void) {
|
|||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
tsd_boot1(void) {
|
tsd_boot1(void) {
|
||||||
tsd_wrapper_t *wrapper;
|
tsd_wrapper_t *wrapper;
|
||||||
wrapper = (tsd_wrapper_t *)
|
wrapper = (tsd_wrapper_t *)malloc_tsd_malloc(sizeof(tsd_wrapper_t));
|
||||||
malloc_tsd_malloc(sizeof(tsd_wrapper_t));
|
|
||||||
if (wrapper == NULL) {
|
if (wrapper == NULL) {
|
||||||
malloc_write("<jemalloc>: Error allocating TSD\n");
|
malloc_write("<jemalloc>: Error allocating TSD\n");
|
||||||
abort();
|
abort();
|
||||||
|
|||||||
@@ -10,49 +10,44 @@
|
|||||||
typedef struct { \
|
typedef struct { \
|
||||||
ql_head(el_type) head; \
|
ql_head(el_type) head; \
|
||||||
} list_type##_t; \
|
} list_type##_t; \
|
||||||
static inline void \
|
static inline void list_type##_init(list_type##_t *list) { \
|
||||||
list_type##_init(list_type##_t *list) { \
|
|
||||||
ql_new(&list->head); \
|
ql_new(&list->head); \
|
||||||
} \
|
} \
|
||||||
static inline el_type * \
|
static inline el_type *list_type##_first(const list_type##_t *list) { \
|
||||||
list_type##_first(const list_type##_t *list) { \
|
|
||||||
return ql_first(&list->head); \
|
return ql_first(&list->head); \
|
||||||
} \
|
} \
|
||||||
static inline el_type * \
|
static inline el_type *list_type##_last(const list_type##_t *list) { \
|
||||||
list_type##_last(const list_type##_t *list) { \
|
|
||||||
return ql_last(&list->head, linkage); \
|
return ql_last(&list->head, linkage); \
|
||||||
} \
|
} \
|
||||||
static inline el_type * \
|
static inline el_type *list_type##_next( \
|
||||||
list_type##_next(const list_type##_t *list, el_type *item) { \
|
const list_type##_t *list, el_type *item) { \
|
||||||
return ql_next(&list->head, item, linkage); \
|
return ql_next(&list->head, item, linkage); \
|
||||||
} \
|
} \
|
||||||
static inline void \
|
static inline void list_type##_append( \
|
||||||
list_type##_append(list_type##_t *list, el_type *item) { \
|
list_type##_t *list, el_type *item) { \
|
||||||
ql_elm_new(item, linkage); \
|
ql_elm_new(item, linkage); \
|
||||||
ql_tail_insert(&list->head, item, linkage); \
|
ql_tail_insert(&list->head, item, linkage); \
|
||||||
} \
|
} \
|
||||||
static inline void \
|
static inline void list_type##_prepend( \
|
||||||
list_type##_prepend(list_type##_t *list, el_type *item) { \
|
list_type##_t *list, el_type *item) { \
|
||||||
ql_elm_new(item, linkage); \
|
ql_elm_new(item, linkage); \
|
||||||
ql_head_insert(&list->head, item, linkage); \
|
ql_head_insert(&list->head, item, linkage); \
|
||||||
} \
|
} \
|
||||||
static inline void \
|
static inline void list_type##_replace( \
|
||||||
list_type##_replace(list_type##_t *list, el_type *to_remove, \
|
list_type##_t *list, el_type *to_remove, el_type *to_insert) { \
|
||||||
el_type *to_insert) { \
|
|
||||||
ql_elm_new(to_insert, linkage); \
|
ql_elm_new(to_insert, linkage); \
|
||||||
ql_after_insert(to_remove, to_insert, linkage); \
|
ql_after_insert(to_remove, to_insert, linkage); \
|
||||||
ql_remove(&list->head, to_remove, linkage); \
|
ql_remove(&list->head, to_remove, linkage); \
|
||||||
} \
|
} \
|
||||||
static inline void \
|
static inline void list_type##_remove( \
|
||||||
list_type##_remove(list_type##_t *list, el_type *item) { \
|
list_type##_t *list, el_type *item) { \
|
||||||
ql_remove(&list->head, item, linkage); \
|
ql_remove(&list->head, item, linkage); \
|
||||||
} \
|
} \
|
||||||
static inline bool \
|
static inline bool list_type##_empty(list_type##_t *list) { \
|
||||||
list_type##_empty(list_type##_t *list) { \
|
|
||||||
return ql_empty(&list->head); \
|
return ql_empty(&list->head); \
|
||||||
} \
|
} \
|
||||||
static inline void \
|
static inline void list_type##_concat( \
|
||||||
list_type##_concat(list_type##_t *list_a, list_type##_t *list_b) { \
|
list_type##_t *list_a, list_type##_t *list_b) { \
|
||||||
ql_concat(&list_a->head, &list_b->head, linkage); \
|
ql_concat(&list_a->head, &list_b->head, linkage); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,8 +70,8 @@ get_errno(void) {
|
|||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# define util_assume __assume
|
# define util_assume __assume
|
||||||
#elif defined(__clang__) && (__clang_major__ > 3 || \
|
#elif defined(__clang__) \
|
||||||
(__clang_major__ == 3 && __clang_minor__ >= 6))
|
&& (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 6))
|
||||||
# define util_assume __builtin_assume
|
# define util_assume __builtin_assume
|
||||||
#else
|
#else
|
||||||
# define util_assume(expr) \
|
# define util_assume(expr) \
|
||||||
@@ -148,7 +148,6 @@ util_prefetch_write_range(void *ptr, size_t sz) {
|
|||||||
* key1-key2:value|key3-key4:value|...
|
* key1-key2:value|key3-key4:value|...
|
||||||
* Note it does not handle the ending '\0'.
|
* Note it does not handle the ending '\0'.
|
||||||
*/
|
*/
|
||||||
bool
|
bool multi_setting_parse_next(const char **setting_segment_cur,
|
||||||
multi_setting_parse_next(const char **setting_segment_cur, size_t *len_left,
|
size_t *len_left, size_t *key_start, size_t *key_end, size_t *value);
|
||||||
size_t *key_start, size_t *key_end, size_t *value);
|
|
||||||
#endif /* JEMALLOC_INTERNAL_UTIL_H */
|
#endif /* JEMALLOC_INTERNAL_UTIL_H */
|
||||||
|
|||||||
@@ -86,15 +86,20 @@ typedef enum witness_rank_e witness_rank_t;
|
|||||||
/* PER-WITNESS DATA */
|
/* PER-WITNESS DATA */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
#if defined(JEMALLOC_DEBUG)
|
#if defined(JEMALLOC_DEBUG)
|
||||||
# define WITNESS_INITIALIZER(name, rank) {name, rank, NULL, NULL, {NULL, NULL}}
|
# define WITNESS_INITIALIZER(name, rank) \
|
||||||
|
{ \
|
||||||
|
name, rank, NULL, NULL, { \
|
||||||
|
NULL, NULL \
|
||||||
|
} \
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
# define WITNESS_INITIALIZER(name, rank)
|
# define WITNESS_INITIALIZER(name, rank)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct witness_s witness_t;
|
typedef struct witness_s witness_t;
|
||||||
typedef ql_head(witness_t) witness_list_t;
|
typedef ql_head(witness_t) witness_list_t;
|
||||||
typedef int witness_comp_t (const witness_t *, void *, const witness_t *,
|
typedef int witness_comp_t(
|
||||||
void *);
|
const witness_t *, void *, const witness_t *, void *);
|
||||||
|
|
||||||
struct witness_s {
|
struct witness_s {
|
||||||
/* Name, used for printing lock order reversal messages. */
|
/* Name, used for printing lock order reversal messages. */
|
||||||
@@ -129,7 +134,8 @@ struct witness_tsd_s {
|
|||||||
bool forking;
|
bool forking;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define WITNESS_TSD_INITIALIZER { ql_head_initializer(witnesses), false }
|
#define WITNESS_TSD_INITIALIZER \
|
||||||
|
{ ql_head_initializer(witnesses), false }
|
||||||
#define WITNESS_TSDN_NULL ((witness_tsdn_t *)0)
|
#define WITNESS_TSDN_NULL ((witness_tsdn_t *)0)
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
@@ -171,8 +177,8 @@ extern witness_owner_error_t *JET_MUTABLE witness_owner_error;
|
|||||||
typedef void(witness_not_owner_error_t)(const witness_t *);
|
typedef void(witness_not_owner_error_t)(const witness_t *);
|
||||||
extern witness_not_owner_error_t *JET_MUTABLE witness_not_owner_error;
|
extern witness_not_owner_error_t *JET_MUTABLE witness_not_owner_error;
|
||||||
|
|
||||||
typedef void (witness_depth_error_t)(const witness_list_t *,
|
typedef void(witness_depth_error_t)(
|
||||||
witness_rank_t rank_inclusive, unsigned depth);
|
const witness_list_t *, witness_rank_t rank_inclusive, unsigned depth);
|
||||||
extern witness_depth_error_t *JET_MUTABLE witness_depth_error;
|
extern witness_depth_error_t *JET_MUTABLE witness_depth_error;
|
||||||
|
|
||||||
void witnesses_cleanup(witness_tsd_t *witness_tsd);
|
void witnesses_cleanup(witness_tsd_t *witness_tsd);
|
||||||
@@ -221,8 +227,8 @@ witness_assert_owner(witness_tsdn_t *witness_tsdn, const witness_t *witness) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
witness_assert_not_owner(witness_tsdn_t *witness_tsdn,
|
witness_assert_not_owner(
|
||||||
const witness_t *witness) {
|
witness_tsdn_t *witness_tsdn, const witness_t *witness) {
|
||||||
witness_tsd_t *witness_tsd;
|
witness_tsd_t *witness_tsd;
|
||||||
witness_list_t *witnesses;
|
witness_list_t *witnesses;
|
||||||
witness_t *w;
|
witness_t *w;
|
||||||
@@ -249,8 +255,8 @@ witness_assert_not_owner(witness_tsdn_t *witness_tsdn,
|
|||||||
|
|
||||||
/* Returns depth. Not intended for direct use. */
|
/* Returns depth. Not intended for direct use. */
|
||||||
static inline unsigned
|
static inline unsigned
|
||||||
witness_depth_to_rank(witness_list_t *witnesses, witness_rank_t rank_inclusive)
|
witness_depth_to_rank(
|
||||||
{
|
witness_list_t *witnesses, witness_rank_t rank_inclusive) {
|
||||||
unsigned d = 0;
|
unsigned d = 0;
|
||||||
witness_t *w = ql_last(witnesses, link);
|
witness_t *w = ql_last(witnesses, link);
|
||||||
|
|
||||||
@@ -292,8 +298,8 @@ witness_assert_lockless(witness_tsdn_t *witness_tsdn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
witness_assert_positive_depth_to_rank(witness_tsdn_t *witness_tsdn,
|
witness_assert_positive_depth_to_rank(
|
||||||
witness_rank_t rank_inclusive) {
|
witness_tsdn_t *witness_tsdn, witness_rank_t rank_inclusive) {
|
||||||
if (!config_debug || witness_tsdn_null(witness_tsdn)) {
|
if (!config_debug || witness_tsdn_null(witness_tsdn)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -335,9 +341,9 @@ witness_lock(witness_tsdn_t *witness_tsdn, witness_t *witness) {
|
|||||||
} else if (w->rank > witness->rank) {
|
} else if (w->rank > witness->rank) {
|
||||||
/* Not forking, rank order reversal. */
|
/* Not forking, rank order reversal. */
|
||||||
witness_lock_error(witnesses, witness);
|
witness_lock_error(witnesses, witness);
|
||||||
} else if (w->rank == witness->rank && (w->comp == NULL || w->comp !=
|
} else if (w->rank == witness->rank
|
||||||
witness->comp || w->comp(w, w->opaque, witness, witness->opaque) >
|
&& (w->comp == NULL || w->comp != witness->comp
|
||||||
0)) {
|
|| w->comp(w, w->opaque, witness, witness->opaque) > 0)) {
|
||||||
/*
|
/*
|
||||||
* Missing/incompatible comparison function, or comparison
|
* Missing/incompatible comparison function, or comparison
|
||||||
* function indicates rank order reversal.
|
* function indicates rank order reversal.
|
||||||
@@ -346,8 +352,8 @@ witness_lock(witness_tsdn_t *witness_tsdn, witness_t *witness) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Suppress spurious warning from static analysis */
|
/* Suppress spurious warning from static analysis */
|
||||||
assert(ql_empty(witnesses) ||
|
assert(
|
||||||
qr_prev(ql_first(witnesses), link) != NULL);
|
ql_empty(witnesses) || qr_prev(ql_first(witnesses), link) != NULL);
|
||||||
ql_elm_new(witness, link);
|
ql_elm_new(witness, link);
|
||||||
ql_tail_insert(witnesses, witness, link);
|
ql_tail_insert(witnesses, witness, link);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,14 +56,14 @@ extern "C" {
|
|||||||
|
|
||||||
// Define _W64 macros to mark types changing their size, like intptr_t.
|
// Define _W64 macros to mark types changing their size, like intptr_t.
|
||||||
# ifndef _W64
|
# ifndef _W64
|
||||||
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
|
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) \
|
||||||
|
&& _MSC_VER >= 1300
|
||||||
# define _W64 __w64
|
# define _W64 __w64
|
||||||
# else
|
# else
|
||||||
# define _W64
|
# define _W64
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
|
||||||
// 7.18.1 Integer types
|
// 7.18.1 Integer types
|
||||||
|
|
||||||
// 7.18.1.1 Exact-width integer types
|
// 7.18.1.1 Exact-width integer types
|
||||||
@@ -89,7 +89,6 @@ extern "C" {
|
|||||||
typedef signed __int64 int64_t;
|
typedef signed __int64 int64_t;
|
||||||
typedef unsigned __int64 uint64_t;
|
typedef unsigned __int64 uint64_t;
|
||||||
|
|
||||||
|
|
||||||
// 7.18.1.2 Minimum-width integer types
|
// 7.18.1.2 Minimum-width integer types
|
||||||
typedef int8_t int_least8_t;
|
typedef int8_t int_least8_t;
|
||||||
typedef int16_t int_least16_t;
|
typedef int16_t int_least16_t;
|
||||||
@@ -123,10 +122,11 @@ typedef uint64_t uint_fast64_t;
|
|||||||
typedef int64_t intmax_t;
|
typedef int64_t intmax_t;
|
||||||
typedef uint64_t uintmax_t;
|
typedef uint64_t uintmax_t;
|
||||||
|
|
||||||
|
|
||||||
// 7.18.2 Limits of specified-width integer types
|
// 7.18.2 Limits of specified-width integer types
|
||||||
|
|
||||||
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
|
# if !defined(__cplusplus) \
|
||||||
|
|| defined( \
|
||||||
|
__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
|
||||||
|
|
||||||
// 7.18.2.1 Limits of exact-width integer types
|
// 7.18.2.1 Limits of exact-width integer types
|
||||||
# define INT8_MIN ((int8_t)_I8_MIN)
|
# define INT8_MIN ((int8_t)_I8_MIN)
|
||||||
@@ -220,10 +220,11 @@ typedef uint64_t uintmax_t;
|
|||||||
|
|
||||||
# endif // __STDC_LIMIT_MACROS ]
|
# endif // __STDC_LIMIT_MACROS ]
|
||||||
|
|
||||||
|
|
||||||
// 7.18.4 Limits of other integer types
|
// 7.18.4 Limits of other integer types
|
||||||
|
|
||||||
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
|
# if !defined(__cplusplus) \
|
||||||
|
|| defined( \
|
||||||
|
__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
|
||||||
|
|
||||||
// 7.18.4.1 Macros for minimum-width integer constants
|
// 7.18.4.1 Macros for minimum-width integer constants
|
||||||
|
|
||||||
@@ -243,5 +244,4 @@ typedef uint64_t uintmax_t;
|
|||||||
|
|
||||||
# endif // __STDC_CONSTANT_MACROS ]
|
# endif // __STDC_CONSTANT_MACROS ]
|
||||||
|
|
||||||
|
|
||||||
#endif // _MSC_STDINT_H_ ]
|
#endif // _MSC_STDINT_H_ ]
|
||||||
|
|||||||
@@ -6,7 +6,8 @@
|
|||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# include <intrin.h>
|
# include <intrin.h>
|
||||||
# pragma intrinsic(_BitScanForward)
|
# pragma intrinsic(_BitScanForward)
|
||||||
static __forceinline int ffsl(long x) {
|
static __forceinline int
|
||||||
|
ffsl(long x) {
|
||||||
unsigned long i;
|
unsigned long i;
|
||||||
|
|
||||||
if (_BitScanForward(&i, x)) {
|
if (_BitScanForward(&i, x)) {
|
||||||
@@ -15,7 +16,8 @@ static __forceinline int ffsl(long x) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static __forceinline int ffs(int x) {
|
static __forceinline int
|
||||||
|
ffs(int x) {
|
||||||
return ffsl(x);
|
return ffsl(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,7 +25,8 @@ static __forceinline int ffs(int x) {
|
|||||||
# pragma intrinsic(_BitScanForward64)
|
# pragma intrinsic(_BitScanForward64)
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
static __forceinline int ffsll(unsigned __int64 x) {
|
static __forceinline int
|
||||||
|
ffsll(unsigned __int64 x) {
|
||||||
unsigned long i;
|
unsigned long i;
|
||||||
# ifdef _M_X64
|
# ifdef _M_X64
|
||||||
if (_BitScanForward64(&i, x)) {
|
if (_BitScanForward64(&i, x)) {
|
||||||
|
|||||||
@@ -12,12 +12,13 @@
|
|||||||
#define JEMALLOC_NO_DEMANGLE
|
#define JEMALLOC_NO_DEMANGLE
|
||||||
#include <jemalloc/jemalloc.h>
|
#include <jemalloc/jemalloc.h>
|
||||||
|
|
||||||
using std::vector;
|
using std::minstd_rand;
|
||||||
using std::thread;
|
using std::thread;
|
||||||
using std::uniform_int_distribution;
|
using std::uniform_int_distribution;
|
||||||
using std::minstd_rand;
|
using std::vector;
|
||||||
|
|
||||||
int test_threads() {
|
int
|
||||||
|
test_threads() {
|
||||||
je_malloc_conf = "narenas:3";
|
je_malloc_conf = "narenas:3";
|
||||||
int narenas = 0;
|
int narenas = 0;
|
||||||
size_t sz = sizeof(narenas);
|
size_t sz = sizeof(narenas);
|
||||||
@@ -26,17 +27,21 @@ int test_threads() {
|
|||||||
printf("Error: unexpected number of arenas: %d\n", narenas);
|
printf("Error: unexpected number of arenas: %d\n", narenas);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
static const int sizes[] = { 7, 16, 32, 60, 91, 100, 120, 144, 169, 199, 255, 400, 670, 900, 917, 1025, 3333, 5190, 13131, 49192, 99999, 123123, 255265, 2333111 };
|
static const int sizes[] = {7, 16, 32, 60, 91, 100, 120, 144, 169, 199,
|
||||||
|
255, 400, 670, 900, 917, 1025, 3333, 5190, 13131, 49192, 99999,
|
||||||
|
123123, 255265, 2333111};
|
||||||
static const int numSizes = (int)(sizeof(sizes) / sizeof(sizes[0]));
|
static const int numSizes = (int)(sizeof(sizes) / sizeof(sizes[0]));
|
||||||
vector<thread> workers;
|
vector<thread> workers;
|
||||||
static const int numThreads = narenas + 1, numAllocsMax = 25, numIter1 = 50, numIter2 = 50;
|
static const int numThreads = narenas + 1, numAllocsMax = 25,
|
||||||
|
numIter1 = 50, numIter2 = 50;
|
||||||
je_malloc_stats_print(NULL, NULL, NULL);
|
je_malloc_stats_print(NULL, NULL, NULL);
|
||||||
size_t allocated1;
|
size_t allocated1;
|
||||||
size_t sz1 = sizeof(allocated1);
|
size_t sz1 = sizeof(allocated1);
|
||||||
je_mallctl("stats.active", (void *)&allocated1, &sz1, NULL, 0);
|
je_mallctl("stats.active", (void *)&allocated1, &sz1, NULL, 0);
|
||||||
printf("\nPress Enter to start threads...\n");
|
printf("\nPress Enter to start threads...\n");
|
||||||
getchar();
|
getchar();
|
||||||
printf("Starting %d threads x %d x %d iterations...\n", numThreads, numIter1, numIter2);
|
printf("Starting %d threads x %d x %d iterations...\n", numThreads,
|
||||||
|
numIter1, numIter2);
|
||||||
for (int i = 0; i < numThreads; i++) {
|
for (int i = 0; i < numThreads; i++) {
|
||||||
workers.emplace_back([tid = i]() {
|
workers.emplace_back([tid = i]() {
|
||||||
uniform_int_distribution<int> sizeDist(0, numSizes - 1);
|
uniform_int_distribution<int> sizeDist(0, numSizes - 1);
|
||||||
@@ -46,23 +51,47 @@ int test_threads() {
|
|||||||
for (int i = 0; i < numIter1; ++i) {
|
for (int i = 0; i < numIter1; ++i) {
|
||||||
thread t([&]() {
|
thread t([&]() {
|
||||||
for (int i = 0; i < numIter2; ++i) {
|
for (int i = 0; i < numIter2; ++i) {
|
||||||
const int numAllocs = numAllocsMax - sizeDist(rnd);
|
const int numAllocs =
|
||||||
for (int j = 0; j < numAllocs; j += 64) {
|
numAllocsMax
|
||||||
const int x = sizeDist(rnd);
|
- sizeDist(rnd);
|
||||||
|
for (int j = 0; j < numAllocs;
|
||||||
|
j += 64) {
|
||||||
|
const int x = sizeDist(
|
||||||
|
rnd);
|
||||||
const int sz = sizes[x];
|
const int sz = sizes[x];
|
||||||
ptrsz[j] = sz;
|
ptrsz[j] = sz;
|
||||||
ptrs[j] = (uint8_t*)je_malloc(sz);
|
ptrs[j] = (uint8_t *)
|
||||||
|
je_malloc(sz);
|
||||||
if (!ptrs[j]) {
|
if (!ptrs[j]) {
|
||||||
printf("Unable to allocate %d bytes in thread %d, iter %d, alloc %d. %d\n", sz, tid, i, j, x);
|
printf(
|
||||||
|
"Unable to allocate %d bytes in thread %d, iter %d, alloc %d. %d\n",
|
||||||
|
sz, tid, i,
|
||||||
|
j, x);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
for (int k = 0; k < sz; k++)
|
for (int k = 0; k < sz;
|
||||||
ptrs[j][k] = tid + k;
|
k++)
|
||||||
|
ptrs[j][k] = tid
|
||||||
|
+ k;
|
||||||
}
|
}
|
||||||
for (int j = 0; j < numAllocs; j += 64) {
|
for (int j = 0; j < numAllocs;
|
||||||
for (int k = 0, sz = ptrsz[j]; k < sz; k++)
|
j += 64) {
|
||||||
if (ptrs[j][k] != (uint8_t)(tid + k)) {
|
for (int k = 0,
|
||||||
printf("Memory error in thread %d, iter %d, alloc %d @ %d : %02X!=%02X\n", tid, i, j, k, ptrs[j][k], (uint8_t)(tid + k));
|
sz = ptrsz[j];
|
||||||
|
k < sz; k++)
|
||||||
|
if (ptrs[j][k]
|
||||||
|
!= (uint8_t)(tid
|
||||||
|
+ k)) {
|
||||||
|
printf(
|
||||||
|
"Memory error in thread %d, iter %d, alloc %d @ %d : %02X!=%02X\n",
|
||||||
|
tid,
|
||||||
|
i,
|
||||||
|
j,
|
||||||
|
k,
|
||||||
|
ptrs[j]
|
||||||
|
[k],
|
||||||
|
(uint8_t)(tid
|
||||||
|
+ k));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
je_free(ptrs[j]);
|
je_free(ptrs[j]);
|
||||||
@@ -81,7 +110,8 @@ int test_threads() {
|
|||||||
je_mallctl("stats.active", (void *)&allocated2, &sz1, NULL, 0);
|
je_mallctl("stats.active", (void *)&allocated2, &sz1, NULL, 0);
|
||||||
size_t leaked = allocated2 - allocated1;
|
size_t leaked = allocated2 - allocated1;
|
||||||
printf("\nDone. Leaked: %zd bytes\n", leaked);
|
printf("\nDone. Leaked: %zd bytes\n", leaked);
|
||||||
bool failed = leaked > 65536; // in case C++ runtime allocated something (e.g. iostream locale or facet)
|
bool failed = leaked
|
||||||
|
> 65536; // in case C++ runtime allocated something (e.g. iostream locale or facet)
|
||||||
printf("\nTest %s!\n", (failed ? "FAILED" : "successful"));
|
printf("\nTest %s!\n", (failed ? "FAILED" : "successful"));
|
||||||
printf("\nPress Enter to continue...\n");
|
printf("\nPress Enter to continue...\n");
|
||||||
getchar();
|
getchar();
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int
|
||||||
|
main(int argc, char **argv) {
|
||||||
int rc = test_threads();
|
int rc = test_threads();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|||||||
404
src/arena.c
404
src/arena.c
@@ -22,12 +22,7 @@ JEMALLOC_DIAGNOSTIC_DISABLE_SPURIOUS
|
|||||||
* options and mallctl processing are straightforward.
|
* options and mallctl processing are straightforward.
|
||||||
*/
|
*/
|
||||||
const char *const percpu_arena_mode_names[] = {
|
const char *const percpu_arena_mode_names[] = {
|
||||||
"percpu",
|
"percpu", "phycpu", "disabled", "percpu", "phycpu"};
|
||||||
"phycpu",
|
|
||||||
"disabled",
|
|
||||||
"percpu",
|
|
||||||
"phycpu"
|
|
||||||
};
|
|
||||||
percpu_arena_mode_t opt_percpu_arena = PERCPU_ARENA_DEFAULT;
|
percpu_arena_mode_t opt_percpu_arena = PERCPU_ARENA_DEFAULT;
|
||||||
|
|
||||||
ssize_t opt_dirty_decay_ms = DIRTY_DECAY_MS_DEFAULT;
|
ssize_t opt_dirty_decay_ms = DIRTY_DECAY_MS_DEFAULT;
|
||||||
@@ -54,7 +49,8 @@ uint32_t arena_bin_offsets[SC_NBINS];
|
|||||||
unsigned huge_arena_ind = 0;
|
unsigned huge_arena_ind = 0;
|
||||||
bool opt_huge_arena_pac_thp = false;
|
bool opt_huge_arena_pac_thp = false;
|
||||||
pac_thp_t huge_arena_pac_thp = {.thp_madvise = false,
|
pac_thp_t huge_arena_pac_thp = {.thp_madvise = false,
|
||||||
.auto_thp_switched = false, .n_thp_lazy = ATOMIC_INIT(0)};
|
.auto_thp_switched = false,
|
||||||
|
.n_thp_lazy = ATOMIC_INIT(0)};
|
||||||
|
|
||||||
const arena_config_t arena_config_default = {
|
const arena_config_t arena_config_default = {
|
||||||
/* .extent_hooks = */ (extent_hooks_t *)&ehooks_default_extent_hooks,
|
/* .extent_hooks = */ (extent_hooks_t *)&ehooks_default_extent_hooks,
|
||||||
@@ -67,13 +63,12 @@ const arena_config_t arena_config_default = {
|
|||||||
* definition.
|
* definition.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static bool arena_decay_dirty(tsdn_t *tsdn, arena_t *arena,
|
static bool arena_decay_dirty(
|
||||||
bool is_background_thread, bool all);
|
tsdn_t *tsdn, arena_t *arena, bool is_background_thread, bool all);
|
||||||
static void arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, edata_t *slab,
|
static void arena_bin_lower_slab(
|
||||||
bin_t *bin);
|
tsdn_t *tsdn, arena_t *arena, edata_t *slab, bin_t *bin);
|
||||||
static void
|
static void arena_maybe_do_deferred_work(
|
||||||
arena_maybe_do_deferred_work(tsdn_t *tsdn, arena_t *arena, decay_t *decay,
|
tsdn_t *tsdn, arena_t *arena, decay_t *decay, size_t npages_new);
|
||||||
size_t npages_new);
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
@@ -92,8 +87,8 @@ void
|
|||||||
arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
||||||
const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms,
|
const char **dss, ssize_t *dirty_decay_ms, ssize_t *muzzy_decay_ms,
|
||||||
size_t *nactive, size_t *ndirty, size_t *nmuzzy, arena_stats_t *astats,
|
size_t *nactive, size_t *ndirty, size_t *nmuzzy, arena_stats_t *astats,
|
||||||
bin_stats_data_t *bstats, arena_stats_large_t *lstats,
|
bin_stats_data_t *bstats, arena_stats_large_t *lstats, pac_estats_t *estats,
|
||||||
pac_estats_t *estats, hpa_shard_stats_t *hpastats, sec_stats_t *secstats) {
|
hpa_shard_stats_t *hpastats, sec_stats_t *secstats) {
|
||||||
cassert(config_stats);
|
cassert(config_stats);
|
||||||
|
|
||||||
arena_basic_stats_merge(tsdn, arena, nthreads, dss, dirty_decay_ms,
|
arena_basic_stats_merge(tsdn, arena, nthreads, dss, dirty_decay_ms,
|
||||||
@@ -135,8 +130,8 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
|||||||
uint64_t nrequests = locked_read_u64(tsdn,
|
uint64_t nrequests = locked_read_u64(tsdn,
|
||||||
LOCKEDINT_MTX(arena->stats.mtx),
|
LOCKEDINT_MTX(arena->stats.mtx),
|
||||||
&arena->stats.lstats[i].nrequests);
|
&arena->stats.lstats[i].nrequests);
|
||||||
locked_inc_u64_unsynchronized(&lstats[i].nrequests,
|
locked_inc_u64_unsynchronized(
|
||||||
nmalloc + nrequests);
|
&lstats[i].nrequests, nmalloc + nrequests);
|
||||||
astats->nrequests_large += nmalloc + nrequests;
|
astats->nrequests_large += nmalloc + nrequests;
|
||||||
|
|
||||||
/* nfill == nmalloc for large currently. */
|
/* nfill == nmalloc for large currently. */
|
||||||
@@ -180,10 +175,11 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
|||||||
}
|
}
|
||||||
|
|
||||||
cache_bin_sz_t ncached, nstashed;
|
cache_bin_sz_t ncached, nstashed;
|
||||||
cache_bin_nitems_get_remote(cache_bin, &ncached, &nstashed);
|
cache_bin_nitems_get_remote(
|
||||||
|
cache_bin, &ncached, &nstashed);
|
||||||
astats->tcache_bytes += ncached * sz_index2size(i);
|
astats->tcache_bytes += ncached * sz_index2size(i);
|
||||||
astats->tcache_stashed_bytes += nstashed *
|
astats->tcache_stashed_bytes += nstashed
|
||||||
sz_index2size(i);
|
* sz_index2size(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
malloc_mutex_prof_read(tsdn,
|
malloc_mutex_prof_read(tsdn,
|
||||||
@@ -193,17 +189,16 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
|||||||
|
|
||||||
#define READ_ARENA_MUTEX_PROF_DATA(mtx, ind) \
|
#define READ_ARENA_MUTEX_PROF_DATA(mtx, ind) \
|
||||||
malloc_mutex_lock(tsdn, &arena->mtx); \
|
malloc_mutex_lock(tsdn, &arena->mtx); \
|
||||||
malloc_mutex_prof_read(tsdn, &astats->mutex_prof_data[ind], \
|
malloc_mutex_prof_read( \
|
||||||
&arena->mtx); \
|
tsdn, &astats->mutex_prof_data[ind], &arena->mtx); \
|
||||||
malloc_mutex_unlock(tsdn, &arena->mtx);
|
malloc_mutex_unlock(tsdn, &arena->mtx);
|
||||||
|
|
||||||
/* Gather per arena mutex profiling data. */
|
/* Gather per arena mutex profiling data. */
|
||||||
READ_ARENA_MUTEX_PROF_DATA(large_mtx, arena_prof_mutex_large);
|
READ_ARENA_MUTEX_PROF_DATA(large_mtx, arena_prof_mutex_large);
|
||||||
READ_ARENA_MUTEX_PROF_DATA(base->mtx,
|
READ_ARENA_MUTEX_PROF_DATA(base->mtx, arena_prof_mutex_base);
|
||||||
arena_prof_mutex_base);
|
|
||||||
#undef READ_ARENA_MUTEX_PROF_DATA
|
#undef READ_ARENA_MUTEX_PROF_DATA
|
||||||
pa_shard_mtx_stats_read(tsdn, &arena->pa_shard,
|
pa_shard_mtx_stats_read(
|
||||||
astats->mutex_prof_data);
|
tsdn, &arena->pa_shard, astats->mutex_prof_data);
|
||||||
|
|
||||||
nstime_copy(&astats->uptime, &arena->create_time);
|
nstime_copy(&astats->uptime, &arena->create_time);
|
||||||
nstime_update(&astats->uptime);
|
nstime_update(&astats->uptime);
|
||||||
@@ -211,32 +206,33 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
|||||||
|
|
||||||
for (szind_t i = 0; i < SC_NBINS; i++) {
|
for (szind_t i = 0; i < SC_NBINS; i++) {
|
||||||
for (unsigned j = 0; j < bin_infos[i].n_shards; j++) {
|
for (unsigned j = 0; j < bin_infos[i].n_shards; j++) {
|
||||||
bin_stats_merge(tsdn, &bstats[i],
|
bin_stats_merge(
|
||||||
arena_get_bin(arena, i, j));
|
tsdn, &bstats[i], arena_get_bin(arena, i, j));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
arena_background_thread_inactivity_check(tsdn_t *tsdn, arena_t *arena,
|
arena_background_thread_inactivity_check(
|
||||||
bool is_background_thread) {
|
tsdn_t *tsdn, arena_t *arena, bool is_background_thread) {
|
||||||
if (!background_thread_enabled() || is_background_thread) {
|
if (!background_thread_enabled() || is_background_thread) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
background_thread_info_t *info =
|
background_thread_info_t *info = arena_background_thread_info_get(
|
||||||
arena_background_thread_info_get(arena);
|
arena);
|
||||||
if (background_thread_indefinite_sleep(info)) {
|
if (background_thread_indefinite_sleep(info)) {
|
||||||
arena_maybe_do_deferred_work(tsdn, arena,
|
arena_maybe_do_deferred_work(
|
||||||
&arena->pa_shard.pac.decay_dirty, 0);
|
tsdn, arena, &arena->pa_shard.pac.decay_dirty, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* React to deferred work generated by a PAI function.
|
* React to deferred work generated by a PAI function.
|
||||||
*/
|
*/
|
||||||
void arena_handle_deferred_work(tsdn_t *tsdn, arena_t *arena) {
|
void
|
||||||
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
arena_handle_deferred_work(tsdn_t *tsdn, arena_t *arena) {
|
||||||
WITNESS_RANK_CORE, 0);
|
witness_assert_depth_to_rank(
|
||||||
|
tsdn_witness_tsdp_get(tsdn), WITNESS_RANK_CORE, 0);
|
||||||
|
|
||||||
if (decay_immediately(&arena->pa_shard.pac.decay_dirty)) {
|
if (decay_immediately(&arena->pa_shard.pac.decay_dirty)) {
|
||||||
arena_decay_dirty(tsdn, arena, false, true);
|
arena_decay_dirty(tsdn, arena, false, true);
|
||||||
@@ -254,15 +250,15 @@ arena_slab_reg_alloc(edata_t *slab, const bin_info_t *bin_info) {
|
|||||||
assert(!bitmap_full(slab_data->bitmap, &bin_info->bitmap_info));
|
assert(!bitmap_full(slab_data->bitmap, &bin_info->bitmap_info));
|
||||||
|
|
||||||
regind = bitmap_sfu(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) +
|
ret = (void *)((byte_t *)edata_addr_get(slab)
|
||||||
(uintptr_t)(bin_info->reg_size * regind));
|
+ (uintptr_t)(bin_info->reg_size * regind));
|
||||||
edata_nfree_dec(slab);
|
edata_nfree_dec(slab);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
arena_slab_reg_alloc_batch(edata_t *slab, const bin_info_t *bin_info,
|
arena_slab_reg_alloc_batch(
|
||||||
unsigned cnt, void** ptrs) {
|
edata_t *slab, const bin_info_t *bin_info, unsigned cnt, void **ptrs) {
|
||||||
slab_data_t *slab_data = edata_slab_data_get(slab);
|
slab_data_t *slab_data = edata_slab_data_get(slab);
|
||||||
|
|
||||||
assert(edata_nfree_get(slab) >= cnt);
|
assert(edata_nfree_get(slab) >= cnt);
|
||||||
@@ -270,10 +266,10 @@ arena_slab_reg_alloc_batch(edata_t *slab, const bin_info_t *bin_info,
|
|||||||
|
|
||||||
#if (!defined JEMALLOC_INTERNAL_POPCOUNTL) || (defined BITMAP_USE_TREE)
|
#if (!defined JEMALLOC_INTERNAL_POPCOUNTL) || (defined BITMAP_USE_TREE)
|
||||||
for (unsigned i = 0; i < cnt; i++) {
|
for (unsigned i = 0; i < cnt; i++) {
|
||||||
size_t regind = bitmap_sfu(slab_data->bitmap,
|
size_t regind = bitmap_sfu(
|
||||||
&bin_info->bitmap_info);
|
slab_data->bitmap, &bin_info->bitmap_info);
|
||||||
*(ptrs + i) = (void *)((uintptr_t)edata_addr_get(slab) +
|
*(ptrs + i) = (void *)((uintptr_t)edata_addr_get(slab)
|
||||||
(uintptr_t)(bin_info->reg_size * regind));
|
+ (uintptr_t)(bin_info->reg_size * regind));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
unsigned group = 0;
|
unsigned group = 0;
|
||||||
@@ -329,8 +325,7 @@ arena_large_malloc_stats_update(tsdn_t *tsdn, arena_t *arena, size_t usize) {
|
|||||||
locked_inc_u64(tsdn, LOCKEDINT_MTX(arena->stats.mtx),
|
locked_inc_u64(tsdn, LOCKEDINT_MTX(arena->stats.mtx),
|
||||||
&arena->stats.lstats[hindex].nmalloc, 1);
|
&arena->stats.lstats[hindex].nmalloc, 1);
|
||||||
locked_inc_u64(tsdn, LOCKEDINT_MTX(arena->stats.mtx),
|
locked_inc_u64(tsdn, LOCKEDINT_MTX(arena->stats.mtx),
|
||||||
&arena->stats.lstats[hindex].active_bytes,
|
&arena->stats.lstats[hindex].active_bytes, usize);
|
||||||
usize);
|
|
||||||
LOCKEDINT_MTX_UNLOCK(tsdn, arena->stats.mtx);
|
LOCKEDINT_MTX_UNLOCK(tsdn, arena->stats.mtx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -355,28 +350,27 @@ arena_large_dalloc_stats_update(tsdn_t *tsdn, arena_t *arena, size_t usize) {
|
|||||||
locked_inc_u64(tsdn, LOCKEDINT_MTX(arena->stats.mtx),
|
locked_inc_u64(tsdn, LOCKEDINT_MTX(arena->stats.mtx),
|
||||||
&arena->stats.lstats[hindex].ndalloc, 1);
|
&arena->stats.lstats[hindex].ndalloc, 1);
|
||||||
locked_dec_u64(tsdn, LOCKEDINT_MTX(arena->stats.mtx),
|
locked_dec_u64(tsdn, LOCKEDINT_MTX(arena->stats.mtx),
|
||||||
&arena->stats.lstats[hindex].active_bytes,
|
&arena->stats.lstats[hindex].active_bytes, usize);
|
||||||
usize);
|
|
||||||
LOCKEDINT_MTX_UNLOCK(tsdn, arena->stats.mtx);
|
LOCKEDINT_MTX_UNLOCK(tsdn, arena->stats.mtx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
arena_large_ralloc_stats_update(tsdn_t *tsdn, arena_t *arena, size_t oldusize,
|
arena_large_ralloc_stats_update(
|
||||||
size_t usize) {
|
tsdn_t *tsdn, arena_t *arena, size_t oldusize, size_t usize) {
|
||||||
arena_large_malloc_stats_update(tsdn, arena, usize);
|
arena_large_malloc_stats_update(tsdn, arena, usize);
|
||||||
arena_large_dalloc_stats_update(tsdn, arena, oldusize);
|
arena_large_dalloc_stats_update(tsdn, arena, oldusize);
|
||||||
}
|
}
|
||||||
|
|
||||||
edata_t *
|
edata_t *
|
||||||
arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize,
|
arena_extent_alloc_large(
|
||||||
size_t alignment, bool zero) {
|
tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment, bool zero) {
|
||||||
bool deferred_work_generated = false;
|
bool deferred_work_generated = false;
|
||||||
szind_t szind = sz_size2index(usize);
|
szind_t szind = sz_size2index(usize);
|
||||||
size_t esize = usize + sz_large_pad;
|
size_t esize = usize + sz_large_pad;
|
||||||
|
|
||||||
bool guarded = san_large_extent_decide_guard(tsdn,
|
bool guarded = san_large_extent_decide_guard(
|
||||||
arena_get_ehooks(arena), esize, alignment);
|
tsdn, arena_get_ehooks(arena), esize, alignment);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* - if usize >= opt_calloc_madvise_threshold,
|
* - if usize >= opt_calloc_madvise_threshold,
|
||||||
@@ -417,14 +411,14 @@ arena_extent_alloc_large(tsdn_t *tsdn, arena_t *arena, size_t usize,
|
|||||||
void
|
void
|
||||||
arena_extent_dalloc_large_prep(tsdn_t *tsdn, arena_t *arena, edata_t *edata) {
|
arena_extent_dalloc_large_prep(tsdn_t *tsdn, arena_t *arena, edata_t *edata) {
|
||||||
if (config_stats) {
|
if (config_stats) {
|
||||||
arena_large_dalloc_stats_update(tsdn, arena,
|
arena_large_dalloc_stats_update(
|
||||||
edata_usize_get(edata));
|
tsdn, arena, edata_usize_get(edata));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, edata_t *edata,
|
arena_extent_ralloc_large_shrink(
|
||||||
size_t oldusize) {
|
tsdn_t *tsdn, arena_t *arena, edata_t *edata, size_t oldusize) {
|
||||||
size_t usize = edata_usize_get(edata);
|
size_t usize = edata_usize_get(edata);
|
||||||
|
|
||||||
if (config_stats) {
|
if (config_stats) {
|
||||||
@@ -433,8 +427,8 @@ arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena, edata_t *edata,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, edata_t *edata,
|
arena_extent_ralloc_large_expand(
|
||||||
size_t oldusize) {
|
tsdn_t *tsdn, arena_t *arena, edata_t *edata, size_t oldusize) {
|
||||||
size_t usize = edata_usize_get(edata);
|
size_t usize = edata_usize_get(edata);
|
||||||
|
|
||||||
if (config_stats) {
|
if (config_stats) {
|
||||||
@@ -459,12 +453,12 @@ arena_decide_unforced_purge_eagerness(bool is_background_thread) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
arena_decay_ms_set(tsdn_t *tsdn, arena_t *arena, extent_state_t state,
|
arena_decay_ms_set(
|
||||||
ssize_t decay_ms) {
|
tsdn_t *tsdn, arena_t *arena, extent_state_t state, ssize_t decay_ms) {
|
||||||
pac_purge_eagerness_t eagerness = arena_decide_unforced_purge_eagerness(
|
pac_purge_eagerness_t eagerness = arena_decide_unforced_purge_eagerness(
|
||||||
/* is_background_thread */ false);
|
/* is_background_thread */ false);
|
||||||
return pa_decay_ms_set(tsdn, &arena->pa_shard, state, decay_ms,
|
return pa_decay_ms_set(
|
||||||
eagerness);
|
tsdn, &arena->pa_shard, state, decay_ms, eagerness);
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t
|
ssize_t
|
||||||
@@ -474,8 +468,8 @@ arena_decay_ms_get(arena_t *arena, extent_state_t state) {
|
|||||||
|
|
||||||
static bool
|
static bool
|
||||||
arena_decay_impl(tsdn_t *tsdn, arena_t *arena, decay_t *decay,
|
arena_decay_impl(tsdn_t *tsdn, arena_t *arena, decay_t *decay,
|
||||||
pac_decay_stats_t *decay_stats, ecache_t *ecache,
|
pac_decay_stats_t *decay_stats, ecache_t *ecache, bool is_background_thread,
|
||||||
bool is_background_thread, bool all) {
|
bool all) {
|
||||||
if (all) {
|
if (all) {
|
||||||
malloc_mutex_lock(tsdn, &decay->mtx);
|
malloc_mutex_lock(tsdn, &decay->mtx);
|
||||||
pac_decay_all(tsdn, &arena->pa_shard.pac, decay, decay_stats,
|
pac_decay_all(tsdn, &arena->pa_shard.pac, decay, decay_stats,
|
||||||
@@ -488,10 +482,10 @@ arena_decay_impl(tsdn_t *tsdn, arena_t *arena, decay_t *decay,
|
|||||||
/* No need to wait if another thread is in progress. */
|
/* No need to wait if another thread is in progress. */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
pac_purge_eagerness_t eagerness =
|
pac_purge_eagerness_t eagerness = arena_decide_unforced_purge_eagerness(
|
||||||
arena_decide_unforced_purge_eagerness(is_background_thread);
|
is_background_thread);
|
||||||
bool epoch_advanced = pac_maybe_decay_purge(tsdn, &arena->pa_shard.pac,
|
bool epoch_advanced = pac_maybe_decay_purge(
|
||||||
decay, decay_stats, ecache, eagerness);
|
tsdn, &arena->pa_shard.pac, decay, decay_stats, ecache, eagerness);
|
||||||
size_t npages_new JEMALLOC_CLANG_ANALYZER_SILENCE_INIT(0);
|
size_t npages_new JEMALLOC_CLANG_ANALYZER_SILENCE_INIT(0);
|
||||||
if (epoch_advanced) {
|
if (epoch_advanced) {
|
||||||
/* Backlog is updated on epoch advance. */
|
/* Backlog is updated on epoch advance. */
|
||||||
@@ -499,8 +493,8 @@ arena_decay_impl(tsdn_t *tsdn, arena_t *arena, decay_t *decay,
|
|||||||
}
|
}
|
||||||
malloc_mutex_unlock(tsdn, &decay->mtx);
|
malloc_mutex_unlock(tsdn, &decay->mtx);
|
||||||
|
|
||||||
if (have_background_thread && background_thread_enabled() &&
|
if (have_background_thread && background_thread_enabled()
|
||||||
epoch_advanced && !is_background_thread) {
|
&& epoch_advanced && !is_background_thread) {
|
||||||
arena_maybe_do_deferred_work(tsdn, arena, decay, npages_new);
|
arena_maybe_do_deferred_work(tsdn, arena, decay, npages_new);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -508,16 +502,16 @@ arena_decay_impl(tsdn_t *tsdn, arena_t *arena, decay_t *decay,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
arena_decay_dirty(tsdn_t *tsdn, arena_t *arena, bool is_background_thread,
|
arena_decay_dirty(
|
||||||
bool all) {
|
tsdn_t *tsdn, arena_t *arena, bool is_background_thread, bool all) {
|
||||||
return arena_decay_impl(tsdn, arena, &arena->pa_shard.pac.decay_dirty,
|
return arena_decay_impl(tsdn, arena, &arena->pa_shard.pac.decay_dirty,
|
||||||
&arena->pa_shard.pac.stats->decay_dirty,
|
&arena->pa_shard.pac.stats->decay_dirty,
|
||||||
&arena->pa_shard.pac.ecache_dirty, is_background_thread, all);
|
&arena->pa_shard.pac.ecache_dirty, is_background_thread, all);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
arena_decay_muzzy(tsdn_t *tsdn, arena_t *arena, bool is_background_thread,
|
arena_decay_muzzy(
|
||||||
bool all) {
|
tsdn_t *tsdn, arena_t *arena, bool is_background_thread, bool all) {
|
||||||
if (pa_shard_dont_decay_muzzy(&arena->pa_shard)) {
|
if (pa_shard_dont_decay_muzzy(&arena->pa_shard)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -564,13 +558,13 @@ arena_should_decay_early(tsdn_t *tsdn, arena_t *arena, decay_t *decay,
|
|||||||
}
|
}
|
||||||
nstime_subtract(remaining_sleep, &decay->epoch);
|
nstime_subtract(remaining_sleep, &decay->epoch);
|
||||||
if (npages_new > 0) {
|
if (npages_new > 0) {
|
||||||
uint64_t npurge_new = decay_npages_purge_in(decay,
|
uint64_t npurge_new = decay_npages_purge_in(
|
||||||
remaining_sleep, npages_new);
|
decay, remaining_sleep, npages_new);
|
||||||
info->npages_to_purge_new += npurge_new;
|
info->npages_to_purge_new += npurge_new;
|
||||||
}
|
}
|
||||||
malloc_mutex_unlock(tsdn, &decay->mtx);
|
malloc_mutex_unlock(tsdn, &decay->mtx);
|
||||||
return info->npages_to_purge_new >
|
return info->npages_to_purge_new
|
||||||
ARENA_DEFERRED_PURGE_NPAGES_THRESHOLD;
|
> ARENA_DEFERRED_PURGE_NPAGES_THRESHOLD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -582,8 +576,8 @@ arena_should_decay_early(tsdn_t *tsdn, arena_t *arena, decay_t *decay,
|
|||||||
* deferred work has been generated.
|
* deferred work has been generated.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
arena_maybe_do_deferred_work(tsdn_t *tsdn, arena_t *arena, decay_t *decay,
|
arena_maybe_do_deferred_work(
|
||||||
size_t npages_new) {
|
tsdn_t *tsdn, arena_t *arena, decay_t *decay, size_t npages_new) {
|
||||||
background_thread_info_t *info = arena_background_thread_info_get(
|
background_thread_info_t *info = arena_background_thread_info_get(
|
||||||
arena);
|
arena);
|
||||||
if (malloc_mutex_trylock(tsdn, &info->mtx)) {
|
if (malloc_mutex_trylock(tsdn, &info->mtx)) {
|
||||||
@@ -687,8 +681,8 @@ arena_bin_reset(tsd_t *tsd, arena_t *arena, bin_t *bin, unsigned binind) {
|
|||||||
|
|
||||||
if (arena_bin_has_batch(binind)) {
|
if (arena_bin_has_batch(binind)) {
|
||||||
bin_with_batch_t *batched_bin = (bin_with_batch_t *)bin;
|
bin_with_batch_t *batched_bin = (bin_with_batch_t *)bin;
|
||||||
batcher_init(&batched_bin->remote_frees,
|
batcher_init(
|
||||||
BIN_REMOTE_FREE_ELEMS_MAX);
|
&batched_bin->remote_frees, BIN_REMOTE_FREE_ELEMS_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bin->slabcur != NULL) {
|
if (bin->slabcur != NULL) {
|
||||||
@@ -743,8 +737,8 @@ arena_prof_demote(tsdn_t *tsdn, edata_t *edata, const void *ptr) {
|
|||||||
assert(ptr != NULL);
|
assert(ptr != NULL);
|
||||||
size_t usize = isalloc(tsdn, ptr);
|
size_t usize = isalloc(tsdn, ptr);
|
||||||
size_t bumped_usize = sz_sa2u(usize, PROF_SAMPLE_ALIGNMENT);
|
size_t bumped_usize = sz_sa2u(usize, PROF_SAMPLE_ALIGNMENT);
|
||||||
assert(bumped_usize <= SC_LARGE_MINCLASS &&
|
assert(bumped_usize <= SC_LARGE_MINCLASS
|
||||||
PAGE_CEILING(bumped_usize) == bumped_usize);
|
&& PAGE_CEILING(bumped_usize) == bumped_usize);
|
||||||
assert(edata_size_get(edata) - bumped_usize <= sz_large_pad);
|
assert(edata_size_get(edata) - bumped_usize <= sz_large_pad);
|
||||||
szind_t szind = sz_size2index(bumped_usize);
|
szind_t szind = sz_size2index(bumped_usize);
|
||||||
|
|
||||||
@@ -757,8 +751,8 @@ arena_prof_demote(tsdn_t *tsdn, edata_t *edata, const void *ptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
arena_dalloc_promoted_impl(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
|
arena_dalloc_promoted_impl(
|
||||||
bool slow_path, edata_t *edata) {
|
tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool slow_path, edata_t *edata) {
|
||||||
cassert(config_prof);
|
cassert(config_prof);
|
||||||
assert(opt_prof);
|
assert(opt_prof);
|
||||||
|
|
||||||
@@ -772,20 +766,20 @@ arena_dalloc_promoted_impl(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
|
|||||||
safety_check_verify_redzone(ptr, usize, bumped_usize);
|
safety_check_verify_redzone(ptr, usize, bumped_usize);
|
||||||
}
|
}
|
||||||
szind_t bumped_ind = sz_size2index(bumped_usize);
|
szind_t bumped_ind = sz_size2index(bumped_usize);
|
||||||
if (bumped_usize >= SC_LARGE_MINCLASS &&
|
if (bumped_usize >= SC_LARGE_MINCLASS && tcache != NULL
|
||||||
tcache != NULL && bumped_ind < TCACHE_NBINS_MAX &&
|
&& bumped_ind < TCACHE_NBINS_MAX
|
||||||
!tcache_bin_disabled(bumped_ind, &tcache->bins[bumped_ind],
|
&& !tcache_bin_disabled(
|
||||||
tcache->tcache_slow)) {
|
bumped_ind, &tcache->bins[bumped_ind], tcache->tcache_slow)) {
|
||||||
tcache_dalloc_large(tsdn_tsd(tsdn), tcache, ptr, bumped_ind,
|
tcache_dalloc_large(
|
||||||
slow_path);
|
tsdn_tsd(tsdn), tcache, ptr, bumped_ind, slow_path);
|
||||||
} else {
|
} else {
|
||||||
large_dalloc(tsdn, edata);
|
large_dalloc(tsdn, edata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
arena_dalloc_promoted(tsdn_t *tsdn, void *ptr, tcache_t *tcache,
|
arena_dalloc_promoted(
|
||||||
bool slow_path) {
|
tsdn_t *tsdn, void *ptr, tcache_t *tcache, bool slow_path) {
|
||||||
edata_t *edata = emap_edata_lookup(tsdn, &arena_emap_global, ptr);
|
edata_t *edata = emap_edata_lookup(tsdn, &arena_emap_global, ptr);
|
||||||
arena_dalloc_promoted_impl(tsdn, ptr, tcache, slow_path, edata);
|
arena_dalloc_promoted_impl(tsdn, ptr, tcache, slow_path, edata);
|
||||||
}
|
}
|
||||||
@@ -816,8 +810,8 @@ arena_reset(tsd_t *tsd, arena_t *arena) {
|
|||||||
|
|
||||||
malloc_mutex_unlock(tsd_tsdn(tsd), &arena->large_mtx);
|
malloc_mutex_unlock(tsd_tsdn(tsd), &arena->large_mtx);
|
||||||
emap_alloc_ctx_t alloc_ctx;
|
emap_alloc_ctx_t alloc_ctx;
|
||||||
emap_alloc_ctx_lookup(tsd_tsdn(tsd), &arena_emap_global, ptr,
|
emap_alloc_ctx_lookup(
|
||||||
&alloc_ctx);
|
tsd_tsdn(tsd), &arena_emap_global, ptr, &alloc_ctx);
|
||||||
assert(alloc_ctx.szind != SC_NSIZES);
|
assert(alloc_ctx.szind != SC_NSIZES);
|
||||||
|
|
||||||
if (config_stats || (config_prof && opt_prof)) {
|
if (config_stats || (config_prof && opt_prof)) {
|
||||||
@@ -841,16 +835,16 @@ arena_reset(tsd_t *tsd, arena_t *arena) {
|
|||||||
/* Bins. */
|
/* Bins. */
|
||||||
for (unsigned i = 0; i < SC_NBINS; i++) {
|
for (unsigned i = 0; i < SC_NBINS; i++) {
|
||||||
for (unsigned j = 0; j < bin_infos[i].n_shards; j++) {
|
for (unsigned j = 0; j < bin_infos[i].n_shards; j++) {
|
||||||
arena_bin_reset(tsd, arena, arena_get_bin(arena, i, j),
|
arena_bin_reset(
|
||||||
i);
|
tsd, arena, arena_get_bin(arena, i, j), i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pa_shard_reset(tsd_tsdn(tsd), &arena->pa_shard);
|
pa_shard_reset(tsd_tsdn(tsd), &arena->pa_shard);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
arena_prepare_base_deletion_sync_finish(tsd_t *tsd, malloc_mutex_t **mutexes,
|
arena_prepare_base_deletion_sync_finish(
|
||||||
unsigned n_mtx) {
|
tsd_t *tsd, malloc_mutex_t **mutexes, unsigned n_mtx) {
|
||||||
for (unsigned i = 0; i < n_mtx; i++) {
|
for (unsigned i = 0; i < n_mtx; i++) {
|
||||||
malloc_mutex_lock(tsd_tsdn(tsd), mutexes[i]);
|
malloc_mutex_lock(tsd_tsdn(tsd), mutexes[i]);
|
||||||
malloc_mutex_unlock(tsd_tsdn(tsd), mutexes[i]);
|
malloc_mutex_unlock(tsd_tsdn(tsd), mutexes[i]);
|
||||||
@@ -921,12 +915,12 @@ arena_prepare_base_deletion(tsd_t *tsd, base_t *base_to_destroy) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
pac_t *pac = &arena->pa_shard.pac;
|
pac_t *pac = &arena->pa_shard.pac;
|
||||||
arena_prepare_base_deletion_sync(tsd, &pac->ecache_dirty.mtx,
|
arena_prepare_base_deletion_sync(
|
||||||
delayed_mtx, &n_delayed);
|
tsd, &pac->ecache_dirty.mtx, delayed_mtx, &n_delayed);
|
||||||
arena_prepare_base_deletion_sync(tsd, &pac->ecache_muzzy.mtx,
|
arena_prepare_base_deletion_sync(
|
||||||
delayed_mtx, &n_delayed);
|
tsd, &pac->ecache_muzzy.mtx, delayed_mtx, &n_delayed);
|
||||||
arena_prepare_base_deletion_sync(tsd, &pac->ecache_retained.mtx,
|
arena_prepare_base_deletion_sync(
|
||||||
delayed_mtx, &n_delayed);
|
tsd, &pac->ecache_retained.mtx, delayed_mtx, &n_delayed);
|
||||||
}
|
}
|
||||||
arena_prepare_base_deletion_sync_finish(tsd, delayed_mtx, n_delayed);
|
arena_prepare_base_deletion_sync_finish(tsd, delayed_mtx, n_delayed);
|
||||||
}
|
}
|
||||||
@@ -968,14 +962,14 @@ arena_destroy(tsd_t *tsd, arena_t *arena) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static edata_t *
|
static edata_t *
|
||||||
arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind, unsigned binshard,
|
arena_slab_alloc(tsdn_t *tsdn, arena_t *arena, szind_t binind,
|
||||||
const bin_info_t *bin_info) {
|
unsigned binshard, const bin_info_t *bin_info) {
|
||||||
bool deferred_work_generated = false;
|
bool deferred_work_generated = false;
|
||||||
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
witness_assert_depth_to_rank(
|
||||||
WITNESS_RANK_CORE, 0);
|
tsdn_witness_tsdp_get(tsdn), WITNESS_RANK_CORE, 0);
|
||||||
|
|
||||||
bool guarded = san_slab_extent_decide_guard(tsdn,
|
bool guarded = san_slab_extent_decide_guard(
|
||||||
arena_get_ehooks(arena));
|
tsdn, arena_get_ehooks(arena));
|
||||||
edata_t *slab = pa_alloc(tsdn, &arena->pa_shard, bin_info->slab_size,
|
edata_t *slab = pa_alloc(tsdn, &arena->pa_shard, bin_info->slab_size,
|
||||||
/* alignment */ PAGE, /* slab */ true, /* szind */ binind,
|
/* alignment */ PAGE, /* slab */ true, /* szind */ binind,
|
||||||
/* zero */ false, guarded, &deferred_work_generated);
|
/* zero */ false, guarded, &deferred_work_generated);
|
||||||
@@ -1024,15 +1018,15 @@ static void *
|
|||||||
arena_bin_malloc_with_fresh_slab(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
|
arena_bin_malloc_with_fresh_slab(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
|
||||||
szind_t binind, edata_t *fresh_slab) {
|
szind_t binind, edata_t *fresh_slab) {
|
||||||
malloc_mutex_assert_owner(tsdn, &bin->lock);
|
malloc_mutex_assert_owner(tsdn, &bin->lock);
|
||||||
arena_bin_refill_slabcur_with_fresh_slab(tsdn, arena, bin, binind,
|
arena_bin_refill_slabcur_with_fresh_slab(
|
||||||
fresh_slab);
|
tsdn, arena, bin, binind, fresh_slab);
|
||||||
|
|
||||||
return arena_slab_reg_alloc(bin->slabcur, &bin_infos[binind]);
|
return arena_slab_reg_alloc(bin->slabcur, &bin_infos[binind]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
arena_bin_refill_slabcur_no_fresh_slab(tsdn_t *tsdn, arena_t *arena,
|
arena_bin_refill_slabcur_no_fresh_slab(
|
||||||
bin_t *bin) {
|
tsdn_t *tsdn, arena_t *arena, bin_t *bin) {
|
||||||
malloc_mutex_assert_owner(tsdn, &bin->lock);
|
malloc_mutex_assert_owner(tsdn, &bin->lock);
|
||||||
/* Only called after arena_slab_reg_alloc[_batch] failed. */
|
/* Only called after arena_slab_reg_alloc[_batch] failed. */
|
||||||
assert(bin->slabcur == NULL || edata_nfree_get(bin->slabcur) == 0);
|
assert(bin->slabcur == NULL || edata_nfree_get(bin->slabcur) == 0);
|
||||||
@@ -1049,8 +1043,8 @@ arena_bin_refill_slabcur_no_fresh_slab(tsdn_t *tsdn, arena_t *arena,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bin_t *
|
bin_t *
|
||||||
arena_bin_choose(tsdn_t *tsdn, arena_t *arena, szind_t binind,
|
arena_bin_choose(
|
||||||
unsigned *binshard_p) {
|
tsdn_t *tsdn, arena_t *arena, szind_t binind, unsigned *binshard_p) {
|
||||||
unsigned binshard;
|
unsigned binshard;
|
||||||
if (tsdn_null(tsdn) || tsd_arena_get(tsdn_tsd(tsdn)) == NULL) {
|
if (tsdn_null(tsdn) || tsd_arena_get(tsdn_tsd(tsdn)) == NULL) {
|
||||||
binshard = 0;
|
binshard = 0;
|
||||||
@@ -1065,8 +1059,8 @@ arena_bin_choose(tsdn_t *tsdn, arena_t *arena, szind_t binind,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
arena_cache_bin_fill_small(tsdn_t *tsdn, arena_t *arena,
|
arena_cache_bin_fill_small(tsdn_t *tsdn, arena_t *arena, cache_bin_t *cache_bin,
|
||||||
cache_bin_t *cache_bin, szind_t binind, const cache_bin_sz_t nfill_min,
|
szind_t binind, const cache_bin_sz_t nfill_min,
|
||||||
const cache_bin_sz_t nfill_max) {
|
const cache_bin_sz_t nfill_max) {
|
||||||
assert(cache_bin_ncached_get_local(cache_bin) == 0);
|
assert(cache_bin_ncached_get_local(cache_bin) == 0);
|
||||||
assert(nfill_min > 0 && nfill_min <= nfill_max);
|
assert(nfill_min > 0 && nfill_min <= nfill_max);
|
||||||
@@ -1120,7 +1114,8 @@ arena_cache_bin_fill_small(tsdn_t *tsdn, arena_t *arena,
|
|||||||
JEMALLOC_CLANG_ANALYZER_SILENCE_INIT({0});
|
JEMALLOC_CLANG_ANALYZER_SILENCE_INIT({0});
|
||||||
label_refill:
|
label_refill:
|
||||||
malloc_mutex_lock(tsdn, &bin->lock);
|
malloc_mutex_lock(tsdn, &bin->lock);
|
||||||
arena_bin_flush_batch_after_lock(tsdn, arena, bin, binind, &batch_flush_state);
|
arena_bin_flush_batch_after_lock(
|
||||||
|
tsdn, arena, bin, binind, &batch_flush_state);
|
||||||
|
|
||||||
while (filled < nfill_min) {
|
while (filled < nfill_min) {
|
||||||
/* Try batch-fill from slabcur first. */
|
/* Try batch-fill from slabcur first. */
|
||||||
@@ -1136,8 +1131,8 @@ label_refill:
|
|||||||
cnt = nfill_min - filled;
|
cnt = nfill_min - filled;
|
||||||
}
|
}
|
||||||
|
|
||||||
arena_slab_reg_alloc_batch(slabcur, bin_info, cnt,
|
arena_slab_reg_alloc_batch(
|
||||||
&ptrs.ptr[filled]);
|
slabcur, bin_info, cnt, &ptrs.ptr[filled]);
|
||||||
made_progress = true;
|
made_progress = true;
|
||||||
filled += cnt;
|
filled += cnt;
|
||||||
continue;
|
continue;
|
||||||
@@ -1150,8 +1145,8 @@ label_refill:
|
|||||||
|
|
||||||
/* Then see if a new slab was reserved already. */
|
/* Then see if a new slab was reserved already. */
|
||||||
if (fresh_slab != NULL) {
|
if (fresh_slab != NULL) {
|
||||||
arena_bin_refill_slabcur_with_fresh_slab(tsdn, arena,
|
arena_bin_refill_slabcur_with_fresh_slab(
|
||||||
bin, binind, fresh_slab);
|
tsdn, arena, bin, binind, fresh_slab);
|
||||||
assert(bin->slabcur != NULL);
|
assert(bin->slabcur != NULL);
|
||||||
fresh_slab = NULL;
|
fresh_slab = NULL;
|
||||||
continue;
|
continue;
|
||||||
@@ -1181,27 +1176,27 @@ label_refill:
|
|||||||
cache_bin->tstats.nrequests = 0;
|
cache_bin->tstats.nrequests = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
arena_bin_flush_batch_before_unlock(tsdn, arena, bin, binind,
|
arena_bin_flush_batch_before_unlock(
|
||||||
&batch_flush_state);
|
tsdn, arena, bin, binind, &batch_flush_state);
|
||||||
malloc_mutex_unlock(tsdn, &bin->lock);
|
malloc_mutex_unlock(tsdn, &bin->lock);
|
||||||
arena_bin_flush_batch_after_unlock(tsdn, arena, bin, binind,
|
arena_bin_flush_batch_after_unlock(
|
||||||
&batch_flush_state);
|
tsdn, arena, bin, binind, &batch_flush_state);
|
||||||
|
|
||||||
if (alloc_and_retry) {
|
if (alloc_and_retry) {
|
||||||
assert(fresh_slab == NULL);
|
assert(fresh_slab == NULL);
|
||||||
assert(filled < nfill_min);
|
assert(filled < nfill_min);
|
||||||
assert(made_progress);
|
assert(made_progress);
|
||||||
|
|
||||||
fresh_slab = arena_slab_alloc(tsdn, arena, binind, binshard,
|
fresh_slab = arena_slab_alloc(
|
||||||
bin_info);
|
tsdn, arena, binind, binshard, bin_info);
|
||||||
/* fresh_slab NULL case handled in the for loop. */
|
/* fresh_slab NULL case handled in the for loop. */
|
||||||
|
|
||||||
alloc_and_retry = false;
|
alloc_and_retry = false;
|
||||||
made_progress = false;
|
made_progress = false;
|
||||||
goto label_refill;
|
goto label_refill;
|
||||||
}
|
}
|
||||||
assert((filled >= nfill_min && filled <= nfill_max) ||
|
assert((filled >= nfill_min && filled <= nfill_max)
|
||||||
(fresh_slab == NULL && !made_progress));
|
|| (fresh_slab == NULL && !made_progress));
|
||||||
|
|
||||||
/* Release if allocated but not used. */
|
/* Release if allocated but not used. */
|
||||||
if (fresh_slab != NULL) {
|
if (fresh_slab != NULL) {
|
||||||
@@ -1233,8 +1228,10 @@ arena_fill_small_fresh(tsdn_t *tsdn, arena_t *arena, szind_t binind,
|
|||||||
edata_list_active_t fulls;
|
edata_list_active_t fulls;
|
||||||
edata_list_active_init(&fulls);
|
edata_list_active_init(&fulls);
|
||||||
|
|
||||||
while (filled < nfill && (slab = arena_slab_alloc(tsdn, arena, binind,
|
while (filled < nfill
|
||||||
binshard, bin_info)) != NULL) {
|
&& (slab = arena_slab_alloc(
|
||||||
|
tsdn, arena, binind, binshard, bin_info))
|
||||||
|
!= NULL) {
|
||||||
assert((size_t)edata_nfree_get(slab) == nregs);
|
assert((size_t)edata_nfree_get(slab) == nregs);
|
||||||
++nslab;
|
++nslab;
|
||||||
size_t batch = nfill - filled;
|
size_t batch = nfill - filled;
|
||||||
@@ -1242,8 +1239,8 @@ arena_fill_small_fresh(tsdn_t *tsdn, arena_t *arena, szind_t binind,
|
|||||||
batch = nregs;
|
batch = nregs;
|
||||||
}
|
}
|
||||||
assert(batch > 0);
|
assert(batch > 0);
|
||||||
arena_slab_reg_alloc_batch(slab, bin_info, (unsigned)batch,
|
arena_slab_reg_alloc_batch(
|
||||||
&ptrs[filled]);
|
slab, bin_info, (unsigned)batch, &ptrs[filled]);
|
||||||
assert(edata_addr_get(slab) == ptrs[filled]);
|
assert(edata_addr_get(slab) == ptrs[filled]);
|
||||||
if (zero) {
|
if (zero) {
|
||||||
memset(ptrs[filled], 0, batch * usize);
|
memset(ptrs[filled], 0, batch * usize);
|
||||||
@@ -1287,8 +1284,8 @@ arena_fill_small_fresh(tsdn_t *tsdn, arena_t *arena, szind_t binind,
|
|||||||
* bin->slabcur if necessary.
|
* bin->slabcur if necessary.
|
||||||
*/
|
*/
|
||||||
static void *
|
static void *
|
||||||
arena_bin_malloc_no_fresh_slab(tsdn_t *tsdn, arena_t *arena, bin_t *bin,
|
arena_bin_malloc_no_fresh_slab(
|
||||||
szind_t binind) {
|
tsdn_t *tsdn, arena_t *arena, bin_t *bin, szind_t binind) {
|
||||||
malloc_mutex_assert_owner(tsdn, &bin->lock);
|
malloc_mutex_assert_owner(tsdn, &bin->lock);
|
||||||
if (bin->slabcur == NULL || edata_nfree_get(bin->slabcur) == 0) {
|
if (bin->slabcur == NULL || edata_nfree_get(bin->slabcur) == 0) {
|
||||||
if (arena_bin_refill_slabcur_no_fresh_slab(tsdn, arena, bin)) {
|
if (arena_bin_refill_slabcur_no_fresh_slab(tsdn, arena, bin)) {
|
||||||
@@ -1314,8 +1311,8 @@ arena_malloc_small(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) {
|
|||||||
if (ret == NULL) {
|
if (ret == NULL) {
|
||||||
malloc_mutex_unlock(tsdn, &bin->lock);
|
malloc_mutex_unlock(tsdn, &bin->lock);
|
||||||
/******************************/
|
/******************************/
|
||||||
fresh_slab = arena_slab_alloc(tsdn, arena, binind, binshard,
|
fresh_slab = arena_slab_alloc(
|
||||||
bin_info);
|
tsdn, arena, binind, binshard, bin_info);
|
||||||
/********************************/
|
/********************************/
|
||||||
malloc_mutex_lock(tsdn, &bin->lock);
|
malloc_mutex_lock(tsdn, &bin->lock);
|
||||||
/* Retry since the lock was dropped. */
|
/* Retry since the lock was dropped. */
|
||||||
@@ -1326,8 +1323,8 @@ arena_malloc_small(tsdn_t *tsdn, arena_t *arena, szind_t binind, bool zero) {
|
|||||||
malloc_mutex_unlock(tsdn, &bin->lock);
|
malloc_mutex_unlock(tsdn, &bin->lock);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ret = arena_bin_malloc_with_fresh_slab(tsdn, arena, bin,
|
ret = arena_bin_malloc_with_fresh_slab(
|
||||||
binind, fresh_slab);
|
tsdn, arena, bin, binind, fresh_slab);
|
||||||
fresh_slab = NULL;
|
fresh_slab = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1390,7 +1387,8 @@ arena_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment,
|
|||||||
if (likely(alignment <= CACHELINE)) {
|
if (likely(alignment <= CACHELINE)) {
|
||||||
return large_malloc(tsdn, arena, usize, zero);
|
return large_malloc(tsdn, arena, usize, zero);
|
||||||
} else {
|
} else {
|
||||||
return large_palloc(tsdn, arena, usize, alignment, zero);
|
return large_palloc(
|
||||||
|
tsdn, arena, usize, alignment, zero);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1418,8 +1416,7 @@ arena_dissociate_bin_slab(arena_t *arena, edata_t *slab, bin_t *bin) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, edata_t *slab,
|
arena_bin_lower_slab(tsdn_t *tsdn, arena_t *arena, edata_t *slab, bin_t *bin) {
|
||||||
bin_t *bin) {
|
|
||||||
assert(edata_nfree_get(slab) > 0);
|
assert(edata_nfree_get(slab) > 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1455,15 +1452,15 @@ arena_dalloc_bin_slab_prepare(tsdn_t *tsdn, edata_t *slab, bin_t *bin) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
arena_dalloc_bin_locked_handle_newly_empty(tsdn_t *tsdn, arena_t *arena,
|
arena_dalloc_bin_locked_handle_newly_empty(
|
||||||
edata_t *slab, bin_t *bin) {
|
tsdn_t *tsdn, arena_t *arena, edata_t *slab, bin_t *bin) {
|
||||||
arena_dissociate_bin_slab(arena, slab, bin);
|
arena_dissociate_bin_slab(arena, slab, bin);
|
||||||
arena_dalloc_bin_slab_prepare(tsdn, slab, bin);
|
arena_dalloc_bin_slab_prepare(tsdn, slab, bin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
arena_dalloc_bin_locked_handle_newly_nonempty(tsdn_t *tsdn, arena_t *arena,
|
arena_dalloc_bin_locked_handle_newly_nonempty(
|
||||||
edata_t *slab, bin_t *bin) {
|
tsdn_t *tsdn, arena_t *arena, edata_t *slab, bin_t *bin) {
|
||||||
arena_bin_slabs_full_remove(arena, bin, slab);
|
arena_bin_slabs_full_remove(arena, bin, slab);
|
||||||
arena_bin_lower_slab(tsdn, arena, slab, bin);
|
arena_bin_lower_slab(tsdn, arena, slab, bin);
|
||||||
}
|
}
|
||||||
@@ -1515,14 +1512,13 @@ arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
|||||||
|
|
||||||
size_t usize_min = sz_s2u(size);
|
size_t usize_min = sz_s2u(size);
|
||||||
size_t usize_max = sz_s2u(size + extra);
|
size_t usize_max = sz_s2u(size + extra);
|
||||||
if (likely(oldsize <= SC_SMALL_MAXCLASS && usize_min
|
if (likely(oldsize <= SC_SMALL_MAXCLASS
|
||||||
<= SC_SMALL_MAXCLASS)) {
|
&& usize_min <= SC_SMALL_MAXCLASS)) {
|
||||||
/*
|
/*
|
||||||
* Avoid moving the allocation if the size class can be left the
|
* Avoid moving the allocation if the size class can be left the
|
||||||
* same.
|
* same.
|
||||||
*/
|
*/
|
||||||
assert(bin_infos[sz_size2index(oldsize)].reg_size ==
|
assert(bin_infos[sz_size2index(oldsize)].reg_size == oldsize);
|
||||||
oldsize);
|
|
||||||
if ((usize_max > SC_SMALL_MAXCLASS
|
if ((usize_max > SC_SMALL_MAXCLASS
|
||||||
|| sz_size2index(usize_max) != sz_size2index(oldsize))
|
|| sz_size2index(usize_max) != sz_size2index(oldsize))
|
||||||
&& (size > oldsize || usize_max < oldsize)) {
|
&& (size > oldsize || usize_max < oldsize)) {
|
||||||
@@ -1535,8 +1531,8 @@ arena_ralloc_no_move(tsdn_t *tsdn, void *ptr, size_t oldsize, size_t size,
|
|||||||
ret = false;
|
ret = false;
|
||||||
} else if (oldsize >= SC_LARGE_MINCLASS
|
} else if (oldsize >= SC_LARGE_MINCLASS
|
||||||
&& usize_max >= SC_LARGE_MINCLASS) {
|
&& usize_max >= SC_LARGE_MINCLASS) {
|
||||||
ret = large_ralloc_no_move(tsdn, edata, usize_min, usize_max,
|
ret = large_ralloc_no_move(
|
||||||
zero);
|
tsdn, edata, usize_min, usize_max, zero);
|
||||||
} else {
|
} else {
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
@@ -1558,8 +1554,8 @@ arena_ralloc_move_helper(tsdn_t *tsdn, arena_t *arena, size_t usize,
|
|||||||
if (unlikely(usize == 0 || usize > SC_LARGE_MAXCLASS)) {
|
if (unlikely(usize == 0 || usize > SC_LARGE_MAXCLASS)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return ipalloct_explicit_slab(tsdn, usize, alignment, zero, slab,
|
return ipalloct_explicit_slab(
|
||||||
tcache, arena);
|
tsdn, usize, alignment, zero, slab, tcache, arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
@@ -1575,37 +1571,38 @@ arena_ralloc(tsdn_t *tsdn, arena_t *arena, void *ptr, size_t oldsize,
|
|||||||
assert(sz_can_use_slab(usize));
|
assert(sz_can_use_slab(usize));
|
||||||
/* Try to avoid moving the allocation. */
|
/* Try to avoid moving the allocation. */
|
||||||
UNUSED size_t newsize;
|
UNUSED size_t newsize;
|
||||||
if (!arena_ralloc_no_move(tsdn, ptr, oldsize, usize, 0, zero,
|
if (!arena_ralloc_no_move(
|
||||||
&newsize)) {
|
tsdn, ptr, oldsize, usize, 0, zero, &newsize)) {
|
||||||
hook_invoke_expand(hook_args->is_realloc
|
hook_invoke_expand(hook_args->is_realloc
|
||||||
? hook_expand_realloc : hook_expand_rallocx,
|
? hook_expand_realloc
|
||||||
|
: hook_expand_rallocx,
|
||||||
ptr, oldsize, usize, (uintptr_t)ptr,
|
ptr, oldsize, usize, (uintptr_t)ptr,
|
||||||
hook_args->args);
|
hook_args->args);
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldsize >= SC_LARGE_MINCLASS
|
if (oldsize >= SC_LARGE_MINCLASS && usize >= SC_LARGE_MINCLASS) {
|
||||||
&& usize >= SC_LARGE_MINCLASS) {
|
return large_ralloc(tsdn, arena, ptr, usize, alignment, zero,
|
||||||
return large_ralloc(tsdn, arena, ptr, usize,
|
tcache, hook_args);
|
||||||
alignment, zero, tcache, hook_args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* size and oldsize are different enough that we need to move the
|
* size and oldsize are different enough that we need to move the
|
||||||
* object. In that case, fall back to allocating new space and copying.
|
* object. In that case, fall back to allocating new space and copying.
|
||||||
*/
|
*/
|
||||||
void *ret = arena_ralloc_move_helper(tsdn, arena, usize, alignment,
|
void *ret = arena_ralloc_move_helper(
|
||||||
zero, slab, tcache);
|
tsdn, arena, usize, alignment, zero, slab, tcache);
|
||||||
if (ret == NULL) {
|
if (ret == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
hook_invoke_alloc(hook_args->is_realloc
|
hook_invoke_alloc(
|
||||||
? hook_alloc_realloc : hook_alloc_rallocx, ret, (uintptr_t)ret,
|
hook_args->is_realloc ? hook_alloc_realloc : hook_alloc_rallocx,
|
||||||
hook_args->args);
|
ret, (uintptr_t)ret, hook_args->args);
|
||||||
hook_invoke_dalloc(hook_args->is_realloc
|
hook_invoke_dalloc(
|
||||||
? hook_dalloc_realloc : hook_dalloc_rallocx, ptr, hook_args->args);
|
hook_args->is_realloc ? hook_dalloc_realloc : hook_dalloc_rallocx,
|
||||||
|
ptr, hook_args->args);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Junk/zero-filling were already done by
|
* Junk/zero-filling were already done by
|
||||||
@@ -1623,8 +1620,8 @@ arena_get_ehooks(arena_t *arena) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extent_hooks_t *
|
extent_hooks_t *
|
||||||
arena_set_extent_hooks(tsd_t *tsd, arena_t *arena,
|
arena_set_extent_hooks(
|
||||||
extent_hooks_t *extent_hooks) {
|
tsd_t *tsd, arena_t *arena, extent_hooks_t *extent_hooks) {
|
||||||
background_thread_info_t *info;
|
background_thread_info_t *info;
|
||||||
if (have_background_thread) {
|
if (have_background_thread) {
|
||||||
info = arena_background_thread_info_get(arena);
|
info = arena_background_thread_info_get(arena);
|
||||||
@@ -1699,11 +1696,11 @@ arena_muzzy_decay_ms_default_set(ssize_t decay_ms) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
arena_retain_grow_limit_get_set(tsd_t *tsd, arena_t *arena, size_t *old_limit,
|
arena_retain_grow_limit_get_set(
|
||||||
size_t *new_limit) {
|
tsd_t *tsd, arena_t *arena, size_t *old_limit, size_t *new_limit) {
|
||||||
assert(opt_retain);
|
assert(opt_retain);
|
||||||
return pac_retain_grow_limit_get_set(tsd_tsdn(tsd),
|
return pac_retain_grow_limit_get_set(
|
||||||
&arena->pa_shard.pac, old_limit, new_limit);
|
tsd_tsdn(tsd), &arena->pa_shard.pac, old_limit, new_limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned
|
unsigned
|
||||||
@@ -1736,8 +1733,8 @@ arena_new(tsdn_t *tsdn, unsigned ind, const arena_config_t *config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t arena_size = ALIGNMENT_CEILING(sizeof(arena_t), CACHELINE) +
|
size_t arena_size = ALIGNMENT_CEILING(sizeof(arena_t), CACHELINE)
|
||||||
sizeof(bin_with_batch_t) * bin_info_nbatched_bins
|
+ sizeof(bin_with_batch_t) * bin_info_nbatched_bins
|
||||||
+ sizeof(bin_t) * bin_info_nunbatched_bins;
|
+ sizeof(bin_t) * bin_info_nunbatched_bins;
|
||||||
arena = (arena_t *)base_alloc(tsdn, base, arena_size, CACHELINE);
|
arena = (arena_t *)base_alloc(tsdn, base, arena_size, CACHELINE);
|
||||||
if (arena == NULL) {
|
if (arena == NULL) {
|
||||||
@@ -1761,8 +1758,8 @@ arena_new(tsdn_t *tsdn, unsigned ind, const arena_config_t *config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_store_u(&arena->dss_prec, (unsigned)extent_dss_prec_get(),
|
atomic_store_u(
|
||||||
ATOMIC_RELAXED);
|
&arena->dss_prec, (unsigned)extent_dss_prec_get(), ATOMIC_RELAXED);
|
||||||
|
|
||||||
edata_list_active_init(&arena->large);
|
edata_list_active_init(&arena->large);
|
||||||
if (malloc_mutex_init(&arena->large_mtx, "arena_large",
|
if (malloc_mutex_init(&arena->large_mtx, "arena_large",
|
||||||
@@ -1814,8 +1811,8 @@ arena_new(tsdn_t *tsdn, unsigned ind, const arena_config_t *config) {
|
|||||||
if (opt_hpa && ehooks_are_default(base_ehooks_get(base)) && ind != 0) {
|
if (opt_hpa && ehooks_are_default(base_ehooks_get(base)) && ind != 0) {
|
||||||
hpa_shard_opts_t hpa_shard_opts = opt_hpa_opts;
|
hpa_shard_opts_t hpa_shard_opts = opt_hpa_opts;
|
||||||
hpa_shard_opts.deferral_allowed = background_thread_enabled();
|
hpa_shard_opts.deferral_allowed = background_thread_enabled();
|
||||||
if (pa_shard_enable_hpa(tsdn, &arena->pa_shard,
|
if (pa_shard_enable_hpa(tsdn, &arena->pa_shard, &hpa_shard_opts,
|
||||||
&hpa_shard_opts, &opt_hpa_sec_opts)) {
|
&opt_hpa_sec_opts)) {
|
||||||
goto label_error;
|
goto label_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1866,13 +1863,13 @@ arena_create_huge_arena(tsd_t *tsd, unsigned ind) {
|
|||||||
*/
|
*/
|
||||||
if (!background_thread_enabled()
|
if (!background_thread_enabled()
|
||||||
&& arena_dirty_decay_ms_default_get() > 0) {
|
&& arena_dirty_decay_ms_default_get() > 0) {
|
||||||
arena_decay_ms_set(tsd_tsdn(tsd), huge_arena,
|
arena_decay_ms_set(
|
||||||
extent_state_dirty, 0);
|
tsd_tsdn(tsd), huge_arena, extent_state_dirty, 0);
|
||||||
}
|
}
|
||||||
if (!background_thread_enabled()
|
if (!background_thread_enabled()
|
||||||
&& arena_muzzy_decay_ms_default_get() > 0) {
|
&& arena_muzzy_decay_ms_default_get() > 0) {
|
||||||
arena_decay_ms_set(tsd_tsdn(tsd), huge_arena,
|
arena_decay_ms_set(
|
||||||
extent_state_muzzy, 0);
|
tsd_tsdn(tsd), huge_arena, extent_state_muzzy, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return huge_arena;
|
return huge_arena;
|
||||||
@@ -1900,8 +1897,8 @@ arena_init_huge(tsdn_t *tsdn, arena_t *a0) {
|
|||||||
assert(huge_arena_ind == 0);
|
assert(huge_arena_ind == 0);
|
||||||
|
|
||||||
/* The threshold should be large size class. */
|
/* The threshold should be large size class. */
|
||||||
if (opt_oversize_threshold > SC_LARGE_MAXCLASS ||
|
if (opt_oversize_threshold > SC_LARGE_MAXCLASS
|
||||||
opt_oversize_threshold < SC_LARGE_MINCLASS) {
|
|| opt_oversize_threshold < SC_LARGE_MINCLASS) {
|
||||||
opt_oversize_threshold = 0;
|
opt_oversize_threshold = 0;
|
||||||
oversize_threshold = SC_LARGE_MAXCLASS + PAGE;
|
oversize_threshold = SC_LARGE_MAXCLASS + PAGE;
|
||||||
huge_enabled = false;
|
huge_enabled = false;
|
||||||
@@ -1917,10 +1914,11 @@ arena_init_huge(tsdn_t *tsdn, arena_t *a0) {
|
|||||||
base_t *b0 = a0->base;
|
base_t *b0 = a0->base;
|
||||||
/* Make sure that b0 thp auto-switch won't happen concurrently here. */
|
/* Make sure that b0 thp auto-switch won't happen concurrently here. */
|
||||||
malloc_mutex_lock(tsdn, &b0->mtx);
|
malloc_mutex_lock(tsdn, &b0->mtx);
|
||||||
(&huge_arena_pac_thp)->thp_madvise = opt_huge_arena_pac_thp &&
|
(&huge_arena_pac_thp)->thp_madvise = opt_huge_arena_pac_thp
|
||||||
metadata_thp_enabled() && (opt_thp == thp_mode_default) &&
|
&& metadata_thp_enabled() && (opt_thp == thp_mode_default)
|
||||||
(init_system_thp_mode == thp_mode_default);
|
&& (init_system_thp_mode == thp_mode_default);
|
||||||
(&huge_arena_pac_thp)->auto_thp_switched = b0->auto_thp_switched;
|
(&huge_arena_pac_thp)->auto_thp_switched =
|
||||||
|
b0->auto_thp_switched;
|
||||||
malloc_mutex_init(&(&huge_arena_pac_thp)->lock, "pac_thp",
|
malloc_mutex_init(&(&huge_arena_pac_thp)->lock, "pac_thp",
|
||||||
WITNESS_RANK_LEAF, malloc_mutex_rank_exclusive);
|
WITNESS_RANK_LEAF, malloc_mutex_rank_exclusive);
|
||||||
edata_list_active_init(&(&huge_arena_pac_thp)->thp_lazy_list);
|
edata_list_active_init(&(&huge_arena_pac_thp)->thp_lazy_list);
|
||||||
@@ -1942,16 +1940,16 @@ arena_boot(sc_data_t *sc_data, base_t *base, bool hpa) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_SUPPRESS_WARN_ON_USAGE(
|
JEMALLOC_SUPPRESS_WARN_ON_USAGE(
|
||||||
uint32_t cur_offset = (uint32_t)offsetof(arena_t, all_bins);
|
uint32_t cur_offset = (uint32_t)offsetof(arena_t, all_bins);)
|
||||||
)
|
|
||||||
for (szind_t i = 0; i < SC_NBINS; i++) {
|
for (szind_t i = 0; i < SC_NBINS; i++) {
|
||||||
arena_bin_offsets[i] = cur_offset;
|
arena_bin_offsets[i] = cur_offset;
|
||||||
uint32_t bin_sz = (i < bin_info_nbatched_sizes
|
uint32_t bin_sz = (i < bin_info_nbatched_sizes
|
||||||
? sizeof(bin_with_batch_t) : sizeof(bin_t));
|
? sizeof(bin_with_batch_t)
|
||||||
|
: sizeof(bin_t));
|
||||||
cur_offset += (uint32_t)bin_infos[i].n_shards * bin_sz;
|
cur_offset += (uint32_t)bin_infos[i].n_shards * bin_sz;
|
||||||
}
|
}
|
||||||
return pa_central_init(&arena_pa_central_global, base, hpa,
|
return pa_central_init(
|
||||||
&hpa_hooks_default);
|
&arena_pa_central_global, base, hpa, &hpa_hooks_default);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ pthread_create_fptr_init(void) {
|
|||||||
# endif
|
# endif
|
||||||
if (pthread_create_fptr == NULL) {
|
if (pthread_create_fptr == NULL) {
|
||||||
if (config_lazy_lock) {
|
if (config_lazy_lock) {
|
||||||
malloc_write("<jemalloc>: Error in dlsym(RTLD_NEXT, "
|
malloc_write(
|
||||||
|
"<jemalloc>: Error in dlsym(RTLD_NEXT, "
|
||||||
"\"pthread_create\")\n");
|
"\"pthread_create\")\n");
|
||||||
abort();
|
abort();
|
||||||
} else {
|
} else {
|
||||||
@@ -85,19 +86,22 @@ pthread_create_fptr_init(void) {
|
|||||||
#endif /* JEMALLOC_PTHREAD_CREATE_WRAPPER */
|
#endif /* JEMALLOC_PTHREAD_CREATE_WRAPPER */
|
||||||
|
|
||||||
#ifndef JEMALLOC_BACKGROUND_THREAD
|
#ifndef JEMALLOC_BACKGROUND_THREAD
|
||||||
#define NOT_REACHED { not_reached(); }
|
# define NOT_REACHED \
|
||||||
bool background_thread_create(tsd_t *tsd, unsigned arena_ind) NOT_REACHED
|
{ not_reached(); }
|
||||||
|
bool
|
||||||
|
background_thread_create(tsd_t *tsd, unsigned arena_ind) NOT_REACHED
|
||||||
bool background_threads_enable(tsd_t *tsd) NOT_REACHED
|
bool background_threads_enable(tsd_t *tsd) NOT_REACHED
|
||||||
bool background_threads_disable(tsd_t *tsd) NOT_REACHED
|
bool background_threads_disable(tsd_t *tsd) NOT_REACHED
|
||||||
bool background_thread_is_started(background_thread_info_t *info) NOT_REACHED
|
bool background_thread_is_started(
|
||||||
void background_thread_wakeup_early(background_thread_info_t *info,
|
background_thread_info_t *info) NOT_REACHED
|
||||||
nstime_t *remaining_sleep) NOT_REACHED
|
void background_thread_wakeup_early(
|
||||||
|
background_thread_info_t *info, nstime_t *remaining_sleep) NOT_REACHED
|
||||||
void background_thread_prefork0(tsdn_t *tsdn) NOT_REACHED
|
void background_thread_prefork0(tsdn_t *tsdn) NOT_REACHED
|
||||||
void background_thread_prefork1(tsdn_t *tsdn) NOT_REACHED
|
void background_thread_prefork1(tsdn_t *tsdn) NOT_REACHED
|
||||||
void background_thread_postfork_parent(tsdn_t *tsdn) NOT_REACHED
|
void background_thread_postfork_parent(tsdn_t *tsdn) NOT_REACHED
|
||||||
void background_thread_postfork_child(tsdn_t *tsdn) NOT_REACHED
|
void background_thread_postfork_child(tsdn_t *tsdn) NOT_REACHED
|
||||||
bool background_thread_stats_read(tsdn_t *tsdn,
|
bool background_thread_stats_read(
|
||||||
background_thread_stats_t *stats) NOT_REACHED
|
tsdn_t *tsdn, background_thread_stats_t *stats) NOT_REACHED
|
||||||
void background_thread_ctl_init(tsdn_t *tsdn) NOT_REACHED
|
void background_thread_ctl_init(tsdn_t *tsdn) NOT_REACHED
|
||||||
# undef NOT_REACHED
|
# undef NOT_REACHED
|
||||||
#else
|
#else
|
||||||
@@ -116,7 +120,8 @@ background_thread_info_init(tsdn_t *tsdn, background_thread_info_t *info) {
|
|||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
set_current_thread_affinity(int cpu) {
|
set_current_thread_affinity(int cpu) {
|
||||||
#if defined(JEMALLOC_HAVE_SCHED_SETAFFINITY) || defined(JEMALLOC_HAVE_PTHREAD_SETAFFINITY_NP)
|
# if defined(JEMALLOC_HAVE_SCHED_SETAFFINITY) \
|
||||||
|
|| defined(JEMALLOC_HAVE_PTHREAD_SETAFFINITY_NP)
|
||||||
# if defined(JEMALLOC_HAVE_SCHED_SETAFFINITY)
|
# if defined(JEMALLOC_HAVE_SCHED_SETAFFINITY)
|
||||||
cpu_set_t cpuset;
|
cpu_set_t cpuset;
|
||||||
# else
|
# else
|
||||||
@@ -138,11 +143,11 @@ set_current_thread_affinity(int cpu) {
|
|||||||
return (sched_setaffinity(0, sizeof(cpu_set_t), &cpuset) != 0);
|
return (sched_setaffinity(0, sizeof(cpu_set_t), &cpuset) != 0);
|
||||||
# else
|
# else
|
||||||
# ifndef __NetBSD__
|
# ifndef __NetBSD__
|
||||||
int ret = pthread_setaffinity_np(pthread_self(), sizeof(cpuset_t),
|
int ret = pthread_setaffinity_np(
|
||||||
&cpuset);
|
pthread_self(), sizeof(cpuset_t), &cpuset);
|
||||||
# else
|
# else
|
||||||
int ret = pthread_setaffinity_np(pthread_self(), cpuset_size(cpuset),
|
int ret = pthread_setaffinity_np(
|
||||||
cpuset);
|
pthread_self(), cpuset_size(cpuset), cpuset);
|
||||||
cpuset_destroy(cpuset);
|
cpuset_destroy(cpuset);
|
||||||
# endif
|
# endif
|
||||||
return ret != 0;
|
return ret != 0;
|
||||||
@@ -157,8 +162,8 @@ set_current_thread_affinity(int cpu) {
|
|||||||
# define BACKGROUND_THREAD_MIN_INTERVAL_NS (BILLION / 10)
|
# define BACKGROUND_THREAD_MIN_INTERVAL_NS (BILLION / 10)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
background_thread_cond_wait(background_thread_info_t *info,
|
background_thread_cond_wait(
|
||||||
struct timespec *ts) {
|
background_thread_info_t *info, struct timespec *ts) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -177,8 +182,8 @@ background_thread_cond_wait(background_thread_info_t *info,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
background_thread_sleep(tsdn_t *tsdn, background_thread_info_t *info,
|
background_thread_sleep(
|
||||||
uint64_t interval) {
|
tsdn_t *tsdn, background_thread_info_t *info, uint64_t interval) {
|
||||||
if (config_stats) {
|
if (config_stats) {
|
||||||
info->tot_n_runs++;
|
info->tot_n_runs++;
|
||||||
}
|
}
|
||||||
@@ -192,21 +197,21 @@ background_thread_sleep(tsdn_t *tsdn, background_thread_info_t *info,
|
|||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
if (interval == BACKGROUND_THREAD_INDEFINITE_SLEEP) {
|
if (interval == BACKGROUND_THREAD_INDEFINITE_SLEEP) {
|
||||||
background_thread_wakeup_time_set(tsdn, info,
|
background_thread_wakeup_time_set(
|
||||||
BACKGROUND_THREAD_INDEFINITE_SLEEP);
|
tsdn, info, BACKGROUND_THREAD_INDEFINITE_SLEEP);
|
||||||
ret = background_thread_cond_wait(info, NULL);
|
ret = background_thread_cond_wait(info, NULL);
|
||||||
assert(ret == 0);
|
assert(ret == 0);
|
||||||
} else {
|
} else {
|
||||||
assert(interval >= BACKGROUND_THREAD_MIN_INTERVAL_NS &&
|
assert(interval >= BACKGROUND_THREAD_MIN_INTERVAL_NS
|
||||||
interval <= BACKGROUND_THREAD_INDEFINITE_SLEEP);
|
&& interval <= BACKGROUND_THREAD_INDEFINITE_SLEEP);
|
||||||
/* We need malloc clock (can be different from tv). */
|
/* We need malloc clock (can be different from tv). */
|
||||||
nstime_t next_wakeup;
|
nstime_t next_wakeup;
|
||||||
nstime_init_update(&next_wakeup);
|
nstime_init_update(&next_wakeup);
|
||||||
nstime_iadd(&next_wakeup, interval);
|
nstime_iadd(&next_wakeup, interval);
|
||||||
assert(nstime_ns(&next_wakeup) <
|
assert(nstime_ns(&next_wakeup)
|
||||||
BACKGROUND_THREAD_INDEFINITE_SLEEP);
|
< BACKGROUND_THREAD_INDEFINITE_SLEEP);
|
||||||
background_thread_wakeup_time_set(tsdn, info,
|
background_thread_wakeup_time_set(
|
||||||
nstime_ns(&next_wakeup));
|
tsdn, info, nstime_ns(&next_wakeup));
|
||||||
|
|
||||||
nstime_t ts_wakeup;
|
nstime_t ts_wakeup;
|
||||||
nstime_copy(&ts_wakeup, &before_sleep);
|
nstime_copy(&ts_wakeup, &before_sleep);
|
||||||
@@ -245,8 +250,8 @@ background_thread_pause_check(tsdn_t *tsdn, background_thread_info_t *info) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
background_work_sleep_once(tsdn_t *tsdn, background_thread_info_t *info,
|
background_work_sleep_once(
|
||||||
unsigned ind) {
|
tsdn_t *tsdn, background_thread_info_t *info, unsigned ind) {
|
||||||
uint64_t ns_until_deferred = BACKGROUND_THREAD_DEFERRED_MAX;
|
uint64_t ns_until_deferred = BACKGROUND_THREAD_DEFERRED_MAX;
|
||||||
unsigned narenas = narenas_total_get();
|
unsigned narenas = narenas_total_get();
|
||||||
bool slept_indefinitely = background_thread_indefinite_sleep(info);
|
bool slept_indefinitely = background_thread_indefinite_sleep(info);
|
||||||
@@ -279,11 +284,10 @@ background_work_sleep_once(tsdn_t *tsdn, background_thread_info_t *info,
|
|||||||
if (ns_until_deferred == BACKGROUND_THREAD_DEFERRED_MAX) {
|
if (ns_until_deferred == BACKGROUND_THREAD_DEFERRED_MAX) {
|
||||||
sleep_ns = BACKGROUND_THREAD_INDEFINITE_SLEEP;
|
sleep_ns = BACKGROUND_THREAD_INDEFINITE_SLEEP;
|
||||||
} else {
|
} else {
|
||||||
sleep_ns =
|
sleep_ns = (ns_until_deferred
|
||||||
(ns_until_deferred < BACKGROUND_THREAD_MIN_INTERVAL_NS)
|
< BACKGROUND_THREAD_MIN_INTERVAL_NS)
|
||||||
? BACKGROUND_THREAD_MIN_INTERVAL_NS
|
? BACKGROUND_THREAD_MIN_INTERVAL_NS
|
||||||
: ns_until_deferred;
|
: ns_until_deferred;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
background_thread_sleep(tsdn, info, sleep_ns);
|
background_thread_sleep(tsdn, info, sleep_ns);
|
||||||
@@ -292,11 +296,11 @@ background_work_sleep_once(tsdn_t *tsdn, background_thread_info_t *info,
|
|||||||
static bool
|
static bool
|
||||||
background_threads_disable_single(tsd_t *tsd, background_thread_info_t *info) {
|
background_threads_disable_single(tsd_t *tsd, background_thread_info_t *info) {
|
||||||
if (info == &background_thread_info[0]) {
|
if (info == &background_thread_info[0]) {
|
||||||
malloc_mutex_assert_owner(tsd_tsdn(tsd),
|
malloc_mutex_assert_owner(
|
||||||
&background_thread_lock);
|
tsd_tsdn(tsd), &background_thread_lock);
|
||||||
} else {
|
} else {
|
||||||
malloc_mutex_assert_not_owner(tsd_tsdn(tsd),
|
malloc_mutex_assert_not_owner(
|
||||||
&background_thread_lock);
|
tsd_tsdn(tsd), &background_thread_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
pre_reentrancy(tsd, NULL);
|
pre_reentrancy(tsd, NULL);
|
||||||
@@ -344,17 +348,19 @@ background_thread_create_signals_masked(pthread_t *thread,
|
|||||||
if (mask_err != 0) {
|
if (mask_err != 0) {
|
||||||
return mask_err;
|
return mask_err;
|
||||||
}
|
}
|
||||||
int create_err = pthread_create_wrapper(thread, attr, start_routine,
|
int create_err = pthread_create_wrapper(
|
||||||
arg);
|
thread, attr, start_routine, arg);
|
||||||
/*
|
/*
|
||||||
* Restore the signal mask. Failure to restore the signal mask here
|
* Restore the signal mask. Failure to restore the signal mask here
|
||||||
* changes program behavior.
|
* changes program behavior.
|
||||||
*/
|
*/
|
||||||
int restore_err = pthread_sigmask(SIG_SETMASK, &oldset, NULL);
|
int restore_err = pthread_sigmask(SIG_SETMASK, &oldset, NULL);
|
||||||
if (restore_err != 0) {
|
if (restore_err != 0) {
|
||||||
malloc_printf("<jemalloc>: background thread creation "
|
malloc_printf(
|
||||||
|
"<jemalloc>: background thread creation "
|
||||||
"failed (%d), and signal mask restoration failed "
|
"failed (%d), and signal mask restoration failed "
|
||||||
"(%d)\n", create_err, restore_err);
|
"(%d)\n",
|
||||||
|
create_err, restore_err);
|
||||||
if (opt_abort) {
|
if (opt_abort) {
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
@@ -364,8 +370,8 @@ background_thread_create_signals_masked(pthread_t *thread,
|
|||||||
|
|
||||||
static bool
|
static bool
|
||||||
check_background_thread_creation(tsd_t *tsd,
|
check_background_thread_creation(tsd_t *tsd,
|
||||||
const size_t const_max_background_threads,
|
const size_t const_max_background_threads, unsigned *n_created,
|
||||||
unsigned *n_created, bool *created_threads) {
|
bool *created_threads) {
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
if (likely(*n_created == n_background_threads)) {
|
if (likely(*n_created == n_background_threads)) {
|
||||||
return ret;
|
return ret;
|
||||||
@@ -399,8 +405,10 @@ check_background_thread_creation(tsd_t *tsd,
|
|||||||
(*n_created)++;
|
(*n_created)++;
|
||||||
created_threads[i] = true;
|
created_threads[i] = true;
|
||||||
} else {
|
} else {
|
||||||
malloc_printf("<jemalloc>: background thread "
|
malloc_printf(
|
||||||
"creation failed (%d)\n", err);
|
"<jemalloc>: background thread "
|
||||||
|
"creation failed (%d)\n",
|
||||||
|
err);
|
||||||
if (opt_abort) {
|
if (opt_abort) {
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
@@ -434,16 +442,17 @@ background_thread0_work(tsd_t *tsd) {
|
|||||||
/* Start working, and create more threads when asked. */
|
/* Start working, and create more threads when asked. */
|
||||||
unsigned n_created = 1;
|
unsigned n_created = 1;
|
||||||
while (background_thread_info[0].state != background_thread_stopped) {
|
while (background_thread_info[0].state != background_thread_stopped) {
|
||||||
if (background_thread_pause_check(tsd_tsdn(tsd),
|
if (background_thread_pause_check(
|
||||||
&background_thread_info[0])) {
|
tsd_tsdn(tsd), &background_thread_info[0])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (check_background_thread_creation(tsd, const_max_background_threads,
|
if (check_background_thread_creation(tsd,
|
||||||
&n_created, (bool *)&created_threads)) {
|
const_max_background_threads, &n_created,
|
||||||
|
(bool *)&created_threads)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
background_work_sleep_once(tsd_tsdn(tsd),
|
background_work_sleep_once(
|
||||||
&background_thread_info[0], 0);
|
tsd_tsdn(tsd), &background_thread_info[0], 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -460,8 +469,8 @@ background_thread0_work(tsd_t *tsd) {
|
|||||||
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
|
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
|
||||||
if (info->state != background_thread_stopped) {
|
if (info->state != background_thread_stopped) {
|
||||||
/* The thread was not created. */
|
/* The thread was not created. */
|
||||||
assert(info->state ==
|
assert(
|
||||||
background_thread_started);
|
info->state == background_thread_started);
|
||||||
n_background_threads--;
|
n_background_threads--;
|
||||||
info->state = background_thread_stopped;
|
info->state = background_thread_stopped;
|
||||||
}
|
}
|
||||||
@@ -477,14 +486,14 @@ background_work(tsd_t *tsd, unsigned ind) {
|
|||||||
background_thread_info_t *info = &background_thread_info[ind];
|
background_thread_info_t *info = &background_thread_info[ind];
|
||||||
|
|
||||||
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
|
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
|
||||||
background_thread_wakeup_time_set(tsd_tsdn(tsd), info,
|
background_thread_wakeup_time_set(
|
||||||
BACKGROUND_THREAD_INDEFINITE_SLEEP);
|
tsd_tsdn(tsd), info, BACKGROUND_THREAD_INDEFINITE_SLEEP);
|
||||||
if (ind == 0) {
|
if (ind == 0) {
|
||||||
background_thread0_work(tsd);
|
background_thread0_work(tsd);
|
||||||
} else {
|
} else {
|
||||||
while (info->state != background_thread_stopped) {
|
while (info->state != background_thread_stopped) {
|
||||||
if (background_thread_pause_check(tsd_tsdn(tsd),
|
if (background_thread_pause_check(
|
||||||
info)) {
|
tsd_tsdn(tsd), info)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
background_work_sleep_once(tsd_tsdn(tsd), info, ind);
|
background_work_sleep_once(tsd_tsdn(tsd), info, ind);
|
||||||
@@ -513,8 +522,8 @@ background_thread_entry(void *ind_arg) {
|
|||||||
* turn triggers another background thread creation).
|
* turn triggers another background thread creation).
|
||||||
*/
|
*/
|
||||||
background_work(tsd_internal_fetch(), thread_ind);
|
background_work(tsd_internal_fetch(), thread_ind);
|
||||||
assert(pthread_equal(pthread_self(),
|
assert(pthread_equal(
|
||||||
background_thread_info[thread_ind].thread));
|
pthread_self(), background_thread_info[thread_ind].thread));
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -538,8 +547,8 @@ background_thread_create_locked(tsd_t *tsd, unsigned arena_ind) {
|
|||||||
|
|
||||||
bool need_new_thread;
|
bool need_new_thread;
|
||||||
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
|
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
|
||||||
need_new_thread = background_thread_enabled() &&
|
need_new_thread = background_thread_enabled()
|
||||||
(info->state == background_thread_stopped);
|
&& (info->state == background_thread_stopped);
|
||||||
if (need_new_thread) {
|
if (need_new_thread) {
|
||||||
background_thread_init(tsd, info);
|
background_thread_init(tsd, info);
|
||||||
}
|
}
|
||||||
@@ -569,8 +578,10 @@ background_thread_create_locked(tsd_t *tsd, unsigned arena_ind) {
|
|||||||
post_reentrancy(tsd);
|
post_reentrancy(tsd);
|
||||||
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
malloc_printf("<jemalloc>: arena 0 background thread creation "
|
malloc_printf(
|
||||||
"failed (%d)\n", err);
|
"<jemalloc>: arena 0 background thread creation "
|
||||||
|
"failed (%d)\n",
|
||||||
|
err);
|
||||||
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
|
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
|
||||||
info->state = background_thread_stopped;
|
info->state = background_thread_stopped;
|
||||||
n_background_threads--;
|
n_background_threads--;
|
||||||
@@ -612,12 +623,12 @@ background_threads_enable(tsd_t *tsd) {
|
|||||||
/* Mark the threads we need to create for thread 0. */
|
/* Mark the threads we need to create for thread 0. */
|
||||||
unsigned narenas = narenas_total_get();
|
unsigned narenas = narenas_total_get();
|
||||||
for (unsigned i = 1; i < narenas; i++) {
|
for (unsigned i = 1; i < narenas; i++) {
|
||||||
if (marked[i % max_background_threads] ||
|
if (marked[i % max_background_threads]
|
||||||
arena_get(tsd_tsdn(tsd), i, false) == NULL) {
|
|| arena_get(tsd_tsdn(tsd), i, false) == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
background_thread_info_t *info = &background_thread_info[
|
background_thread_info_t *info =
|
||||||
i % max_background_threads];
|
&background_thread_info[i % max_background_threads];
|
||||||
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
|
malloc_mutex_lock(tsd_tsdn(tsd), &info->mtx);
|
||||||
assert(info->state == background_thread_stopped);
|
assert(info->state == background_thread_stopped);
|
||||||
background_thread_init(tsd, info);
|
background_thread_init(tsd, info);
|
||||||
@@ -635,8 +646,8 @@ background_threads_enable(tsd_t *tsd) {
|
|||||||
for (unsigned i = 0; i < narenas; i++) {
|
for (unsigned i = 0; i < narenas; i++) {
|
||||||
arena_t *arena = arena_get(tsd_tsdn(tsd), i, false);
|
arena_t *arena = arena_get(tsd_tsdn(tsd), i, false);
|
||||||
if (arena != NULL) {
|
if (arena != NULL) {
|
||||||
pa_shard_set_deferral_allowed(tsd_tsdn(tsd),
|
pa_shard_set_deferral_allowed(
|
||||||
&arena->pa_shard, true);
|
tsd_tsdn(tsd), &arena->pa_shard, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -648,8 +659,8 @@ background_threads_disable(tsd_t *tsd) {
|
|||||||
malloc_mutex_assert_owner(tsd_tsdn(tsd), &background_thread_lock);
|
malloc_mutex_assert_owner(tsd_tsdn(tsd), &background_thread_lock);
|
||||||
|
|
||||||
/* Thread 0 will be responsible for terminating other threads. */
|
/* Thread 0 will be responsible for terminating other threads. */
|
||||||
if (background_threads_disable_single(tsd,
|
if (background_threads_disable_single(
|
||||||
&background_thread_info[0])) {
|
tsd, &background_thread_info[0])) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
assert(n_background_threads == 0);
|
assert(n_background_threads == 0);
|
||||||
@@ -657,8 +668,8 @@ background_threads_disable(tsd_t *tsd) {
|
|||||||
for (unsigned i = 0; i < narenas; i++) {
|
for (unsigned i = 0; i < narenas; i++) {
|
||||||
arena_t *arena = arena_get(tsd_tsdn(tsd), i, false);
|
arena_t *arena = arena_get(tsd_tsdn(tsd), i, false);
|
||||||
if (arena != NULL) {
|
if (arena != NULL) {
|
||||||
pa_shard_set_deferral_allowed(tsd_tsdn(tsd),
|
pa_shard_set_deferral_allowed(
|
||||||
&arena->pa_shard, false);
|
tsd_tsdn(tsd), &arena->pa_shard, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -671,15 +682,15 @@ background_thread_is_started(background_thread_info_t *info) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
background_thread_wakeup_early(background_thread_info_t *info,
|
background_thread_wakeup_early(
|
||||||
nstime_t *remaining_sleep) {
|
background_thread_info_t *info, nstime_t *remaining_sleep) {
|
||||||
/*
|
/*
|
||||||
* This is an optimization to increase batching. At this point
|
* This is an optimization to increase batching. At this point
|
||||||
* we know that background thread wakes up soon, so the time to cache
|
* we know that background thread wakes up soon, so the time to cache
|
||||||
* the just freed memory is bounded and low.
|
* the just freed memory is bounded and low.
|
||||||
*/
|
*/
|
||||||
if (remaining_sleep != NULL && nstime_ns(remaining_sleep) <
|
if (remaining_sleep != NULL
|
||||||
BACKGROUND_THREAD_MIN_INTERVAL_NS) {
|
&& nstime_ns(remaining_sleep) < BACKGROUND_THREAD_MIN_INTERVAL_NS) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pthread_cond_signal(&info->cond);
|
pthread_cond_signal(&info->cond);
|
||||||
@@ -701,8 +712,8 @@ background_thread_prefork1(tsdn_t *tsdn) {
|
|||||||
void
|
void
|
||||||
background_thread_postfork_parent(tsdn_t *tsdn) {
|
background_thread_postfork_parent(tsdn_t *tsdn) {
|
||||||
for (unsigned i = 0; i < max_background_threads; i++) {
|
for (unsigned i = 0; i < max_background_threads; i++) {
|
||||||
malloc_mutex_postfork_parent(tsdn,
|
malloc_mutex_postfork_parent(
|
||||||
&background_thread_info[i].mtx);
|
tsdn, &background_thread_info[i].mtx);
|
||||||
}
|
}
|
||||||
malloc_mutex_postfork_parent(tsdn, &background_thread_lock);
|
malloc_mutex_postfork_parent(tsdn, &background_thread_lock);
|
||||||
}
|
}
|
||||||
@@ -710,8 +721,8 @@ background_thread_postfork_parent(tsdn_t *tsdn) {
|
|||||||
void
|
void
|
||||||
background_thread_postfork_child(tsdn_t *tsdn) {
|
background_thread_postfork_child(tsdn_t *tsdn) {
|
||||||
for (unsigned i = 0; i < max_background_threads; i++) {
|
for (unsigned i = 0; i < max_background_threads; i++) {
|
||||||
malloc_mutex_postfork_child(tsdn,
|
malloc_mutex_postfork_child(
|
||||||
&background_thread_info[i].mtx);
|
tsdn, &background_thread_info[i].mtx);
|
||||||
}
|
}
|
||||||
malloc_mutex_postfork_child(tsdn, &background_thread_lock);
|
malloc_mutex_postfork_child(tsdn, &background_thread_lock);
|
||||||
if (!background_thread_enabled_at_fork) {
|
if (!background_thread_enabled_at_fork) {
|
||||||
@@ -760,8 +771,8 @@ background_thread_stats_read(tsdn_t *tsdn, background_thread_stats_t *stats) {
|
|||||||
if (info->state != background_thread_stopped) {
|
if (info->state != background_thread_stopped) {
|
||||||
num_runs += info->tot_n_runs;
|
num_runs += info->tot_n_runs;
|
||||||
nstime_add(&stats->run_interval, &info->tot_sleep_time);
|
nstime_add(&stats->run_interval, &info->tot_sleep_time);
|
||||||
malloc_mutex_prof_max_update(tsdn,
|
malloc_mutex_prof_max_update(
|
||||||
&stats->max_counter_per_bg_thd, &info->mtx);
|
tsdn, &stats->max_counter_per_bg_thd, &info->mtx);
|
||||||
}
|
}
|
||||||
malloc_mutex_unlock(tsdn, &info->mtx);
|
malloc_mutex_unlock(tsdn, &info->mtx);
|
||||||
}
|
}
|
||||||
@@ -795,16 +806,16 @@ background_thread_ctl_init(tsdn_t *tsdn) {
|
|||||||
|
|
||||||
#endif /* defined(JEMALLOC_BACKGROUND_THREAD) */
|
#endif /* defined(JEMALLOC_BACKGROUND_THREAD) */
|
||||||
|
|
||||||
bool
|
bool background_thread_boot0(void) {
|
||||||
background_thread_boot0(void) {
|
|
||||||
if (!have_background_thread && opt_background_thread) {
|
if (!have_background_thread && opt_background_thread) {
|
||||||
malloc_printf("<jemalloc>: option background_thread currently "
|
malloc_printf(
|
||||||
|
"<jemalloc>: option background_thread currently "
|
||||||
"supports pthread only\n");
|
"supports pthread only\n");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER
|
#ifdef JEMALLOC_PTHREAD_CREATE_WRAPPER
|
||||||
if ((config_lazy_lock || opt_background_thread) &&
|
if ((config_lazy_lock || opt_background_thread)
|
||||||
pthread_create_fptr_init()) {
|
&& pthread_create_fptr_init()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -830,8 +841,8 @@ background_thread_boot1(tsdn_t *tsdn, base_t *base) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
background_thread_info = (background_thread_info_t *)base_alloc(tsdn,
|
background_thread_info = (background_thread_info_t *)base_alloc(tsdn,
|
||||||
base, opt_max_background_threads *
|
base, opt_max_background_threads * sizeof(background_thread_info_t),
|
||||||
sizeof(background_thread_info_t), CACHELINE);
|
CACHELINE);
|
||||||
if (background_thread_info == NULL) {
|
if (background_thread_info == NULL) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
171
src/base.c
171
src/base.c
@@ -22,18 +22,14 @@ static base_t *b0;
|
|||||||
|
|
||||||
metadata_thp_mode_t opt_metadata_thp = METADATA_THP_DEFAULT;
|
metadata_thp_mode_t opt_metadata_thp = METADATA_THP_DEFAULT;
|
||||||
|
|
||||||
const char *const metadata_thp_mode_names[] = {
|
const char *const metadata_thp_mode_names[] = {"disabled", "auto", "always"};
|
||||||
"disabled",
|
|
||||||
"auto",
|
|
||||||
"always"
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
metadata_thp_madvise(void) {
|
metadata_thp_madvise(void) {
|
||||||
return (metadata_thp_enabled() &&
|
return (metadata_thp_enabled()
|
||||||
(init_system_thp_mode == thp_mode_default));
|
&& (init_system_thp_mode == thp_mode_default));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
@@ -56,16 +52,16 @@ base_map(tsdn_t *tsdn, ehooks_t *ehooks, unsigned ind, size_t size) {
|
|||||||
if (ehooks_are_default(ehooks)) {
|
if (ehooks_are_default(ehooks)) {
|
||||||
addr = extent_alloc_mmap(NULL, size, alignment, &zero, &commit);
|
addr = extent_alloc_mmap(NULL, size, alignment, &zero, &commit);
|
||||||
} else {
|
} else {
|
||||||
addr = ehooks_alloc(tsdn, ehooks, NULL, size, alignment, &zero,
|
addr = ehooks_alloc(
|
||||||
&commit);
|
tsdn, ehooks, NULL, size, alignment, &zero, &commit);
|
||||||
}
|
}
|
||||||
|
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
base_unmap(tsdn_t *tsdn, ehooks_t *ehooks, unsigned ind, void *addr,
|
base_unmap(
|
||||||
size_t size) {
|
tsdn_t *tsdn, ehooks_t *ehooks, unsigned ind, void *addr, size_t size) {
|
||||||
/*
|
/*
|
||||||
* Cascade through dalloc, decommit, purge_forced, and purge_lazy,
|
* Cascade through dalloc, decommit, purge_forced, and purge_lazy,
|
||||||
* stopping at first success. This cascade is performed for consistency
|
* stopping at first success. This cascade is performed for consistency
|
||||||
@@ -109,8 +105,8 @@ base_unmap(tsdn_t *tsdn, ehooks_t *ehooks, unsigned ind, void *addr,
|
|||||||
label_done:
|
label_done:
|
||||||
if (metadata_thp_madvise()) {
|
if (metadata_thp_madvise()) {
|
||||||
/* Set NOHUGEPAGE after unmap to avoid kernel defrag. */
|
/* Set NOHUGEPAGE after unmap to avoid kernel defrag. */
|
||||||
assert(((uintptr_t)addr & HUGEPAGE_MASK) == 0 &&
|
assert(((uintptr_t)addr & HUGEPAGE_MASK) == 0
|
||||||
(size & HUGEPAGE_MASK) == 0);
|
&& (size & HUGEPAGE_MASK) == 0);
|
||||||
pages_nohuge(addr, size);
|
pages_nohuge(addr, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -126,8 +122,8 @@ base_edata_is_reused(edata_t *edata) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
base_edata_init(size_t *extent_sn_next, edata_t *edata, void *addr,
|
base_edata_init(
|
||||||
size_t size) {
|
size_t *extent_sn_next, edata_t *edata, void *addr, size_t size) {
|
||||||
size_t sn;
|
size_t sn;
|
||||||
|
|
||||||
sn = *extent_sn_next;
|
sn = *extent_sn_next;
|
||||||
@@ -196,11 +192,11 @@ base_auto_thp_switch(tsdn_t *tsdn, base_t *base) {
|
|||||||
/* Called when adding a new block. */
|
/* Called when adding a new block. */
|
||||||
bool should_switch;
|
bool should_switch;
|
||||||
if (base_ind_get(base) != 0) {
|
if (base_ind_get(base) != 0) {
|
||||||
should_switch = (base_get_num_blocks(base, true) ==
|
should_switch = (base_get_num_blocks(base, true)
|
||||||
BASE_AUTO_THP_THRESHOLD);
|
== BASE_AUTO_THP_THRESHOLD);
|
||||||
} else {
|
} else {
|
||||||
should_switch = (base_get_num_blocks(base, true) ==
|
should_switch = (base_get_num_blocks(base, true)
|
||||||
BASE_AUTO_THP_THRESHOLD_A0);
|
== BASE_AUTO_THP_THRESHOLD_A0);
|
||||||
}
|
}
|
||||||
if (!should_switch) {
|
if (!should_switch) {
|
||||||
return;
|
return;
|
||||||
@@ -214,8 +210,9 @@ base_auto_thp_switch(tsdn_t *tsdn, base_t *base) {
|
|||||||
assert((block->size & HUGEPAGE_MASK) == 0);
|
assert((block->size & HUGEPAGE_MASK) == 0);
|
||||||
pages_huge(block, block->size);
|
pages_huge(block, block->size);
|
||||||
if (config_stats) {
|
if (config_stats) {
|
||||||
base->n_thp += HUGEPAGE_CEILING(block->size -
|
base->n_thp += HUGEPAGE_CEILING(block->size
|
||||||
edata_bsize_get(&block->edata)) >> LG_HUGEPAGE;
|
- edata_bsize_get(&block->edata))
|
||||||
|
>> LG_HUGEPAGE;
|
||||||
}
|
}
|
||||||
block = block->next;
|
block = block->next;
|
||||||
assert(block == NULL || (base_ind_get(base) == 0));
|
assert(block == NULL || (base_ind_get(base) == 0));
|
||||||
@@ -242,20 +239,22 @@ base_auto_thp_switch(tsdn_t *tsdn, base_t *base) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
base_extent_bump_alloc_helper(edata_t *edata, size_t *gap_size, size_t size,
|
base_extent_bump_alloc_helper(
|
||||||
size_t alignment) {
|
edata_t *edata, size_t *gap_size, size_t size, size_t alignment) {
|
||||||
void *ret;
|
void *ret;
|
||||||
|
|
||||||
assert(alignment == ALIGNMENT_CEILING(alignment, QUANTUM));
|
assert(alignment == ALIGNMENT_CEILING(alignment, QUANTUM));
|
||||||
assert(size == ALIGNMENT_CEILING(size, alignment));
|
assert(size == ALIGNMENT_CEILING(size, alignment));
|
||||||
|
|
||||||
*gap_size = ALIGNMENT_CEILING((uintptr_t)edata_addr_get(edata),
|
*gap_size = ALIGNMENT_CEILING(
|
||||||
alignment) - (uintptr_t)edata_addr_get(edata);
|
(uintptr_t)edata_addr_get(edata), alignment)
|
||||||
|
- (uintptr_t)edata_addr_get(edata);
|
||||||
ret = (void *)((byte_t *)edata_addr_get(edata) + *gap_size);
|
ret = (void *)((byte_t *)edata_addr_get(edata) + *gap_size);
|
||||||
assert(edata_bsize_get(edata) >= *gap_size + size);
|
assert(edata_bsize_get(edata) >= *gap_size + size);
|
||||||
edata_binit(edata, (void *)((byte_t *)edata_addr_get(edata) +
|
edata_binit(edata,
|
||||||
*gap_size + size), edata_bsize_get(edata) - *gap_size - size,
|
(void *)((byte_t *)edata_addr_get(edata) + *gap_size + size),
|
||||||
edata_sn_get(edata), base_edata_is_reused(edata));
|
edata_bsize_get(edata) - *gap_size - size, edata_sn_get(edata),
|
||||||
|
base_edata_is_reused(edata));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,23 +311,25 @@ base_extent_bump_alloc_post(tsdn_t *tsdn, base_t *base, edata_t *edata,
|
|||||||
* crossed by the new allocation. Adjust n_thp similarly when
|
* crossed by the new allocation. Adjust n_thp similarly when
|
||||||
* metadata_thp is enabled.
|
* metadata_thp is enabled.
|
||||||
*/
|
*/
|
||||||
base->resident += PAGE_CEILING((uintptr_t)addr + size) -
|
base->resident += PAGE_CEILING((uintptr_t)addr + size)
|
||||||
PAGE_CEILING((uintptr_t)addr - gap_size);
|
- PAGE_CEILING((uintptr_t)addr - gap_size);
|
||||||
assert(base->allocated <= base->resident);
|
assert(base->allocated <= base->resident);
|
||||||
assert(base->resident <= base->mapped);
|
assert(base->resident <= base->mapped);
|
||||||
if (metadata_thp_madvise() && (opt_metadata_thp ==
|
if (metadata_thp_madvise()
|
||||||
metadata_thp_always || base->auto_thp_switched)) {
|
&& (opt_metadata_thp == metadata_thp_always
|
||||||
|
|| base->auto_thp_switched)) {
|
||||||
base->n_thp += (HUGEPAGE_CEILING((uintptr_t)addr + size)
|
base->n_thp += (HUGEPAGE_CEILING((uintptr_t)addr + size)
|
||||||
- HUGEPAGE_CEILING((uintptr_t)addr - gap_size)) >>
|
- HUGEPAGE_CEILING(
|
||||||
LG_HUGEPAGE;
|
(uintptr_t)addr - gap_size))
|
||||||
|
>> LG_HUGEPAGE;
|
||||||
assert(base->mapped >= base->n_thp << LG_HUGEPAGE);
|
assert(base->mapped >= base->n_thp << LG_HUGEPAGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
base_extent_bump_alloc(tsdn_t *tsdn, base_t *base, edata_t *edata, size_t size,
|
base_extent_bump_alloc(
|
||||||
size_t alignment) {
|
tsdn_t *tsdn, base_t *base, edata_t *edata, size_t size, size_t alignment) {
|
||||||
void *ret;
|
void *ret;
|
||||||
size_t gap_size;
|
size_t gap_size;
|
||||||
|
|
||||||
@@ -339,9 +340,9 @@ base_extent_bump_alloc(tsdn_t *tsdn, base_t *base, edata_t *edata, size_t size,
|
|||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
base_block_size_ceil(size_t block_size) {
|
base_block_size_ceil(size_t block_size) {
|
||||||
return opt_metadata_thp == metadata_thp_disabled ?
|
return opt_metadata_thp == metadata_thp_disabled
|
||||||
ALIGNMENT_CEILING(block_size, BASE_BLOCK_MIN_ALIGN) :
|
? ALIGNMENT_CEILING(block_size, BASE_BLOCK_MIN_ALIGN)
|
||||||
HUGEPAGE_CEILING(block_size);
|
: HUGEPAGE_CEILING(block_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -356,8 +357,8 @@ base_block_alloc(tsdn_t *tsdn, base_t *base, ehooks_t *ehooks, unsigned ind,
|
|||||||
alignment = ALIGNMENT_CEILING(alignment, QUANTUM);
|
alignment = ALIGNMENT_CEILING(alignment, QUANTUM);
|
||||||
size_t usize = ALIGNMENT_CEILING(size, alignment);
|
size_t usize = ALIGNMENT_CEILING(size, alignment);
|
||||||
size_t header_size = sizeof(base_block_t);
|
size_t header_size = sizeof(base_block_t);
|
||||||
size_t gap_size = ALIGNMENT_CEILING(header_size, alignment) -
|
size_t gap_size = ALIGNMENT_CEILING(header_size, alignment)
|
||||||
header_size;
|
- header_size;
|
||||||
/*
|
/*
|
||||||
* Create increasingly larger blocks in order to limit the total number
|
* Create increasingly larger blocks in order to limit the total number
|
||||||
* of disjoint virtual memory ranges. Choose the next size in the page
|
* of disjoint virtual memory ranges. Choose the next size in the page
|
||||||
@@ -365,27 +366,29 @@ base_block_alloc(tsdn_t *tsdn, base_t *base, ehooks_t *ehooks, unsigned ind,
|
|||||||
* HUGEPAGE when using metadata_thp), or a size large enough to satisfy
|
* HUGEPAGE when using metadata_thp), or a size large enough to satisfy
|
||||||
* the requested size and alignment, whichever is larger.
|
* the requested size and alignment, whichever is larger.
|
||||||
*/
|
*/
|
||||||
size_t min_block_size = base_block_size_ceil(sz_psz2u(header_size +
|
size_t min_block_size = base_block_size_ceil(
|
||||||
gap_size + usize));
|
sz_psz2u(header_size + gap_size + usize));
|
||||||
pszind_t pind_next = (*pind_last + 1 < sz_psz2ind(SC_LARGE_MAXCLASS)) ?
|
pszind_t pind_next = (*pind_last + 1 < sz_psz2ind(SC_LARGE_MAXCLASS))
|
||||||
*pind_last + 1 : *pind_last;
|
? *pind_last + 1
|
||||||
|
: *pind_last;
|
||||||
size_t next_block_size = base_block_size_ceil(sz_pind2sz(pind_next));
|
size_t next_block_size = base_block_size_ceil(sz_pind2sz(pind_next));
|
||||||
size_t block_size = (min_block_size > next_block_size) ? min_block_size
|
size_t block_size = (min_block_size > next_block_size)
|
||||||
|
? min_block_size
|
||||||
: next_block_size;
|
: next_block_size;
|
||||||
base_block_t *block = (base_block_t *)base_map(tsdn, ehooks, ind,
|
base_block_t *block = (base_block_t *)base_map(
|
||||||
block_size);
|
tsdn, ehooks, ind, block_size);
|
||||||
if (block == NULL) {
|
if (block == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metadata_thp_madvise()) {
|
if (metadata_thp_madvise()) {
|
||||||
void *addr = (void *)block;
|
void *addr = (void *)block;
|
||||||
assert(((uintptr_t)addr & HUGEPAGE_MASK) == 0 &&
|
assert(((uintptr_t)addr & HUGEPAGE_MASK) == 0
|
||||||
(block_size & HUGEPAGE_MASK) == 0);
|
&& (block_size & HUGEPAGE_MASK) == 0);
|
||||||
if (opt_metadata_thp == metadata_thp_always) {
|
if (opt_metadata_thp == metadata_thp_always) {
|
||||||
pages_huge(addr, block_size);
|
pages_huge(addr, block_size);
|
||||||
} else if (opt_metadata_thp == metadata_thp_auto &&
|
} else if (opt_metadata_thp == metadata_thp_auto
|
||||||
base != NULL) {
|
&& base != NULL) {
|
||||||
/* base != NULL indicates this is not a new base. */
|
/* base != NULL indicates this is not a new base. */
|
||||||
malloc_mutex_lock(tsdn, &base->mtx);
|
malloc_mutex_lock(tsdn, &base->mtx);
|
||||||
base_auto_thp_switch(tsdn, base);
|
base_auto_thp_switch(tsdn, base);
|
||||||
@@ -432,12 +435,12 @@ base_extent_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) {
|
|||||||
base->allocated += sizeof(base_block_t);
|
base->allocated += sizeof(base_block_t);
|
||||||
base->resident += PAGE_CEILING(sizeof(base_block_t));
|
base->resident += PAGE_CEILING(sizeof(base_block_t));
|
||||||
base->mapped += block->size;
|
base->mapped += block->size;
|
||||||
if (metadata_thp_madvise() &&
|
if (metadata_thp_madvise()
|
||||||
!(opt_metadata_thp == metadata_thp_auto
|
&& !(opt_metadata_thp == metadata_thp_auto
|
||||||
&& !base->auto_thp_switched)) {
|
&& !base->auto_thp_switched)) {
|
||||||
assert(base->n_thp > 0);
|
assert(base->n_thp > 0);
|
||||||
base->n_thp += HUGEPAGE_CEILING(sizeof(base_block_t)) >>
|
base->n_thp += HUGEPAGE_CEILING(sizeof(base_block_t))
|
||||||
LG_HUGEPAGE;
|
>> LG_HUGEPAGE;
|
||||||
}
|
}
|
||||||
assert(base->allocated <= base->resident);
|
assert(base->allocated <= base->resident);
|
||||||
assert(base->resident <= base->mapped);
|
assert(base->resident <= base->mapped);
|
||||||
@@ -463,9 +466,10 @@ base_new(tsdn_t *tsdn, unsigned ind, const extent_hooks_t *extent_hooks,
|
|||||||
* memory, and then initialize the ehooks within the base_t.
|
* memory, and then initialize the ehooks within the base_t.
|
||||||
*/
|
*/
|
||||||
ehooks_t fake_ehooks;
|
ehooks_t fake_ehooks;
|
||||||
ehooks_init(&fake_ehooks, metadata_use_hooks ?
|
ehooks_init(&fake_ehooks,
|
||||||
(extent_hooks_t *)extent_hooks :
|
metadata_use_hooks ? (extent_hooks_t *)extent_hooks
|
||||||
(extent_hooks_t *)&ehooks_default_extent_hooks, ind);
|
: (extent_hooks_t *)&ehooks_default_extent_hooks,
|
||||||
|
ind);
|
||||||
|
|
||||||
base_block_t *block = base_block_alloc(tsdn, NULL, &fake_ehooks, ind,
|
base_block_t *block = base_block_alloc(tsdn, NULL, &fake_ehooks, ind,
|
||||||
&pind_last, &extent_sn_next, sizeof(base_t), QUANTUM);
|
&pind_last, &extent_sn_next, sizeof(base_t), QUANTUM);
|
||||||
@@ -476,12 +480,13 @@ base_new(tsdn_t *tsdn, unsigned ind, const extent_hooks_t *extent_hooks,
|
|||||||
size_t gap_size;
|
size_t gap_size;
|
||||||
size_t base_alignment = CACHELINE;
|
size_t base_alignment = CACHELINE;
|
||||||
size_t base_size = ALIGNMENT_CEILING(sizeof(base_t), base_alignment);
|
size_t base_size = ALIGNMENT_CEILING(sizeof(base_t), base_alignment);
|
||||||
base_t *base = (base_t *)base_extent_bump_alloc_helper(&block->edata,
|
base_t *base = (base_t *)base_extent_bump_alloc_helper(
|
||||||
&gap_size, base_size, base_alignment);
|
&block->edata, &gap_size, base_size, base_alignment);
|
||||||
ehooks_init(&base->ehooks, (extent_hooks_t *)extent_hooks, ind);
|
ehooks_init(&base->ehooks, (extent_hooks_t *)extent_hooks, ind);
|
||||||
ehooks_init(&base->ehooks_base, metadata_use_hooks ?
|
ehooks_init(&base->ehooks_base,
|
||||||
(extent_hooks_t *)extent_hooks :
|
metadata_use_hooks ? (extent_hooks_t *)extent_hooks
|
||||||
(extent_hooks_t *)&ehooks_default_extent_hooks, ind);
|
: (extent_hooks_t *)&ehooks_default_extent_hooks,
|
||||||
|
ind);
|
||||||
if (malloc_mutex_init(&base->mtx, "base", WITNESS_RANK_BASE,
|
if (malloc_mutex_init(&base->mtx, "base", WITNESS_RANK_BASE,
|
||||||
malloc_mutex_rank_exclusive)) {
|
malloc_mutex_rank_exclusive)) {
|
||||||
base_unmap(tsdn, &fake_ehooks, ind, block, block->size);
|
base_unmap(tsdn, &fake_ehooks, ind, block, block->size);
|
||||||
@@ -502,9 +507,10 @@ base_new(tsdn_t *tsdn, unsigned ind, const extent_hooks_t *extent_hooks,
|
|||||||
base->allocated = sizeof(base_block_t);
|
base->allocated = sizeof(base_block_t);
|
||||||
base->resident = PAGE_CEILING(sizeof(base_block_t));
|
base->resident = PAGE_CEILING(sizeof(base_block_t));
|
||||||
base->mapped = block->size;
|
base->mapped = block->size;
|
||||||
base->n_thp = (opt_metadata_thp == metadata_thp_always) &&
|
base->n_thp = (opt_metadata_thp == metadata_thp_always)
|
||||||
metadata_thp_madvise() ? HUGEPAGE_CEILING(sizeof(base_block_t))
|
&& metadata_thp_madvise()
|
||||||
>> LG_HUGEPAGE : 0;
|
? HUGEPAGE_CEILING(sizeof(base_block_t)) >> LG_HUGEPAGE
|
||||||
|
: 0;
|
||||||
assert(base->allocated <= base->resident);
|
assert(base->allocated <= base->resident);
|
||||||
assert(base->resident <= base->mapped);
|
assert(base->resident <= base->mapped);
|
||||||
assert(base->n_thp << LG_HUGEPAGE <= base->mapped);
|
assert(base->n_thp << LG_HUGEPAGE <= base->mapped);
|
||||||
@@ -512,8 +518,8 @@ base_new(tsdn_t *tsdn, unsigned ind, const extent_hooks_t *extent_hooks,
|
|||||||
|
|
||||||
/* Locking here is only necessary because of assertions. */
|
/* Locking here is only necessary because of assertions. */
|
||||||
malloc_mutex_lock(tsdn, &base->mtx);
|
malloc_mutex_lock(tsdn, &base->mtx);
|
||||||
base_extent_bump_alloc_post(tsdn, base, &block->edata, gap_size, base,
|
base_extent_bump_alloc_post(
|
||||||
base_size);
|
tsdn, base, &block->edata, gap_size, base, base_size);
|
||||||
malloc_mutex_unlock(tsdn, &base->mtx);
|
malloc_mutex_unlock(tsdn, &base->mtx);
|
||||||
|
|
||||||
return base;
|
return base;
|
||||||
@@ -526,8 +532,8 @@ base_delete(tsdn_t *tsdn, base_t *base) {
|
|||||||
do {
|
do {
|
||||||
base_block_t *block = next;
|
base_block_t *block = next;
|
||||||
next = block->next;
|
next = block->next;
|
||||||
base_unmap(tsdn, ehooks, base_ind_get(base), block,
|
base_unmap(
|
||||||
block->size);
|
tsdn, ehooks, base_ind_get(base), block, block->size);
|
||||||
} while (next != NULL);
|
} while (next != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,8 +549,8 @@ base_ehooks_get_for_metadata(base_t *base) {
|
|||||||
|
|
||||||
extent_hooks_t *
|
extent_hooks_t *
|
||||||
base_extent_hooks_set(base_t *base, extent_hooks_t *extent_hooks) {
|
base_extent_hooks_set(base_t *base, extent_hooks_t *extent_hooks) {
|
||||||
extent_hooks_t *old_extent_hooks =
|
extent_hooks_t *old_extent_hooks = ehooks_get_extent_hooks_ptr(
|
||||||
ehooks_get_extent_hooks_ptr(&base->ehooks);
|
&base->ehooks);
|
||||||
ehooks_init(&base->ehooks, extent_hooks, ehooks_ind_get(&base->ehooks));
|
ehooks_init(&base->ehooks, extent_hooks, ehooks_ind_get(&base->ehooks));
|
||||||
return old_extent_hooks;
|
return old_extent_hooks;
|
||||||
}
|
}
|
||||||
@@ -603,8 +609,8 @@ base_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment) {
|
|||||||
edata_t *
|
edata_t *
|
||||||
base_alloc_edata(tsdn_t *tsdn, base_t *base) {
|
base_alloc_edata(tsdn_t *tsdn, base_t *base) {
|
||||||
size_t esn, usize;
|
size_t esn, usize;
|
||||||
edata_t *edata = base_alloc_impl(tsdn, base, sizeof(edata_t),
|
edata_t *edata = base_alloc_impl(
|
||||||
EDATA_ALIGNMENT, &esn, &usize);
|
tsdn, base, sizeof(edata_t), EDATA_ALIGNMENT, &esn, &usize);
|
||||||
if (edata == NULL) {
|
if (edata == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -618,8 +624,8 @@ base_alloc_edata(tsdn_t *tsdn, base_t *base) {
|
|||||||
void *
|
void *
|
||||||
base_alloc_rtree(tsdn_t *tsdn, base_t *base, size_t size) {
|
base_alloc_rtree(tsdn_t *tsdn, base_t *base, size_t size) {
|
||||||
size_t usize;
|
size_t usize;
|
||||||
void *rtree = base_alloc_impl(tsdn, base, size, CACHELINE, NULL,
|
void *rtree = base_alloc_impl(
|
||||||
&usize);
|
tsdn, base, size, CACHELINE, NULL, &usize);
|
||||||
if (rtree == NULL) {
|
if (rtree == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -632,8 +638,8 @@ base_alloc_rtree(tsdn_t *tsdn, base_t *base, size_t size) {
|
|||||||
static inline void
|
static inline void
|
||||||
b0_alloc_header_size(size_t *header_size, size_t *alignment) {
|
b0_alloc_header_size(size_t *header_size, size_t *alignment) {
|
||||||
*alignment = QUANTUM;
|
*alignment = QUANTUM;
|
||||||
*header_size = QUANTUM > sizeof(edata_t *) ? QUANTUM :
|
*header_size = QUANTUM > sizeof(edata_t *) ? QUANTUM
|
||||||
sizeof(edata_t *);
|
: sizeof(edata_t *);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -662,8 +668,8 @@ b0_alloc_tcache_stack(tsdn_t *tsdn, size_t stack_size) {
|
|||||||
b0_alloc_header_size(&header_size, &alignment);
|
b0_alloc_header_size(&header_size, &alignment);
|
||||||
|
|
||||||
size_t alloc_size = sz_s2u(stack_size + header_size);
|
size_t alloc_size = sz_s2u(stack_size + header_size);
|
||||||
void *addr = base_alloc_impl(tsdn, base, alloc_size, alignment, &esn,
|
void *addr = base_alloc_impl(
|
||||||
NULL);
|
tsdn, base, alloc_size, alignment, &esn, NULL);
|
||||||
if (addr == NULL) {
|
if (addr == NULL) {
|
||||||
edata_avail_insert(&base->edata_avail, edata);
|
edata_avail_insert(&base->edata_avail, edata);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -707,7 +713,8 @@ base_stats_get(tsdn_t *tsdn, base_t *base, size_t *allocated,
|
|||||||
malloc_mutex_lock(tsdn, &base->mtx);
|
malloc_mutex_lock(tsdn, &base->mtx);
|
||||||
assert(base->allocated <= base->resident);
|
assert(base->allocated <= base->resident);
|
||||||
assert(base->resident <= base->mapped);
|
assert(base->resident <= base->mapped);
|
||||||
assert(base->edata_allocated + base->rtree_allocated <= base->allocated);
|
assert(
|
||||||
|
base->edata_allocated + base->rtree_allocated <= base->allocated);
|
||||||
*allocated = base->allocated;
|
*allocated = base->allocated;
|
||||||
*edata_allocated = base->edata_allocated;
|
*edata_allocated = base->edata_allocated;
|
||||||
*rtree_allocated = base->rtree_allocated;
|
*rtree_allocated = base->rtree_allocated;
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ batcher_init(batcher_t *batcher, size_t nelems_max) {
|
|||||||
* Returns an index (into some user-owned array) to use for pushing, or
|
* Returns an index (into some user-owned array) to use for pushing, or
|
||||||
* BATCHER_NO_IDX if no index is free.
|
* BATCHER_NO_IDX if no index is free.
|
||||||
*/
|
*/
|
||||||
size_t batcher_push_begin(tsdn_t *tsdn, batcher_t *batcher,
|
size_t
|
||||||
size_t elems_to_push) {
|
batcher_push_begin(tsdn_t *tsdn, batcher_t *batcher, size_t elems_to_push) {
|
||||||
assert(elems_to_push > 0);
|
assert(elems_to_push > 0);
|
||||||
size_t nelems_guess = atomic_load_zu(&batcher->nelems, ATOMIC_RELAXED);
|
size_t nelems_guess = atomic_load_zu(&batcher->nelems, ATOMIC_RELAXED);
|
||||||
if (nelems_guess + elems_to_push > batcher->nelems_max) {
|
if (nelems_guess + elems_to_push > batcher->nelems_max) {
|
||||||
@@ -37,7 +37,8 @@ size_t batcher_push_begin(tsdn_t *tsdn, batcher_t *batcher,
|
|||||||
* racing accesses of the batcher can fail fast instead of trying to
|
* racing accesses of the batcher can fail fast instead of trying to
|
||||||
* acquire a mutex only to discover that there's no space for them.
|
* acquire a mutex only to discover that there's no space for them.
|
||||||
*/
|
*/
|
||||||
atomic_store_zu(&batcher->nelems, nelems + elems_to_push, ATOMIC_RELAXED);
|
atomic_store_zu(
|
||||||
|
&batcher->nelems, nelems + elems_to_push, ATOMIC_RELAXED);
|
||||||
batcher->npushes++;
|
batcher->npushes++;
|
||||||
return nelems;
|
return nelems;
|
||||||
}
|
}
|
||||||
@@ -75,7 +76,8 @@ batcher_pop_begin(tsdn_t *tsdn, batcher_t *batcher) {
|
|||||||
return nelems;
|
return nelems;
|
||||||
}
|
}
|
||||||
|
|
||||||
void batcher_pop_end(tsdn_t *tsdn, batcher_t *batcher) {
|
void
|
||||||
|
batcher_pop_end(tsdn_t *tsdn, batcher_t *batcher) {
|
||||||
assert(atomic_load_zu(&batcher->nelems, ATOMIC_RELAXED) == 0);
|
assert(atomic_load_zu(&batcher->nelems, ATOMIC_RELAXED) == 0);
|
||||||
malloc_mutex_unlock(tsdn, &batcher->mtx);
|
malloc_mutex_unlock(tsdn, &batcher->mtx);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
unsigned bin_batching_test_ndalloc_slabs_max = (unsigned)-1;
|
unsigned bin_batching_test_ndalloc_slabs_max = (unsigned)-1;
|
||||||
void (*bin_batching_test_after_push_hook)(size_t push_idx);
|
void (*bin_batching_test_after_push_hook)(size_t push_idx);
|
||||||
void (*bin_batching_test_mid_pop_hook)(size_t nelems_to_pop);
|
void (*bin_batching_test_mid_pop_hook)(size_t nelems_to_pop);
|
||||||
void (*bin_batching_test_after_unlock_hook)(unsigned slab_dalloc_count,
|
void (*bin_batching_test_after_unlock_hook)(
|
||||||
bool list_empty);
|
unsigned slab_dalloc_count, bool list_empty);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -60,8 +60,8 @@ bin_init(bin_t *bin, unsigned binind) {
|
|||||||
}
|
}
|
||||||
if (arena_bin_has_batch(binind)) {
|
if (arena_bin_has_batch(binind)) {
|
||||||
bin_with_batch_t *batched_bin = (bin_with_batch_t *)bin;
|
bin_with_batch_t *batched_bin = (bin_with_batch_t *)bin;
|
||||||
batcher_init(&batched_bin->remote_frees,
|
batcher_init(
|
||||||
opt_bin_info_remote_free_max);
|
&batched_bin->remote_frees, opt_bin_info_remote_free_max);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ bin_infos_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS],
|
|||||||
bin_info->reg_size = ((size_t)1U << sc->lg_base)
|
bin_info->reg_size = ((size_t)1U << sc->lg_base)
|
||||||
+ ((size_t)sc->ndelta << sc->lg_delta);
|
+ ((size_t)sc->ndelta << sc->lg_delta);
|
||||||
bin_info->slab_size = (sc->pgs << LG_PAGE);
|
bin_info->slab_size = (sc->pgs << LG_PAGE);
|
||||||
bin_info->nregs =
|
bin_info->nregs = (uint32_t)(bin_info->slab_size
|
||||||
(uint32_t)(bin_info->slab_size / bin_info->reg_size);
|
/ bin_info->reg_size);
|
||||||
bin_info->n_shards = bin_shard_sizes[i];
|
bin_info->n_shards = bin_shard_sizes[i];
|
||||||
bitmap_info_t bitmap_info = BITMAP_INFO_INITIALIZER(
|
bitmap_info_t bitmap_info = BITMAP_INFO_INITIALIZER(
|
||||||
bin_info->nregs);
|
bin_info->nregs);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user