Add psset: a set of pageslabs.
This introduces a new sort of edata_t; a pageslab, and a set to manage them. This is part of a series of a commits to implement a hugepage allocator; the pageset will be per-arena, and track small page allocations requests within a larger extent allocated from a centralized hugepage allocator.
This commit is contained in:
committed by
David Goldblatt
parent
ed99d300b9
commit
018b162d67
@@ -202,7 +202,31 @@ struct edata_s {
|
||||
* This keeps the size of an edata_t at exactly 128 bytes on
|
||||
* architectures with 8-byte pointers and 4k pages.
|
||||
*/
|
||||
void *reserved1, *reserved2;
|
||||
void *reserved1;
|
||||
union {
|
||||
/*
|
||||
* We could steal a low bit from these fields to indicate what
|
||||
* sort of "thing" this is (a page slab, an object within a page
|
||||
* slab, or a non-pageslab range). We don't do this yet, but it
|
||||
* would enable some extra asserts.
|
||||
*/
|
||||
|
||||
/*
|
||||
* If this edata is from an HPA, it may be part of some larger
|
||||
* pageslab. Track it if so. Otherwise (either because it's
|
||||
* not part of a pageslab, or not from the HPA at all), NULL.
|
||||
*/
|
||||
edata_t *ps;
|
||||
/*
|
||||
* If this edata *is* a pageslab, then it has some longest free
|
||||
* range in it. Track it.
|
||||
*/
|
||||
struct {
|
||||
uint32_t longest_free_range;
|
||||
/* Not yet tracked. */
|
||||
/* uint32_t longest_free_range_pos; */
|
||||
};
|
||||
};
|
||||
|
||||
union {
|
||||
/*
|
||||
@@ -346,6 +370,18 @@ edata_bsize_get(const edata_t *edata) {
|
||||
return edata->e_bsize;
|
||||
}
|
||||
|
||||
static inline edata_t *
|
||||
edata_ps_get(const edata_t *edata) {
|
||||
assert(edata_pai_get(edata) == EXTENT_PAI_HPA);
|
||||
return edata->ps;
|
||||
}
|
||||
|
||||
static inline uint32_t
|
||||
edata_longest_free_range_get(const edata_t *edata) {
|
||||
assert(edata_pai_get(edata) == EXTENT_PAI_HPA);
|
||||
return edata->longest_free_range;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
edata_before_get(const edata_t *edata) {
|
||||
return (void *)((uintptr_t)edata_base_get(edata) - PAGE);
|
||||
@@ -428,6 +464,19 @@ edata_bsize_set(edata_t *edata, size_t bsize) {
|
||||
edata->e_bsize = bsize;
|
||||
}
|
||||
|
||||
static inline void
|
||||
edata_ps_set(edata_t *edata, edata_t *ps) {
|
||||
assert(edata_pai_get(edata) == EXTENT_PAI_HPA || ps == NULL);
|
||||
edata->ps = ps;
|
||||
}
|
||||
|
||||
static inline void
|
||||
edata_longest_free_range_set(edata_t *edata, uint32_t longest_free_range) {
|
||||
assert(edata_pai_get(edata) == EXTENT_PAI_HPA
|
||||
|| longest_free_range == 0);
|
||||
edata->longest_free_range = longest_free_range;
|
||||
}
|
||||
|
||||
static inline void
|
||||
edata_szind_set(edata_t *edata, szind_t szind) {
|
||||
assert(szind <= SC_NSIZES); /* SC_NSIZES means "invalid". */
|
||||
@@ -562,6 +611,8 @@ edata_init(edata_t *edata, unsigned arena_ind, void *addr, size_t size,
|
||||
if (config_prof) {
|
||||
edata_prof_tctx_set(edata, NULL);
|
||||
}
|
||||
edata_ps_set(edata, NULL);
|
||||
edata_longest_free_range_set(edata, 0);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -581,6 +632,8 @@ edata_binit(edata_t *edata, void *addr, size_t bsize, size_t sn) {
|
||||
* wasting a state bit to encode this fact.
|
||||
*/
|
||||
edata_pai_set(edata, EXTENT_PAI_PAC);
|
||||
edata_ps_set(edata, NULL);
|
||||
edata_longest_free_range_set(edata, 0);
|
||||
}
|
||||
|
||||
static inline int
|
||||
|
61
include/jemalloc/internal/psset.h
Normal file
61
include/jemalloc/internal/psset.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef JEMALLOC_INTERNAL_PSSET_H
|
||||
#define JEMALLOC_INTERNAL_PSSET_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.
|
||||
*
|
||||
* It has the same synchronization guarantees as the eset; stats queries don't
|
||||
* need any external synchronization, everything else does.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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_s psset_t;
|
||||
struct psset_s {
|
||||
/*
|
||||
* The pageslabs, quantized by the size class of the largest contiguous
|
||||
* free run of pages in a pageslab.
|
||||
*/
|
||||
edata_heap_t pageslabs[PSSET_NPSIZES];
|
||||
bitmap_t bitmap[BITMAP_GROUPS(PSSET_NPSIZES)];
|
||||
};
|
||||
|
||||
void psset_init(psset_t *psset);
|
||||
|
||||
|
||||
/*
|
||||
* Tries to obtain a chunk from an existing pageslab already in the set.
|
||||
* Returns true on failure.
|
||||
*/
|
||||
bool psset_alloc_reuse(psset_t *psset, edata_t *r_edata, size_t size);
|
||||
|
||||
/*
|
||||
* Given a newly created pageslab ps (not currently in the set), pass ownership
|
||||
* to the psset and allocate an extent from within it. The passed-in pageslab
|
||||
* must be at least as big as size.
|
||||
*/
|
||||
void psset_alloc_new(psset_t *psset, edata_t *ps,
|
||||
edata_t *r_edata, size_t size);
|
||||
|
||||
/*
|
||||
* Given an extent that comes from a pageslab in this pageslab set, returns it
|
||||
* to its slab. Does not take ownership of the underlying edata_t.
|
||||
*
|
||||
* If some slab becomes empty as a result of the dalloc, it is retuend -- the
|
||||
* result must be checked and deallocated to the central HPA. Otherwise returns
|
||||
* NULL.
|
||||
*/
|
||||
edata_t *psset_dalloc(psset_t *psset, edata_t *edata);
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_PSSET_H */
|
Reference in New Issue
Block a user