#ifndef JEMALLOC_INTERNAL_PSSET_H #define JEMALLOC_INTERNAL_PSSET_H #include "jemalloc/internal/hpdata.h" /* * A page-slab set. What the eset is to PAC, the psset is to HPA. It maintains * a collection of page-slabs (the intent being that they are backed by * hugepages, or at least could be), and handles allocation and deallocation * requests. */ /* * One more than the maximum pszind_t we will serve out of the HPA. * Practically, we expect only the first few to be actually used. This * corresponds to a maximum size of of 512MB on systems with 4k pages and * SC_NGROUP == 4, which is already an unreasonably large maximum. Morally, you * can think of this as being SC_NPSIZES, but there's no sense in wasting that * much space in the arena, making bitmaps that much larger, etc. */ #define PSSET_NPSIZES 64 typedef struct psset_bin_stats_s psset_bin_stats_t; struct psset_bin_stats_s { /* How many pageslabs are in this bin? */ size_t npageslabs; /* Of them, how many pages are active? */ size_t nactive; /* And how many are dirty? */ size_t ndirty; }; typedef struct psset_stats_s psset_stats_t; struct psset_stats_s { /* * The second index is huge stats; nonfull_slabs[pszind][0] contains * stats for the non-huge slabs in bucket pszind, while * nonfull_slabs[pszind][1] contains stats for the huge slabs. */ psset_bin_stats_t nonfull_slabs[PSSET_NPSIZES][2]; /* * Full slabs don't live in any edata heap, but we still track their * stats. */ psset_bin_stats_t full_slabs[2]; /* Empty slabs are similar. */ psset_bin_stats_t empty_slabs[2]; }; typedef struct psset_s psset_t; struct psset_s { /* * The pageslabs, quantized by the size class of the largest contiguous * free run of pages in a pageslab. */ hpdata_age_heap_t pageslabs[PSSET_NPSIZES]; bitmap_t bitmap[BITMAP_GROUPS(PSSET_NPSIZES)]; /* * The sum of all bin stats in stats. This lets us quickly answer * queries for the number of dirty, active, and retained pages in the * entire set. */ psset_bin_stats_t merged_stats; psset_stats_t stats; /* * Slabs with no active allocations, but which are allowed to serve new * allocations. */ hpdata_empty_list_t empty; /* Slabs which are available to be purged. */ hpdata_purge_list_t to_purge; /* Slabs which are available to be hugified. */ hpdata_hugify_list_t to_hugify; }; void psset_init(psset_t *psset); void psset_stats_accum(psset_stats_t *dst, psset_stats_t *src); /* * Begin or end updating the given pageslab's metadata. While the pageslab is * being updated, it won't be returned from psset_fit calls. */ void psset_update_begin(psset_t *psset, hpdata_t *ps); void psset_update_end(psset_t *psset, hpdata_t *ps); /* Analogous to the eset_fit; pick a hpdata to serve the request. */ hpdata_t *psset_pick_alloc(psset_t *psset, size_t size); /* Pick one to purge. */ hpdata_t *psset_pick_purge(psset_t *psset); /* Pick one to hugify. */ hpdata_t *psset_pick_hugify(psset_t *psset); void psset_insert(psset_t *psset, hpdata_t *ps); void psset_remove(psset_t *psset, hpdata_t *ps); static inline size_t psset_npageslabs(psset_t *psset) { return psset->merged_stats.npageslabs; } static inline size_t psset_nactive(psset_t *psset) { return psset->merged_stats.nactive; } static inline size_t psset_ndirty(psset_t *psset) { return psset->merged_stats.ndirty; } #endif /* JEMALLOC_INTERNAL_PSSET_H */