5c77af98b1
Add extent serial numbers and use them where appropriate as a sort key that is higher priority than address, so that the allocation policy prefers older extents. This resolves #147.
271 lines
6.6 KiB
C
271 lines
6.6 KiB
C
/******************************************************************************/
|
|
#ifdef JEMALLOC_H_TYPES
|
|
|
|
typedef struct extent_node_s extent_node_t;
|
|
|
|
#endif /* JEMALLOC_H_TYPES */
|
|
/******************************************************************************/
|
|
#ifdef JEMALLOC_H_STRUCTS
|
|
|
|
/* Tree of extents. Use accessor functions for en_* fields. */
|
|
struct extent_node_s {
|
|
/* Arena from which this extent came, if any. */
|
|
arena_t *en_arena;
|
|
|
|
/* Pointer to the extent that this tree node is responsible for. */
|
|
void *en_addr;
|
|
|
|
/* Total region size. */
|
|
size_t en_size;
|
|
|
|
/*
|
|
* Serial number (potentially non-unique).
|
|
*
|
|
* In principle serial numbers can wrap around on 32-bit systems if
|
|
* JEMALLOC_MUNMAP is defined, but as long as comparison functions fall
|
|
* back on address comparison for equal serial numbers, stable (if
|
|
* imperfect) ordering is maintained.
|
|
*
|
|
* Serial numbers may not be unique even in the absence of wrap-around,
|
|
* e.g. when splitting an extent and assigning the same serial number to
|
|
* both resulting adjacent extents.
|
|
*/
|
|
size_t en_sn;
|
|
|
|
/*
|
|
* The zeroed flag is used by chunk recycling code to track whether
|
|
* memory is zero-filled.
|
|
*/
|
|
bool en_zeroed;
|
|
|
|
/*
|
|
* True if physical memory is committed to the extent, whether
|
|
* explicitly or implicitly as on a system that overcommits and
|
|
* satisfies physical memory needs on demand via soft page faults.
|
|
*/
|
|
bool en_committed;
|
|
|
|
/*
|
|
* The achunk flag is used to validate that huge allocation lookups
|
|
* don't return arena chunks.
|
|
*/
|
|
bool en_achunk;
|
|
|
|
/* Profile counters, used for huge objects. */
|
|
prof_tctx_t *en_prof_tctx;
|
|
|
|
/* Linkage for arena's runs_dirty and chunks_cache rings. */
|
|
arena_runs_dirty_link_t rd;
|
|
qr(extent_node_t) cc_link;
|
|
|
|
union {
|
|
/* Linkage for the size/sn/address-ordered tree. */
|
|
rb_node(extent_node_t) szsnad_link;
|
|
|
|
/* Linkage for arena's achunks, huge, and node_cache lists. */
|
|
ql_elm(extent_node_t) ql_link;
|
|
};
|
|
|
|
/* Linkage for the address-ordered tree. */
|
|
rb_node(extent_node_t) ad_link;
|
|
};
|
|
typedef rb_tree(extent_node_t) extent_tree_t;
|
|
|
|
#endif /* JEMALLOC_H_STRUCTS */
|
|
/******************************************************************************/
|
|
#ifdef JEMALLOC_H_EXTERNS
|
|
|
|
rb_proto(, extent_tree_szsnad_, extent_tree_t, extent_node_t)
|
|
|
|
rb_proto(, extent_tree_ad_, extent_tree_t, extent_node_t)
|
|
|
|
#endif /* JEMALLOC_H_EXTERNS */
|
|
/******************************************************************************/
|
|
#ifdef JEMALLOC_H_INLINES
|
|
|
|
#ifndef JEMALLOC_ENABLE_INLINE
|
|
arena_t *extent_node_arena_get(const extent_node_t *node);
|
|
void *extent_node_addr_get(const extent_node_t *node);
|
|
size_t extent_node_size_get(const extent_node_t *node);
|
|
size_t extent_node_sn_get(const extent_node_t *node);
|
|
bool extent_node_zeroed_get(const extent_node_t *node);
|
|
bool extent_node_committed_get(const extent_node_t *node);
|
|
bool extent_node_achunk_get(const extent_node_t *node);
|
|
prof_tctx_t *extent_node_prof_tctx_get(const extent_node_t *node);
|
|
void extent_node_arena_set(extent_node_t *node, arena_t *arena);
|
|
void extent_node_addr_set(extent_node_t *node, void *addr);
|
|
void extent_node_size_set(extent_node_t *node, size_t size);
|
|
void extent_node_sn_set(extent_node_t *node, size_t sn);
|
|
void extent_node_zeroed_set(extent_node_t *node, bool zeroed);
|
|
void extent_node_committed_set(extent_node_t *node, bool committed);
|
|
void extent_node_achunk_set(extent_node_t *node, bool achunk);
|
|
void extent_node_prof_tctx_set(extent_node_t *node, prof_tctx_t *tctx);
|
|
void extent_node_init(extent_node_t *node, arena_t *arena, void *addr,
|
|
size_t size, size_t sn, bool zeroed, bool committed);
|
|
void extent_node_dirty_linkage_init(extent_node_t *node);
|
|
void extent_node_dirty_insert(extent_node_t *node,
|
|
arena_runs_dirty_link_t *runs_dirty, extent_node_t *chunks_dirty);
|
|
void extent_node_dirty_remove(extent_node_t *node);
|
|
#endif
|
|
|
|
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_EXTENT_C_))
|
|
JEMALLOC_INLINE arena_t *
|
|
extent_node_arena_get(const extent_node_t *node)
|
|
{
|
|
|
|
return (node->en_arena);
|
|
}
|
|
|
|
JEMALLOC_INLINE void *
|
|
extent_node_addr_get(const extent_node_t *node)
|
|
{
|
|
|
|
return (node->en_addr);
|
|
}
|
|
|
|
JEMALLOC_INLINE size_t
|
|
extent_node_size_get(const extent_node_t *node)
|
|
{
|
|
|
|
return (node->en_size);
|
|
}
|
|
|
|
JEMALLOC_INLINE size_t
|
|
extent_node_sn_get(const extent_node_t *node)
|
|
{
|
|
|
|
return (node->en_sn);
|
|
}
|
|
|
|
JEMALLOC_INLINE bool
|
|
extent_node_zeroed_get(const extent_node_t *node)
|
|
{
|
|
|
|
return (node->en_zeroed);
|
|
}
|
|
|
|
JEMALLOC_INLINE bool
|
|
extent_node_committed_get(const extent_node_t *node)
|
|
{
|
|
|
|
assert(!node->en_achunk);
|
|
return (node->en_committed);
|
|
}
|
|
|
|
JEMALLOC_INLINE bool
|
|
extent_node_achunk_get(const extent_node_t *node)
|
|
{
|
|
|
|
return (node->en_achunk);
|
|
}
|
|
|
|
JEMALLOC_INLINE prof_tctx_t *
|
|
extent_node_prof_tctx_get(const extent_node_t *node)
|
|
{
|
|
|
|
return (node->en_prof_tctx);
|
|
}
|
|
|
|
JEMALLOC_INLINE void
|
|
extent_node_arena_set(extent_node_t *node, arena_t *arena)
|
|
{
|
|
|
|
node->en_arena = arena;
|
|
}
|
|
|
|
JEMALLOC_INLINE void
|
|
extent_node_addr_set(extent_node_t *node, void *addr)
|
|
{
|
|
|
|
node->en_addr = addr;
|
|
}
|
|
|
|
JEMALLOC_INLINE void
|
|
extent_node_size_set(extent_node_t *node, size_t size)
|
|
{
|
|
|
|
node->en_size = size;
|
|
}
|
|
|
|
JEMALLOC_INLINE void
|
|
extent_node_sn_set(extent_node_t *node, size_t sn)
|
|
{
|
|
|
|
node->en_sn = sn;
|
|
}
|
|
|
|
JEMALLOC_INLINE void
|
|
extent_node_zeroed_set(extent_node_t *node, bool zeroed)
|
|
{
|
|
|
|
node->en_zeroed = zeroed;
|
|
}
|
|
|
|
JEMALLOC_INLINE void
|
|
extent_node_committed_set(extent_node_t *node, bool committed)
|
|
{
|
|
|
|
node->en_committed = committed;
|
|
}
|
|
|
|
JEMALLOC_INLINE void
|
|
extent_node_achunk_set(extent_node_t *node, bool achunk)
|
|
{
|
|
|
|
node->en_achunk = achunk;
|
|
}
|
|
|
|
JEMALLOC_INLINE void
|
|
extent_node_prof_tctx_set(extent_node_t *node, prof_tctx_t *tctx)
|
|
{
|
|
|
|
node->en_prof_tctx = tctx;
|
|
}
|
|
|
|
JEMALLOC_INLINE void
|
|
extent_node_init(extent_node_t *node, arena_t *arena, void *addr, size_t size,
|
|
size_t sn, bool zeroed, bool committed)
|
|
{
|
|
|
|
extent_node_arena_set(node, arena);
|
|
extent_node_addr_set(node, addr);
|
|
extent_node_size_set(node, size);
|
|
extent_node_sn_set(node, sn);
|
|
extent_node_zeroed_set(node, zeroed);
|
|
extent_node_committed_set(node, committed);
|
|
extent_node_achunk_set(node, false);
|
|
if (config_prof)
|
|
extent_node_prof_tctx_set(node, NULL);
|
|
}
|
|
|
|
JEMALLOC_INLINE void
|
|
extent_node_dirty_linkage_init(extent_node_t *node)
|
|
{
|
|
|
|
qr_new(&node->rd, rd_link);
|
|
qr_new(node, cc_link);
|
|
}
|
|
|
|
JEMALLOC_INLINE void
|
|
extent_node_dirty_insert(extent_node_t *node,
|
|
arena_runs_dirty_link_t *runs_dirty, extent_node_t *chunks_dirty)
|
|
{
|
|
|
|
qr_meld(runs_dirty, &node->rd, rd_link);
|
|
qr_meld(chunks_dirty, node, cc_link);
|
|
}
|
|
|
|
JEMALLOC_INLINE void
|
|
extent_node_dirty_remove(extent_node_t *node)
|
|
{
|
|
|
|
qr_remove(&node->rd, rd_link);
|
|
qr_remove(node, cc_link);
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif /* JEMALLOC_H_INLINES */
|
|
/******************************************************************************/
|
|
|