mirror of
https://github.com/jemalloc/jemalloc
synced 2026-06-08 15:01:07 +00:00
f008ce9fe1
This change includes the following improvements: - Remove the hpa_sec_batch_fill_extra parameter. - Refactor the hpa_alloc() code and helper functions to be able to allocate more than one extent out of a single pageslab. This way we can amortize the per-pageslab costs (active bitmap iteration, pageslab metadata updates) across multiple extents. - Decide on a min and max number of extents that will be allocated in hpa_alloc(). The code will try to allocate at least the min and allocate up to the max as long as we can allocate additional ones from the pageslab we already have, as additional allocations are relatively cheap. - Add extent allocation distribution stats. - Amend hpa_sec_integration.c unit test.
245 lines
7.0 KiB
C
245 lines
7.0 KiB
C
#ifndef JEMALLOC_INTERNAL_HPA_H
|
|
#define JEMALLOC_INTERNAL_HPA_H
|
|
|
|
#include "jemalloc/internal/jemalloc_preamble.h"
|
|
#include "jemalloc/internal/base.h"
|
|
#include "jemalloc/internal/edata_cache.h"
|
|
#include "jemalloc/internal/emap.h"
|
|
#include "jemalloc/internal/exp_grow.h"
|
|
#include "jemalloc/internal/hpa_central.h"
|
|
#include "jemalloc/internal/hpa_hooks.h"
|
|
#include "jemalloc/internal/hpa_opts.h"
|
|
#include "jemalloc/internal/mutex.h"
|
|
#include "jemalloc/internal/psset.h"
|
|
#include "jemalloc/internal/sec.h"
|
|
|
|
typedef struct hpa_shard_nonderived_stats_s hpa_shard_nonderived_stats_t;
|
|
struct hpa_shard_nonderived_stats_s {
|
|
/*
|
|
* The number of times we've purged within a hugepage.
|
|
*
|
|
* Guarded by mtx.
|
|
*/
|
|
uint64_t npurge_passes;
|
|
/*
|
|
* The number of individual purge calls we perform (which should always
|
|
* be bigger than npurge_passes, since each pass purges at least one
|
|
* extent within a hugepage.
|
|
*
|
|
* Guarded by mtx.
|
|
*/
|
|
uint64_t npurges;
|
|
|
|
/*
|
|
* The number of times we've hugified a pageslab.
|
|
*
|
|
* Guarded by mtx.
|
|
*/
|
|
uint64_t nhugifies;
|
|
|
|
/*
|
|
* The number of times we've tried to hugify a pageslab, but failed.
|
|
*
|
|
* Guarded by mtx.
|
|
*/
|
|
uint64_t nhugify_failures;
|
|
|
|
/*
|
|
* The number of times we've dehugified a pageslab.
|
|
*
|
|
* Guarded by mtx.
|
|
*/
|
|
uint64_t ndehugifies;
|
|
|
|
/*
|
|
* Distribution of the min number of extents we will try to allocate
|
|
* from a single hpa_alloc() call.
|
|
*
|
|
* Guarded by mtx.
|
|
*/
|
|
uint64_t hpa_alloc_min_extents[SEC_MAX_NALLOCS + 1];
|
|
|
|
/*
|
|
* Distribution of the max number of extents we will try to allocate
|
|
* from a single hpa_alloc() call.
|
|
*
|
|
* Guarded by mtx.
|
|
*/
|
|
uint64_t hpa_alloc_max_extents[SEC_MAX_NALLOCS + 1];
|
|
|
|
/*
|
|
* Distribution of the number of extents allocated for a single
|
|
* hpa_alloc() call and a single mtx lock acquisition.
|
|
*
|
|
* Guarded by mtx.
|
|
*/
|
|
uint64_t hpa_alloc_extents[SEC_MAX_NALLOCS + 1];
|
|
|
|
/*
|
|
* Distribution of the number of ps out of which we allocated extents
|
|
* for a single hpa_alloc() call and a single mtx lock acquisition.
|
|
*
|
|
* Guarded by mtx.
|
|
*/
|
|
uint64_t hpa_alloc_ps[SEC_MAX_NALLOCS + 1];
|
|
|
|
/*
|
|
* Distribution of the number of pages allocated from a single ps.
|
|
*
|
|
* Guarded by mtx.
|
|
*/
|
|
uint64_t hpa_alloc_pages_per_ps[SEC_MAX_NALLOCS + 1];
|
|
|
|
/*
|
|
* Distribution of the number of extents allocated from a single ps.
|
|
*
|
|
* Guarded by mtx.
|
|
*/
|
|
uint64_t hpa_alloc_extents_per_ps[SEC_MAX_NALLOCS + 1];
|
|
|
|
/*
|
|
* Distribution of the total elapsed time (ns) for allocating extents
|
|
* from a single ps.
|
|
*
|
|
* Guarded by mtx.
|
|
*/
|
|
uint64_t hpa_alloc_total_elapsed_ns_per_ps[SEC_MAX_NALLOCS + 1];
|
|
};
|
|
|
|
/* Completely derived; only used by CTL. */
|
|
typedef struct hpa_shard_stats_s hpa_shard_stats_t;
|
|
struct hpa_shard_stats_s {
|
|
psset_stats_t psset_stats;
|
|
hpa_shard_nonderived_stats_t nonderived_stats;
|
|
sec_stats_t secstats;
|
|
};
|
|
|
|
typedef struct hpa_shard_s hpa_shard_t;
|
|
struct hpa_shard_s {
|
|
/* The central allocator we get our hugepages from. */
|
|
hpa_central_t *central;
|
|
|
|
/* Protects most of this shard's state. */
|
|
malloc_mutex_t mtx;
|
|
|
|
/*
|
|
* Guards the shard's access to the central allocator (preventing
|
|
* multiple threads operating on this shard from accessing the central
|
|
* allocator).
|
|
*/
|
|
malloc_mutex_t grow_mtx;
|
|
|
|
/* The base metadata allocator. */
|
|
base_t *base;
|
|
|
|
/*
|
|
* This edata cache is the one we use when allocating a small extent
|
|
* from a pageslab. The pageslab itself comes from the centralized
|
|
* allocator, and so will use its edata_cache.
|
|
*/
|
|
edata_cache_fast_t ecf;
|
|
|
|
/* Small extent cache (not guarded by mtx) */
|
|
JEMALLOC_ALIGNED(CACHELINE) sec_t sec;
|
|
|
|
psset_t psset;
|
|
|
|
/*
|
|
* How many grow operations have occurred.
|
|
*
|
|
* Guarded by grow_mtx.
|
|
*/
|
|
uint64_t age_counter;
|
|
|
|
/* The arena ind we're associated with. */
|
|
unsigned ind;
|
|
|
|
/*
|
|
* Our emap. This is just a cache of the emap pointer in the associated
|
|
* hpa_central.
|
|
*/
|
|
emap_t *emap;
|
|
|
|
/* The configuration choices for this hpa shard. */
|
|
hpa_shard_opts_t opts;
|
|
|
|
/*
|
|
* How many pages have we started but not yet finished purging in this
|
|
* hpa shard.
|
|
*/
|
|
size_t npending_purge;
|
|
|
|
/*
|
|
* Those stats which are copied directly into the CTL-centric hpa shard
|
|
* stats.
|
|
*/
|
|
hpa_shard_nonderived_stats_t stats;
|
|
|
|
/*
|
|
* Last time we performed purge on this shard.
|
|
*/
|
|
nstime_t last_purge;
|
|
|
|
/*
|
|
* Last time when we attempted work (purging or hugifying). If deferral
|
|
* of the work is allowed (we have background thread), this is the time
|
|
* when background thread checked if purging or hugifying needs to be
|
|
* done. If deferral is not allowed, this is the time of (hpa_alloc or
|
|
* hpa_dalloc) activity in the shard.
|
|
*/
|
|
nstime_t last_time_work_attempted;
|
|
};
|
|
|
|
bool hpa_hugepage_size_exceeds_limit(void);
|
|
/*
|
|
* Whether or not the HPA can be used given the current configuration. This
|
|
* is not necessarily a guarantee that it backs its allocations by hugepages,
|
|
* just that it can function properly given the system it's running on.
|
|
*/
|
|
bool hpa_supported(void);
|
|
bool hpa_shard_init(tsdn_t *tsdn, hpa_shard_t *shard, hpa_central_t *central,
|
|
emap_t *emap, base_t *base, edata_cache_t *edata_cache, unsigned ind,
|
|
const hpa_shard_opts_t *opts, const sec_opts_t *sec_opts);
|
|
|
|
edata_t *hpa_alloc(tsdn_t *tsdn, hpa_shard_t *shard, size_t size,
|
|
size_t alignment, bool zero, bool guarded, bool frequent_reuse,
|
|
bool *deferred_work_generated);
|
|
bool hpa_expand(tsdn_t *tsdn, hpa_shard_t *shard, edata_t *edata,
|
|
size_t old_size, size_t new_size, bool zero,
|
|
bool *deferred_work_generated);
|
|
bool hpa_shrink(tsdn_t *tsdn, hpa_shard_t *shard, edata_t *edata,
|
|
size_t old_size, size_t new_size, bool *deferred_work_generated);
|
|
void hpa_dalloc(tsdn_t *tsdn, hpa_shard_t *shard, edata_t *edata,
|
|
bool *deferred_work_generated);
|
|
uint64_t hpa_time_until_deferred_work(tsdn_t *tsdn, hpa_shard_t *shard);
|
|
|
|
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, hpa_shard_stats_t *dst);
|
|
|
|
/*
|
|
* Notify the shard that we won't use it for allocations much longer. Due to
|
|
* the possibility of races, we don't actually prevent allocations; just flush
|
|
* and disable the embedded edata_cache_small.
|
|
*/
|
|
void hpa_shard_disable(tsdn_t *tsdn, hpa_shard_t *shard);
|
|
void hpa_shard_destroy(tsdn_t *tsdn, hpa_shard_t *shard);
|
|
/* Flush caches that shard may be using */
|
|
void hpa_shard_flush(tsdn_t *tsdn, hpa_shard_t *shard);
|
|
|
|
void hpa_shard_set_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);
|
|
|
|
/*
|
|
* We share the fork ordering with the PA and arena prefork handling; that's why
|
|
* these are 2, 3 and 4 rather than 0 and 1.
|
|
*/
|
|
void hpa_shard_prefork2(tsdn_t *tsdn, hpa_shard_t *shard);
|
|
void hpa_shard_prefork3(tsdn_t *tsdn, hpa_shard_t *shard);
|
|
void hpa_shard_prefork4(tsdn_t *tsdn, hpa_shard_t *shard);
|
|
void hpa_shard_postfork_parent(tsdn_t *tsdn, hpa_shard_t *shard);
|
|
void hpa_shard_postfork_child(tsdn_t *tsdn, hpa_shard_t *shard);
|
|
|
|
#endif /* JEMALLOC_INTERNAL_HPA_H */
|