mirror of
https://github.com/jemalloc/jemalloc.git
synced 2026-06-21 03:15:38 +03:00
Prepare pac and hpa psset for size to grow by PAGE over GROUP*PAGE
For PAC, to avoid having too many bins, arena bins still have the same layout. This means some extra search is needed for a page-level request that is not aligned with the orginal size class: it should also search the heap before the current index since the previous heap might also be able to have some allocations satisfying it. The same changes apply to HPA's psset. This search relies on the enumeration of the heap because not all allocs in the previous heap are guaranteed to satisfy the request. To balance the memory and CPU overhead, we currently enumerate at most a fixed number of nodes before concluding none can satisfy the request during an enumeration.
This commit is contained in:
parent
205ba7b223
commit
bffe921ba0
6 changed files with 298 additions and 12 deletions
|
|
@ -21,6 +21,14 @@
|
|||
*/
|
||||
#define EDATA_ALIGNMENT 128
|
||||
|
||||
/*
|
||||
* Defines how many nodes visited when enumerating the heap to search for
|
||||
* qualifed extents. More nodes visited may result in better choices at
|
||||
* the cost of longer search time. This size should not exceed 2^16 - 1
|
||||
* because we use uint16_t for accessing the queue needed for enumeration.
|
||||
*/
|
||||
#define ESET_ENUMERATE_MAX_NUM 32
|
||||
|
||||
enum extent_state_e {
|
||||
extent_state_active = 0,
|
||||
extent_state_dirty = 1,
|
||||
|
|
@ -89,8 +97,8 @@ struct edata_cmp_summary_s {
|
|||
|
||||
/* Extent (span of pages). Use accessor functions for e_* fields. */
|
||||
typedef struct edata_s edata_t;
|
||||
ph_structs(edata_avail, edata_t);
|
||||
ph_structs(edata_heap, edata_t);
|
||||
ph_structs(edata_avail, edata_t, ESET_ENUMERATE_MAX_NUM);
|
||||
ph_structs(edata_heap, edata_t, ESET_ENUMERATE_MAX_NUM);
|
||||
struct edata_s {
|
||||
/*
|
||||
* Bitfield containing several fields:
|
||||
|
|
|
|||
|
|
@ -20,8 +20,14 @@
|
|||
* an observable property of any given region of address space). It's just
|
||||
* hugepage-sized and hugepage-aligned; it's *potentially* huge.
|
||||
*/
|
||||
|
||||
/*
|
||||
* The max enumeration num should not exceed 2^16 - 1, see comments in edata.h
|
||||
* for ESET_ENUMERATE_MAX_NUM for more details.
|
||||
*/
|
||||
#define PSSET_ENUMERATE_MAX_NUM 32
|
||||
typedef struct hpdata_s hpdata_t;
|
||||
ph_structs(hpdata_age_heap, hpdata_t);
|
||||
ph_structs(hpdata_age_heap, hpdata_t, PSSET_ENUMERATE_MAX_NUM);
|
||||
struct hpdata_s {
|
||||
/*
|
||||
* We likewise follow the edata convention of mangling names and forcing
|
||||
|
|
|
|||
|
|
@ -75,6 +75,16 @@ struct ph_s {
|
|||
size_t auxcount;
|
||||
};
|
||||
|
||||
typedef struct ph_enumerate_vars_s ph_enumerate_vars_t;
|
||||
struct ph_enumerate_vars_s {
|
||||
uint16_t front;
|
||||
uint16_t rear;
|
||||
uint16_t queue_size;
|
||||
uint16_t visited_num;
|
||||
uint16_t max_visit_num;
|
||||
uint16_t max_queue_size;
|
||||
};
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE phn_link_t *
|
||||
phn_link_get(void *phn, size_t offset) {
|
||||
return (phn_link_t *)(((char *)phn) + offset);
|
||||
|
|
@ -414,14 +424,98 @@ ph_remove(ph_t *ph, void *phn, size_t offset, ph_cmp_t cmp) {
|
|||
}
|
||||
}
|
||||
|
||||
#define ph_structs(a_prefix, a_type) \
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
ph_enumerate_vars_init(ph_enumerate_vars_t *vars, uint16_t max_visit_num,
|
||||
uint16_t max_queue_size) {
|
||||
vars->queue_size = 0;
|
||||
vars->visited_num = 0;
|
||||
vars->front = 0;
|
||||
vars->rear = 0;
|
||||
vars->max_visit_num = max_visit_num;
|
||||
vars->max_queue_size = max_queue_size;
|
||||
assert(vars->max_visit_num > 0);
|
||||
/*
|
||||
* max_queue_size must be able to support max_visit_num, which means
|
||||
* the queue will not overflow before reaching max_visit_num.
|
||||
*/
|
||||
assert(vars->max_queue_size >= (vars->max_visit_num + 1)/2);
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
ph_enumerate_queue_push(void *phn, void **bfs_queue,
|
||||
ph_enumerate_vars_t *vars) {
|
||||
assert(vars->queue_size < vars->max_queue_size);
|
||||
bfs_queue[vars->rear] = phn;
|
||||
vars->rear = (vars->rear + 1) % vars->max_queue_size;
|
||||
(vars->queue_size) ++;
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void *
|
||||
ph_enumerate_queue_pop(void **bfs_queue, ph_enumerate_vars_t *vars) {
|
||||
assert(vars->queue_size > 0);
|
||||
assert(vars->queue_size <= vars->max_queue_size);
|
||||
void *ret = bfs_queue[vars->front];
|
||||
vars->front = (vars->front + 1) % vars->max_queue_size;
|
||||
(vars->queue_size) --;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The two functions below offer a solution to enumerate the pairing heap.
|
||||
* Whe enumerating, always call ph_enumerate_prepare first to prepare the queue
|
||||
* needed for BFS. Next, call ph_enumerate_next to get the next element in
|
||||
* the enumeration. When enumeration ends, ph_enumerate_next returns NULL and
|
||||
* should not be called again. Enumeration ends when all elements in the heap
|
||||
* has been enumerated or the number of visited elements exceed
|
||||
* max_visit_num.
|
||||
*/
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
ph_enumerate_prepare(ph_t *ph, void **bfs_queue, ph_enumerate_vars_t *vars,
|
||||
uint16_t max_visit_num, uint16_t max_queue_size) {
|
||||
ph_enumerate_vars_init(vars, max_visit_num, max_queue_size);
|
||||
ph_enumerate_queue_push(ph->root, bfs_queue, vars);
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void *
|
||||
ph_enumerate_next(ph_t *ph, size_t offset, void **bfs_queue,
|
||||
ph_enumerate_vars_t *vars) {
|
||||
if (vars->queue_size == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
(vars->visited_num) ++;
|
||||
if (vars->visited_num > vars->max_visit_num) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *ret = ph_enumerate_queue_pop(bfs_queue, vars);
|
||||
assert(ret != NULL);
|
||||
void *left = phn_lchild_get(ret, offset);
|
||||
void *right = phn_next_get(ret, offset);
|
||||
if (left) {
|
||||
ph_enumerate_queue_push(left, bfs_queue, vars);
|
||||
}
|
||||
if (right) {
|
||||
ph_enumerate_queue_push(right, bfs_queue, vars);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define ph_structs(a_prefix, a_type, a_max_queue_size) \
|
||||
typedef struct { \
|
||||
phn_link_t link; \
|
||||
} a_prefix##_link_t; \
|
||||
\
|
||||
typedef struct { \
|
||||
ph_t ph; \
|
||||
} a_prefix##_t;
|
||||
} a_prefix##_t; \
|
||||
\
|
||||
typedef struct { \
|
||||
void *bfs_queue[a_max_queue_size]; \
|
||||
ph_enumerate_vars_t vars; \
|
||||
} a_prefix##_enumerate_helper_t;
|
||||
|
||||
|
||||
/*
|
||||
* The ph_proto() macro generates function prototypes that correspond to the
|
||||
|
|
@ -436,7 +530,12 @@ a_attr a_type *a_prefix##_any(a_prefix##_t *ph); \
|
|||
a_attr void a_prefix##_insert(a_prefix##_t *ph, a_type *phn); \
|
||||
a_attr a_type *a_prefix##_remove_first(a_prefix##_t *ph); \
|
||||
a_attr void a_prefix##_remove(a_prefix##_t *ph, a_type *phn); \
|
||||
a_attr a_type *a_prefix##_remove_any(a_prefix##_t *ph);
|
||||
a_attr a_type *a_prefix##_remove_any(a_prefix##_t *ph); \
|
||||
a_attr void a_prefix##_enumerate_prepare(a_prefix##_t *ph, \
|
||||
a_prefix##_enumerate_helper_t *helper, uint16_t max_visit_num, \
|
||||
uint16_t max_queue_size); \
|
||||
a_attr a_type *a_prefix##_enumerate_next(a_prefix##_t *ph, \
|
||||
a_prefix##_enumerate_helper_t *helper);
|
||||
|
||||
/* The ph_gen() macro generates a type-specific pairing heap implementation. */
|
||||
#define ph_gen(a_attr, a_prefix, a_type, a_field, a_cmp) \
|
||||
|
|
@ -491,6 +590,21 @@ a_prefix##_remove_any(a_prefix##_t *ph) { \
|
|||
a_prefix##_remove(ph, ret); \
|
||||
} \
|
||||
return ret; \
|
||||
} \
|
||||
\
|
||||
a_attr void \
|
||||
a_prefix##_enumerate_prepare(a_prefix##_t *ph, \
|
||||
a_prefix##_enumerate_helper_t *helper, uint16_t max_visit_num, \
|
||||
uint16_t max_queue_size) { \
|
||||
ph_enumerate_prepare(&ph->ph, helper->bfs_queue, &helper->vars, \
|
||||
max_visit_num, max_queue_size); \
|
||||
} \
|
||||
\
|
||||
a_attr a_type * \
|
||||
a_prefix##_enumerate_next(a_prefix##_t *ph, \
|
||||
a_prefix##_enumerate_helper_t *helper) { \
|
||||
return ph_enumerate_next(&ph->ph, offsetof(a_type, a_field), \
|
||||
helper->bfs_queue, &helper->vars); \
|
||||
}
|
||||
|
||||
#endif /* JEMALLOC_INTERNAL_PH_H */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue