PAC: Move in decay rate setting.
This commit is contained in:
parent
6a2774719f
commit
471eb5913c
@ -40,10 +40,9 @@ void arena_extent_ralloc_large_shrink(tsdn_t *tsdn, arena_t *arena,
|
|||||||
edata_t *edata, size_t oldsize);
|
edata_t *edata, size_t oldsize);
|
||||||
void arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena,
|
void arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena,
|
||||||
edata_t *edata, size_t oldsize);
|
edata_t *edata, size_t oldsize);
|
||||||
ssize_t arena_dirty_decay_ms_get(arena_t *arena);
|
bool arena_decay_ms_set(tsdn_t *tsdn, arena_t *arena, extent_state_t state,
|
||||||
bool arena_dirty_decay_ms_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_ms);
|
ssize_t decay_ms);
|
||||||
ssize_t arena_muzzy_decay_ms_get(arena_t *arena);
|
ssize_t arena_decay_ms_get(arena_t *arena, extent_state_t state);
|
||||||
bool arena_muzzy_decay_ms_set(tsdn_t *tsdn, arena_t *arena, ssize_t decay_ms);
|
|
||||||
void arena_decay(tsdn_t *tsdn, arena_t *arena, bool is_background_thread,
|
void arena_decay(tsdn_t *tsdn, arena_t *arena, bool is_background_thread,
|
||||||
bool all);
|
bool all);
|
||||||
void arena_reset(tsd_t *tsd, arena_t *arena);
|
void arena_reset(tsd_t *tsd, arena_t *arena);
|
||||||
|
@ -90,7 +90,7 @@ 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_muzzy_decay_ms_get(&shard->pac) <= 0;
|
pac_decay_ms_get(&shard->pac, extent_state_muzzy) <= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline ehooks_t *
|
static inline ehooks_t *
|
||||||
@ -137,6 +137,10 @@ bool pa_shrink(tsdn_t *tsdn, pa_shard_t *shard, edata_t *edata, size_t old_size,
|
|||||||
void pa_dalloc(tsdn_t *tsdn, pa_shard_t *shard, edata_t *edata,
|
void pa_dalloc(tsdn_t *tsdn, pa_shard_t *shard, edata_t *edata,
|
||||||
bool *generated_dirty);
|
bool *generated_dirty);
|
||||||
|
|
||||||
|
bool pa_decay_ms_set(tsdn_t *tsdn, pa_shard_t *shard, extent_state_t state,
|
||||||
|
ssize_t decay_ms, pac_purge_eagerness_t eagerness);
|
||||||
|
ssize_t pa_decay_ms_get(pa_shard_t *shard, extent_state_t state);
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/*
|
/*
|
||||||
* Various bits of "boring" functionality that are still part of this module,
|
* Various bits of "boring" functionality that are still part of this module,
|
||||||
|
@ -10,12 +10,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* How "eager" decay/purging should be. */
|
/* How "eager" decay/purging should be. */
|
||||||
enum pac_decay_purge_setting_e {
|
enum pac_purge_eagerness_e {
|
||||||
PAC_DECAY_PURGE_ALWAYS,
|
PAC_PURGE_ALWAYS,
|
||||||
PAC_DECAY_PURGE_NEVER,
|
PAC_PURGE_NEVER,
|
||||||
PAC_DECAY_PURGE_ON_EPOCH_ADVANCE
|
PAC_PURGE_ON_EPOCH_ADVANCE
|
||||||
};
|
};
|
||||||
typedef enum pac_decay_purge_setting_e pac_decay_purge_setting_t;
|
typedef enum pac_purge_eagerness_e pac_purge_eagerness_t;
|
||||||
|
|
||||||
typedef struct pac_decay_stats_s pac_decay_stats_t;
|
typedef struct pac_decay_stats_s pac_decay_stats_t;
|
||||||
struct pac_decay_stats_s {
|
struct pac_decay_stats_s {
|
||||||
@ -112,16 +112,6 @@ bool pac_retain_grow_limit_get_set(tsdn_t *tsdn, pac_t *pac, size_t *old_limit,
|
|||||||
void pac_stats_merge(tsdn_t *tsdn, pac_t *pac, pac_stats_t *pac_stats_out,
|
void pac_stats_merge(tsdn_t *tsdn, pac_t *pac, pac_stats_t *pac_stats_out,
|
||||||
pac_estats_t *estats_out, size_t *resident);
|
pac_estats_t *estats_out, size_t *resident);
|
||||||
|
|
||||||
static inline ssize_t
|
|
||||||
pac_dirty_decay_ms_get(pac_t *pac) {
|
|
||||||
return decay_ms_read(&pac->decay_dirty);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline ssize_t
|
|
||||||
pac_muzzy_decay_ms_get(pac_t *pac) {
|
|
||||||
return decay_ms_read(&pac->decay_muzzy);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline size_t
|
static inline size_t
|
||||||
pac_mapped(pac_t *pac) {
|
pac_mapped(pac_t *pac) {
|
||||||
return atomic_load_zu(&pac->stats->pac_mapped, ATOMIC_RELAXED);
|
return atomic_load_zu(&pac->stats->pac_mapped, ATOMIC_RELAXED);
|
||||||
@ -146,7 +136,7 @@ void pac_decay_all(tsdn_t *tsdn, pac_t *pac, decay_t *decay,
|
|||||||
*/
|
*/
|
||||||
bool pac_maybe_decay_purge(tsdn_t *tsdn, pac_t *pac, decay_t *decay,
|
bool pac_maybe_decay_purge(tsdn_t *tsdn, pac_t *pac, decay_t *decay,
|
||||||
pac_decay_stats_t *decay_stats, ecache_t *ecache,
|
pac_decay_stats_t *decay_stats, ecache_t *ecache,
|
||||||
pac_decay_purge_setting_t decay_purge_setting);
|
pac_purge_eagerness_t eagerness);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Gets / sets the maximum amount that we'll grow an arena down the
|
* Gets / sets the maximum amount that we'll grow an arena down the
|
||||||
@ -160,4 +150,7 @@ bool pac_maybe_decay_purge(tsdn_t *tsdn, pac_t *pac, decay_t *decay,
|
|||||||
bool pac_retain_grow_limit_get_set(tsdn_t *tsdn, pac_t *pac, size_t *old_limit,
|
bool pac_retain_grow_limit_get_set(tsdn_t *tsdn, pac_t *pac, size_t *old_limit,
|
||||||
size_t *new_limit);
|
size_t *new_limit);
|
||||||
|
|
||||||
|
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 pac_decay_ms_get(pac_t *pac, extent_state_t state);
|
||||||
#endif /* JEMALLOC_INTERNAL_PAC_H */
|
#endif /* JEMALLOC_INTERNAL_PAC_H */
|
||||||
|
86
src/arena.c
86
src/arena.c
@ -70,8 +70,8 @@ arena_basic_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
|||||||
size_t *nactive, size_t *ndirty, size_t *nmuzzy) {
|
size_t *nactive, size_t *ndirty, size_t *nmuzzy) {
|
||||||
*nthreads += arena_nthreads_get(arena, false);
|
*nthreads += arena_nthreads_get(arena, false);
|
||||||
*dss = dss_prec_names[arena_dss_prec_get(arena)];
|
*dss = dss_prec_names[arena_dss_prec_get(arena)];
|
||||||
*dirty_decay_ms = arena_dirty_decay_ms_get(arena);
|
*dirty_decay_ms = arena_decay_ms_get(arena, extent_state_dirty);
|
||||||
*muzzy_decay_ms = arena_muzzy_decay_ms_get(arena);
|
*muzzy_decay_ms = arena_decay_ms_get(arena, extent_state_muzzy);
|
||||||
pa_shard_basic_stats_merge(&arena->pa_shard, nactive, ndirty, nmuzzy);
|
pa_shard_basic_stats_merge(&arena->pa_shard, nactive, ndirty, nmuzzy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +189,7 @@ void arena_handle_new_dirty_pages(tsdn_t *tsdn, arena_t *arena) {
|
|||||||
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
witness_assert_depth_to_rank(tsdn_witness_tsdp_get(tsdn),
|
||||||
WITNESS_RANK_CORE, 0);
|
WITNESS_RANK_CORE, 0);
|
||||||
|
|
||||||
if (arena_dirty_decay_ms_get(arena) == 0) {
|
if (arena_decay_ms_get(arena, extent_state_dirty) == 0) {
|
||||||
arena_decay_dirty(tsdn, arena, false, true);
|
arena_decay_dirty(tsdn, arena, false, true);
|
||||||
} else {
|
} else {
|
||||||
arena_background_thread_inactivity_check(tsdn, arena, false);
|
arena_background_thread_inactivity_check(tsdn, arena, false);
|
||||||
@ -395,77 +395,37 @@ arena_extent_ralloc_large_expand(tsdn_t *tsdn, arena_t *arena, edata_t *edata,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t
|
|
||||||
arena_dirty_decay_ms_get(arena_t *arena) {
|
|
||||||
return pac_dirty_decay_ms_get(&arena->pa_shard.pac);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t
|
|
||||||
arena_muzzy_decay_ms_get(arena_t *arena) {
|
|
||||||
return pac_muzzy_decay_ms_get(&arena->pa_shard.pac);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In situations where we're not forcing a decay (i.e. because the user
|
* In situations where we're not forcing a decay (i.e. because the user
|
||||||
* specifically requested it), should we purge ourselves, or wait for the
|
* specifically requested it), should we purge ourselves, or wait for the
|
||||||
* background thread to get to it.
|
* background thread to get to it.
|
||||||
*/
|
*/
|
||||||
static pac_decay_purge_setting_t
|
static pac_purge_eagerness_t
|
||||||
arena_decide_unforced_decay_purge_setting(bool is_background_thread) {
|
arena_decide_unforced_purge_eagerness(bool is_background_thread) {
|
||||||
if (is_background_thread) {
|
if (is_background_thread) {
|
||||||
return PAC_DECAY_PURGE_ALWAYS;
|
return PAC_PURGE_ALWAYS;
|
||||||
} else if (!is_background_thread && background_thread_enabled()) {
|
} else if (!is_background_thread && background_thread_enabled()) {
|
||||||
return PAC_DECAY_PURGE_NEVER;
|
return PAC_PURGE_NEVER;
|
||||||
} else {
|
} else {
|
||||||
return PAC_DECAY_PURGE_ON_EPOCH_ADVANCE;
|
return PAC_PURGE_ON_EPOCH_ADVANCE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
|
||||||
arena_decay_ms_set(tsdn_t *tsdn, arena_t *arena, decay_t *decay,
|
|
||||||
pac_decay_stats_t *decay_stats, ecache_t *ecache, ssize_t decay_ms) {
|
|
||||||
if (!decay_ms_valid(decay_ms)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
malloc_mutex_lock(tsdn, &decay->mtx);
|
|
||||||
/*
|
|
||||||
* Restart decay backlog from scratch, which may cause many dirty pages
|
|
||||||
* to be immediately purged. It would conceptually be possible to map
|
|
||||||
* the old backlog onto the new backlog, but there is no justification
|
|
||||||
* for such complexity since decay_ms changes are intended to be
|
|
||||||
* infrequent, either between the {-1, 0, >0} states, or a one-time
|
|
||||||
* arbitrary change during initial arena configuration.
|
|
||||||
*/
|
|
||||||
nstime_t cur_time;
|
|
||||||
nstime_init_update(&cur_time);
|
|
||||||
decay_reinit(decay, &cur_time, decay_ms);
|
|
||||||
pac_decay_purge_setting_t decay_purge =
|
|
||||||
arena_decide_unforced_decay_purge_setting(
|
|
||||||
/* is_background_thread */ false);
|
|
||||||
pac_maybe_decay_purge(tsdn, &arena->pa_shard.pac, decay, decay_stats,
|
|
||||||
ecache, decay_purge);
|
|
||||||
malloc_mutex_unlock(tsdn, &decay->mtx);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
arena_dirty_decay_ms_set(tsdn_t *tsdn, arena_t *arena,
|
arena_decay_ms_set(tsdn_t *tsdn, arena_t *arena, extent_state_t state,
|
||||||
ssize_t decay_ms) {
|
ssize_t decay_ms) {
|
||||||
return arena_decay_ms_set(tsdn, arena, &arena->pa_shard.pac.decay_dirty,
|
pac_purge_eagerness_t eagerness = arena_decide_unforced_purge_eagerness(
|
||||||
&arena->pa_shard.pac.stats->decay_dirty,
|
/* is_background_thread */ false);
|
||||||
&arena->pa_shard.pac.ecache_dirty, decay_ms);
|
return pa_decay_ms_set(tsdn, &arena->pa_shard, state, decay_ms,
|
||||||
|
eagerness);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
ssize_t
|
||||||
arena_muzzy_decay_ms_set(tsdn_t *tsdn, arena_t *arena,
|
arena_decay_ms_get(arena_t *arena, extent_state_t state) {
|
||||||
ssize_t decay_ms) {
|
return pa_decay_ms_get(&arena->pa_shard, state);
|
||||||
return arena_decay_ms_set(tsdn, arena, &arena->pa_shard.pac.decay_muzzy,
|
|
||||||
&arena->pa_shard.pac.stats->decay_muzzy,
|
|
||||||
&arena->pa_shard.pac.ecache_muzzy, decay_ms);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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,
|
||||||
@ -497,10 +457,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_decay_purge_setting_t decay_purge =
|
pac_purge_eagerness_t eagerness =
|
||||||
arena_decide_unforced_decay_purge_setting(is_background_thread);
|
arena_decide_unforced_purge_eagerness(is_background_thread);
|
||||||
bool epoch_advanced = pac_maybe_decay_purge(tsdn, &arena->pa_shard.pac,
|
bool epoch_advanced = pac_maybe_decay_purge(tsdn, &arena->pa_shard.pac,
|
||||||
decay, decay_stats, ecache, decay_purge);
|
decay, decay_stats, ecache, eagerness);
|
||||||
size_t npages_new;
|
size_t npages_new;
|
||||||
if (epoch_advanced) {
|
if (epoch_advanced) {
|
||||||
/* Backlog is updated on epoch advance. */
|
/* Backlog is updated on epoch advance. */
|
||||||
@ -1546,10 +1506,12 @@ arena_choose_huge(tsd_t *tsd) {
|
|||||||
* expected for huge allocations.
|
* expected for huge allocations.
|
||||||
*/
|
*/
|
||||||
if (arena_dirty_decay_ms_default_get() > 0) {
|
if (arena_dirty_decay_ms_default_get() > 0) {
|
||||||
arena_dirty_decay_ms_set(tsd_tsdn(tsd), huge_arena, 0);
|
arena_decay_ms_set(tsd_tsdn(tsd), huge_arena,
|
||||||
|
extent_state_dirty, 0);
|
||||||
}
|
}
|
||||||
if (arena_muzzy_decay_ms_default_get() > 0) {
|
if (arena_muzzy_decay_ms_default_get() > 0) {
|
||||||
arena_muzzy_decay_ms_set(tsd_tsdn(tsd), huge_arena, 0);
|
arena_decay_ms_set(tsd_tsdn(tsd), huge_arena,
|
||||||
|
extent_state_muzzy, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
src/ctl.c
10
src/ctl.c
@ -2430,10 +2430,10 @@ arena_i_decay_ms_ctl_impl(tsd_t *tsd, const size_t *mib, size_t miblen,
|
|||||||
ret = EFAULT;
|
ret = EFAULT;
|
||||||
goto label_return;
|
goto label_return;
|
||||||
}
|
}
|
||||||
|
extent_state_t state = dirty ? extent_state_dirty : extent_state_muzzy;
|
||||||
|
|
||||||
if (oldp != NULL && oldlenp != NULL) {
|
if (oldp != NULL && oldlenp != NULL) {
|
||||||
size_t oldval = dirty ? arena_dirty_decay_ms_get(arena) :
|
size_t oldval = arena_decay_ms_get(arena, state);
|
||||||
arena_muzzy_decay_ms_get(arena);
|
|
||||||
READ(oldval, ssize_t);
|
READ(oldval, ssize_t);
|
||||||
}
|
}
|
||||||
if (newp != NULL) {
|
if (newp != NULL) {
|
||||||
@ -2452,9 +2452,9 @@ arena_i_decay_ms_ctl_impl(tsd_t *tsd, const size_t *mib, size_t miblen,
|
|||||||
goto label_return;
|
goto label_return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (dirty ? arena_dirty_decay_ms_set(tsd_tsdn(tsd), arena,
|
|
||||||
*(ssize_t *)newp) : arena_muzzy_decay_ms_set(tsd_tsdn(tsd),
|
if (arena_decay_ms_set(tsd_tsdn(tsd), arena, state,
|
||||||
arena, *(ssize_t *)newp)) {
|
*(ssize_t *)newp)) {
|
||||||
ret = EFAULT;
|
ret = EFAULT;
|
||||||
goto label_return;
|
goto label_return;
|
||||||
}
|
}
|
||||||
|
@ -55,8 +55,8 @@ extent_sn_next(pac_t *pac) {
|
|||||||
|
|
||||||
static inline bool
|
static inline bool
|
||||||
extent_may_force_decay(pac_t *pac) {
|
extent_may_force_decay(pac_t *pac) {
|
||||||
return !(pac_dirty_decay_ms_get(pac) == -1
|
return !(pac_decay_ms_get(pac, extent_state_dirty) == -1
|
||||||
|| pac_muzzy_decay_ms_get(pac) == -1);
|
|| pac_decay_ms_get(pac, extent_state_muzzy) == -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
66
src/pa.c
66
src/pa.c
@ -78,9 +78,9 @@ pa_shard_destroy_retained(tsdn_t *tsdn, pa_shard_t *shard) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static inline bool
|
||||||
pa_shard_may_have_muzzy(pa_shard_t *shard) {
|
pa_shard_may_have_muzzy(pa_shard_t *shard) {
|
||||||
return pac_muzzy_decay_ms_get(&shard->pac) != 0;
|
return pac_decay_ms_get(&shard->pac, extent_state_muzzy) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static edata_t *
|
static edata_t *
|
||||||
@ -389,60 +389,20 @@ pa_decay_all(tsdn_t *tsdn, pa_shard_t *shard, decay_t *decay,
|
|||||||
/* npages_limit */ 0, ecache_npages_get(ecache));
|
/* npages_limit */ 0, ecache_npages_get(ecache));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
pa_decay_try_purge(tsdn_t *tsdn, pa_shard_t *shard, decay_t *decay,
|
|
||||||
pac_decay_stats_t *decay_stats, ecache_t *ecache,
|
|
||||||
size_t current_npages, size_t npages_limit) {
|
|
||||||
if (current_npages > npages_limit) {
|
|
||||||
pa_decay_to_limit(tsdn, shard, decay, decay_stats, ecache,
|
|
||||||
/* fully_decay */ false, npages_limit,
|
|
||||||
current_npages - npages_limit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
pa_maybe_decay_purge(tsdn_t *tsdn, pa_shard_t *shard, decay_t *decay,
|
|
||||||
pac_decay_stats_t *decay_stats, ecache_t *ecache,
|
|
||||||
pac_decay_purge_setting_t decay_purge_setting) {
|
|
||||||
malloc_mutex_assert_owner(tsdn, &decay->mtx);
|
|
||||||
|
|
||||||
/* Purge all or nothing if the option is disabled. */
|
|
||||||
ssize_t decay_ms = decay_ms_read(decay);
|
|
||||||
if (decay_ms <= 0) {
|
|
||||||
if (decay_ms == 0) {
|
|
||||||
pa_decay_to_limit(tsdn, shard, decay, decay_stats,
|
|
||||||
ecache, /* fully_decay */ false,
|
|
||||||
/* npages_limit */ 0, ecache_npages_get(ecache));
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the deadline has been reached, advance to the current epoch and
|
|
||||||
* purge to the new limit if necessary. Note that dirty pages created
|
|
||||||
* during the current epoch are not subject to purge until a future
|
|
||||||
* epoch, so as a result purging only happens during epoch advances, or
|
|
||||||
* being triggered by background threads (scheduled event).
|
|
||||||
*/
|
|
||||||
nstime_t time;
|
|
||||||
nstime_init_update(&time);
|
|
||||||
size_t npages_current = ecache_npages_get(ecache);
|
|
||||||
bool epoch_advanced = decay_maybe_advance_epoch(decay, &time,
|
|
||||||
npages_current);
|
|
||||||
if (decay_purge_setting == PAC_DECAY_PURGE_ALWAYS
|
|
||||||
|| (epoch_advanced && decay_purge_setting
|
|
||||||
== PAC_DECAY_PURGE_ON_EPOCH_ADVANCE)) {
|
|
||||||
size_t npages_limit = decay_npages_limit_get(decay);
|
|
||||||
pa_decay_try_purge(tsdn, shard, decay, decay_stats, ecache,
|
|
||||||
npages_current, npages_limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
return epoch_advanced;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
pa_shard_retain_grow_limit_get_set(tsdn_t *tsdn, pa_shard_t *shard,
|
pa_shard_retain_grow_limit_get_set(tsdn_t *tsdn, pa_shard_t *shard,
|
||||||
size_t *old_limit, size_t *new_limit) {
|
size_t *old_limit, size_t *new_limit) {
|
||||||
return pac_retain_grow_limit_get_set(tsdn, &shard->pac, old_limit,
|
return pac_retain_grow_limit_get_set(tsdn, &shard->pac, old_limit,
|
||||||
new_limit);
|
new_limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
pa_decay_ms_set(tsdn_t *tsdn, pa_shard_t *shard, extent_state_t state,
|
||||||
|
ssize_t decay_ms, pac_purge_eagerness_t eagerness) {
|
||||||
|
return pac_decay_ms_set(tsdn, &shard->pac, state, decay_ms, eagerness);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
pa_decay_ms_get(pa_shard_t *shard, extent_state_t state) {
|
||||||
|
return pac_decay_ms_get(&shard->pac, state);
|
||||||
|
}
|
||||||
|
70
src/pac.c
70
src/pac.c
@ -8,6 +8,27 @@ pac_ehooks_get(pac_t *pac) {
|
|||||||
return base_ehooks_get(pac->base);
|
return base_ehooks_get(pac->base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
pac_decay_data_get(pac_t *pac, extent_state_t state,
|
||||||
|
decay_t **r_decay, pac_decay_stats_t **r_decay_stats, ecache_t **r_ecache) {
|
||||||
|
switch(state) {
|
||||||
|
case extent_state_dirty:
|
||||||
|
*r_decay = &pac->decay_dirty;
|
||||||
|
*r_decay_stats = &pac->stats->decay_dirty;
|
||||||
|
*r_ecache = &pac->ecache_dirty;
|
||||||
|
return;
|
||||||
|
case extent_state_muzzy:
|
||||||
|
*r_decay = &pac->decay_muzzy;
|
||||||
|
*r_decay_stats = &pac->stats->decay_muzzy;
|
||||||
|
*r_ecache = &pac->ecache_muzzy;
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
pac_init(tsdn_t *tsdn, pac_t *pac, base_t *base, emap_t *emap,
|
pac_init(tsdn_t *tsdn, pac_t *pac, base_t *base, emap_t *emap,
|
||||||
edata_cache_t *edata_cache, nstime_t *cur_time, ssize_t dirty_decay_ms,
|
edata_cache_t *edata_cache, nstime_t *cur_time, ssize_t dirty_decay_ms,
|
||||||
@ -117,7 +138,8 @@ pac_decay_stashed(tsdn_t *tsdn, pac_t *pac, decay_t *decay,
|
|||||||
|
|
||||||
ehooks_t *ehooks = pac_ehooks_get(pac);
|
ehooks_t *ehooks = pac_ehooks_get(pac);
|
||||||
|
|
||||||
bool try_muzzy = !fully_decay && pac_muzzy_decay_ms_get(pac) != 0;
|
bool try_muzzy = !fully_decay
|
||||||
|
&& pac_decay_ms_get(pac, extent_state_muzzy) != 0;
|
||||||
|
|
||||||
for (edata_t *edata = edata_list_first(decay_extents); edata !=
|
for (edata_t *edata = edata_list_first(decay_extents); edata !=
|
||||||
NULL; edata = edata_list_first(decay_extents)) {
|
NULL; edata = edata_list_first(decay_extents)) {
|
||||||
@ -225,7 +247,7 @@ pac_decay_try_purge(tsdn_t *tsdn, pac_t *pac, decay_t *decay,
|
|||||||
bool
|
bool
|
||||||
pac_maybe_decay_purge(tsdn_t *tsdn, pac_t *pac, decay_t *decay,
|
pac_maybe_decay_purge(tsdn_t *tsdn, pac_t *pac, decay_t *decay,
|
||||||
pac_decay_stats_t *decay_stats, ecache_t *ecache,
|
pac_decay_stats_t *decay_stats, ecache_t *ecache,
|
||||||
pac_decay_purge_setting_t decay_purge_setting) {
|
pac_purge_eagerness_t eagerness) {
|
||||||
malloc_mutex_assert_owner(tsdn, &decay->mtx);
|
malloc_mutex_assert_owner(tsdn, &decay->mtx);
|
||||||
|
|
||||||
/* Purge all or nothing if the option is disabled. */
|
/* Purge all or nothing if the option is disabled. */
|
||||||
@ -251,9 +273,8 @@ pac_maybe_decay_purge(tsdn_t *tsdn, pac_t *pac, decay_t *decay,
|
|||||||
size_t npages_current = ecache_npages_get(ecache);
|
size_t npages_current = ecache_npages_get(ecache);
|
||||||
bool epoch_advanced = decay_maybe_advance_epoch(decay, &time,
|
bool epoch_advanced = decay_maybe_advance_epoch(decay, &time,
|
||||||
npages_current);
|
npages_current);
|
||||||
if (decay_purge_setting == PAC_DECAY_PURGE_ALWAYS
|
if (eagerness == PAC_PURGE_ALWAYS
|
||||||
|| (epoch_advanced && decay_purge_setting
|
|| (epoch_advanced && eagerness == PAC_PURGE_ON_EPOCH_ADVANCE)) {
|
||||||
== PAC_DECAY_PURGE_ON_EPOCH_ADVANCE)) {
|
|
||||||
size_t npages_limit = decay_npages_limit_get(decay);
|
size_t npages_limit = decay_npages_limit_get(decay);
|
||||||
pac_decay_try_purge(tsdn, pac, decay, decay_stats, ecache,
|
pac_decay_try_purge(tsdn, pac, decay, decay_stats, ecache,
|
||||||
npages_current, npages_limit);
|
npages_current, npages_limit);
|
||||||
@ -261,3 +282,42 @@ pac_maybe_decay_purge(tsdn_t *tsdn, pac_t *pac, decay_t *decay,
|
|||||||
|
|
||||||
return epoch_advanced;
|
return epoch_advanced;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
pac_decay_ms_set(tsdn_t *tsdn, pac_t *pac, extent_state_t state,
|
||||||
|
ssize_t decay_ms, pac_purge_eagerness_t eagerness) {
|
||||||
|
decay_t *decay;
|
||||||
|
pac_decay_stats_t *decay_stats;
|
||||||
|
ecache_t *ecache;
|
||||||
|
pac_decay_data_get(pac, state, &decay, &decay_stats, &ecache);
|
||||||
|
|
||||||
|
if (!decay_ms_valid(decay_ms)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
malloc_mutex_lock(tsdn, &decay->mtx);
|
||||||
|
/*
|
||||||
|
* Restart decay backlog from scratch, which may cause many dirty pages
|
||||||
|
* to be immediately purged. It would conceptually be possible to map
|
||||||
|
* the old backlog onto the new backlog, but there is no justification
|
||||||
|
* for such complexity since decay_ms changes are intended to be
|
||||||
|
* infrequent, either between the {-1, 0, >0} states, or a one-time
|
||||||
|
* arbitrary change during initial arena configuration.
|
||||||
|
*/
|
||||||
|
nstime_t cur_time;
|
||||||
|
nstime_init_update(&cur_time);
|
||||||
|
decay_reinit(decay, &cur_time, decay_ms);
|
||||||
|
pac_maybe_decay_purge(tsdn, pac, decay, decay_stats, ecache, eagerness);
|
||||||
|
malloc_mutex_unlock(tsdn, &decay->mtx);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
pac_decay_ms_get(pac_t *pac, extent_state_t state) {
|
||||||
|
decay_t *decay;
|
||||||
|
pac_decay_stats_t *decay_stats;
|
||||||
|
ecache_t *ecache;
|
||||||
|
pac_decay_data_get(pac, state, &decay, &decay_stats, &ecache);
|
||||||
|
return decay_ms_read(decay);
|
||||||
|
}
|
||||||
|
@ -107,7 +107,6 @@ TEST_BEGIN(test_alloc_free_purge_thds) {
|
|||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
thd_join(thds[i], NULL);
|
thd_join(thds[i], NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
TEST_END
|
TEST_END
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user