diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-01-21 22:52:54 +0100 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-01-21 22:52:54 +0100 |
| commit | dcacc00e3750300617ba6e16eb346713f91a783a (patch) | |
| tree | 38e2d4fb5ed9d119711d4295c6eda4b014af73fd /examples/redis-unstable/deps/jemalloc/src/decay.c | |
| parent | 58dac10aeb8f5a041c46bddbeaf4c7966a99b998 (diff) | |
| download | crep-dcacc00e3750300617ba6e16eb346713f91a783a.tar.gz | |
Remove testing data
Diffstat (limited to 'examples/redis-unstable/deps/jemalloc/src/decay.c')
| -rw-r--r-- | examples/redis-unstable/deps/jemalloc/src/decay.c | 295 |
1 files changed, 0 insertions, 295 deletions
diff --git a/examples/redis-unstable/deps/jemalloc/src/decay.c b/examples/redis-unstable/deps/jemalloc/src/decay.c deleted file mode 100644 index d801b2b..0000000 --- a/examples/redis-unstable/deps/jemalloc/src/decay.c +++ /dev/null @@ -1,295 +0,0 @@ -#include "jemalloc/internal/jemalloc_preamble.h" -#include "jemalloc/internal/jemalloc_internal_includes.h" - -#include "jemalloc/internal/decay.h" - -static const uint64_t h_steps[SMOOTHSTEP_NSTEPS] = { -#define STEP(step, h, x, y) \ - h, - SMOOTHSTEP -#undef STEP -}; - -/* - * Generate a new deadline that is uniformly random within the next epoch after - * the current one. - */ -void -decay_deadline_init(decay_t *decay) { - nstime_copy(&decay->deadline, &decay->epoch); - nstime_add(&decay->deadline, &decay->interval); - if (decay_ms_read(decay) > 0) { - nstime_t jitter; - - nstime_init(&jitter, prng_range_u64(&decay->jitter_state, - nstime_ns(&decay->interval))); - nstime_add(&decay->deadline, &jitter); - } -} - -void -decay_reinit(decay_t *decay, nstime_t *cur_time, ssize_t decay_ms) { - atomic_store_zd(&decay->time_ms, decay_ms, ATOMIC_RELAXED); - if (decay_ms > 0) { - nstime_init(&decay->interval, (uint64_t)decay_ms * - KQU(1000000)); - nstime_idivide(&decay->interval, SMOOTHSTEP_NSTEPS); - } - - nstime_copy(&decay->epoch, cur_time); - decay->jitter_state = (uint64_t)(uintptr_t)decay; - decay_deadline_init(decay); - decay->nunpurged = 0; - memset(decay->backlog, 0, SMOOTHSTEP_NSTEPS * sizeof(size_t)); -} - -bool -decay_init(decay_t *decay, nstime_t *cur_time, ssize_t decay_ms) { - if (config_debug) { - for (size_t i = 0; i < sizeof(decay_t); i++) { - assert(((char *)decay)[i] == 0); - } - decay->ceil_npages = 0; - } - if (malloc_mutex_init(&decay->mtx, "decay", WITNESS_RANK_DECAY, - malloc_mutex_rank_exclusive)) { - return true; - } - decay->purging = false; - decay_reinit(decay, cur_time, decay_ms); - return false; -} - -bool -decay_ms_valid(ssize_t decay_ms) { - if (decay_ms < -1) { - return false; - } - if (decay_ms == -1 || (uint64_t)decay_ms <= NSTIME_SEC_MAX * - KQU(1000)) { - return true; - } - return false; -} - -static void -decay_maybe_update_time(decay_t *decay, nstime_t *new_time) { - if (unlikely(!nstime_monotonic() && nstime_compare(&decay->epoch, - new_time) > 0)) { - /* - * Time went backwards. Move the epoch back in time and - * generate a new deadline, with the expectation that time - * typically flows forward for long enough periods of time that - * epochs complete. Unfortunately, this strategy is susceptible - * to clock jitter triggering premature epoch advances, but - * clock jitter estimation and compensation isn't feasible here - * because calls into this code are event-driven. - */ - nstime_copy(&decay->epoch, new_time); - decay_deadline_init(decay); - } else { - /* Verify that time does not go backwards. */ - assert(nstime_compare(&decay->epoch, new_time) <= 0); - } -} - -static size_t -decay_backlog_npages_limit(const decay_t *decay) { - /* - * For each element of decay_backlog, multiply by the corresponding - * fixed-point smoothstep decay factor. Sum the products, then divide - * to round down to the nearest whole number of pages. - */ - uint64_t sum = 0; - for (unsigned i = 0; i < SMOOTHSTEP_NSTEPS; i++) { - sum += decay->backlog[i] * h_steps[i]; - } - size_t npages_limit_backlog = (size_t)(sum >> SMOOTHSTEP_BFP); - - return npages_limit_backlog; -} - -/* - * Update backlog, assuming that 'nadvance_u64' time intervals have passed. - * Trailing 'nadvance_u64' records should be erased and 'current_npages' is - * placed as the newest record. - */ -static void -decay_backlog_update(decay_t *decay, uint64_t nadvance_u64, - size_t current_npages) { - if (nadvance_u64 >= SMOOTHSTEP_NSTEPS) { - memset(decay->backlog, 0, (SMOOTHSTEP_NSTEPS-1) * - sizeof(size_t)); - } else { - size_t nadvance_z = (size_t)nadvance_u64; - - assert((uint64_t)nadvance_z == nadvance_u64); - - memmove(decay->backlog, &decay->backlog[nadvance_z], - (SMOOTHSTEP_NSTEPS - nadvance_z) * sizeof(size_t)); - if (nadvance_z > 1) { - memset(&decay->backlog[SMOOTHSTEP_NSTEPS - - nadvance_z], 0, (nadvance_z-1) * sizeof(size_t)); - } - } - - size_t npages_delta = (current_npages > decay->nunpurged) ? - current_npages - decay->nunpurged : 0; - decay->backlog[SMOOTHSTEP_NSTEPS-1] = npages_delta; - - if (config_debug) { - if (current_npages > decay->ceil_npages) { - decay->ceil_npages = current_npages; - } - size_t npages_limit = decay_backlog_npages_limit(decay); - assert(decay->ceil_npages >= npages_limit); - if (decay->ceil_npages > npages_limit) { - decay->ceil_npages = npages_limit; - } - } -} - -static inline bool -decay_deadline_reached(const decay_t *decay, const nstime_t *time) { - return (nstime_compare(&decay->deadline, time) <= 0); -} - -uint64_t -decay_npages_purge_in(decay_t *decay, nstime_t *time, size_t npages_new) { - uint64_t decay_interval_ns = decay_epoch_duration_ns(decay); - size_t n_epoch = (size_t)(nstime_ns(time) / decay_interval_ns); - - uint64_t npages_purge; - if (n_epoch >= SMOOTHSTEP_NSTEPS) { - npages_purge = npages_new; - } else { - uint64_t h_steps_max = h_steps[SMOOTHSTEP_NSTEPS - 1]; - assert(h_steps_max >= - h_steps[SMOOTHSTEP_NSTEPS - 1 - n_epoch]); - npages_purge = npages_new * (h_steps_max - - h_steps[SMOOTHSTEP_NSTEPS - 1 - n_epoch]); - npages_purge >>= SMOOTHSTEP_BFP; - } - return npages_purge; -} - -bool -decay_maybe_advance_epoch(decay_t *decay, nstime_t *new_time, - size_t npages_current) { - /* Handle possible non-monotonicity of time. */ - decay_maybe_update_time(decay, new_time); - - if (!decay_deadline_reached(decay, new_time)) { - return false; - } - nstime_t delta; - nstime_copy(&delta, new_time); - nstime_subtract(&delta, &decay->epoch); - - uint64_t nadvance_u64 = nstime_divide(&delta, &decay->interval); - assert(nadvance_u64 > 0); - - /* Add nadvance_u64 decay intervals to epoch. */ - nstime_copy(&delta, &decay->interval); - nstime_imultiply(&delta, nadvance_u64); - nstime_add(&decay->epoch, &delta); - - /* Set a new deadline. */ - decay_deadline_init(decay); - - /* Update the backlog. */ - decay_backlog_update(decay, nadvance_u64, npages_current); - - decay->npages_limit = decay_backlog_npages_limit(decay); - decay->nunpurged = (decay->npages_limit > npages_current) ? - decay->npages_limit : npages_current; - - return true; -} - -/* - * Calculate how many pages should be purged after 'interval'. - * - * First, calculate how many pages should remain at the moment, then subtract - * the number of pages that should remain after 'interval'. The difference is - * how many pages should be purged until then. - * - * The number of pages that should remain at a specific moment is calculated - * like this: pages(now) = sum(backlog[i] * h_steps[i]). After 'interval' - * passes, backlog would shift 'interval' positions to the left and sigmoid - * curve would be applied starting with backlog[interval]. - * - * The implementation doesn't directly map to the description, but it's - * essentially the same calculation, optimized to avoid iterating over - * [interval..SMOOTHSTEP_NSTEPS) twice. - */ -static inline size_t -decay_npurge_after_interval(decay_t *decay, size_t interval) { - size_t i; - uint64_t sum = 0; - for (i = 0; i < interval; i++) { - sum += decay->backlog[i] * h_steps[i]; - } - for (; i < SMOOTHSTEP_NSTEPS; i++) { - sum += decay->backlog[i] * - (h_steps[i] - h_steps[i - interval]); - } - - return (size_t)(sum >> SMOOTHSTEP_BFP); -} - -uint64_t decay_ns_until_purge(decay_t *decay, size_t npages_current, - uint64_t npages_threshold) { - if (!decay_gradually(decay)) { - return DECAY_UNBOUNDED_TIME_TO_PURGE; - } - uint64_t decay_interval_ns = decay_epoch_duration_ns(decay); - assert(decay_interval_ns > 0); - if (npages_current == 0) { - unsigned i; - for (i = 0; i < SMOOTHSTEP_NSTEPS; i++) { - if (decay->backlog[i] > 0) { - break; - } - } - if (i == SMOOTHSTEP_NSTEPS) { - /* No dirty pages recorded. Sleep indefinitely. */ - return DECAY_UNBOUNDED_TIME_TO_PURGE; - } - } - if (npages_current <= npages_threshold) { - /* Use max interval. */ - return decay_interval_ns * SMOOTHSTEP_NSTEPS; - } - - /* Minimal 2 intervals to ensure reaching next epoch deadline. */ - size_t lb = 2; - size_t ub = SMOOTHSTEP_NSTEPS; - - size_t npurge_lb, npurge_ub; - npurge_lb = decay_npurge_after_interval(decay, lb); - if (npurge_lb > npages_threshold) { - return decay_interval_ns * lb; - } - npurge_ub = decay_npurge_after_interval(decay, ub); - if (npurge_ub < npages_threshold) { - return decay_interval_ns * ub; - } - - unsigned n_search = 0; - size_t target, npurge; - while ((npurge_lb + npages_threshold < npurge_ub) && (lb + 2 < ub)) { - target = (lb + ub) / 2; - npurge = decay_npurge_after_interval(decay, target); - if (npurge > npages_threshold) { - ub = target; - npurge_ub = npurge; - } else { - lb = target; - npurge_lb = npurge; - } - assert(n_search < lg_floor(SMOOTHSTEP_NSTEPS) + 1); - ++n_search; - } - return decay_interval_ns * (ub + lb) / 2; -} |
