Implement per arena base allocators.
Add/rename related mallctls: - Add stats.arenas.<i>.base . - Rename stats.arenas.<i>.metadata to stats.arenas.<i>.internal . - Add stats.arenas.<i>.resident . Modify the arenas.extend mallctl to take an optional (extent_hooks_t *) argument so that it is possible for all base allocations to be serviced by the specified extent hooks. This resolves #463.
This commit is contained in:
@@ -143,9 +143,6 @@ struct arena_bin_s {
|
||||
};
|
||||
|
||||
struct arena_s {
|
||||
/* This arena's index within the arenas array. */
|
||||
unsigned ind;
|
||||
|
||||
/*
|
||||
* Number of threads currently assigned to this arena, synchronized via
|
||||
* atomic operations. Each thread has two distinct assignments, one for
|
||||
@@ -226,12 +223,6 @@ struct arena_s {
|
||||
/* Protects extents_{cached,retained,dirty}. */
|
||||
malloc_mutex_t extents_mtx;
|
||||
|
||||
/* User-configurable extent hook functions. */
|
||||
union {
|
||||
extent_hooks_t *extent_hooks;
|
||||
void *extent_hooks_pun;
|
||||
};
|
||||
|
||||
/*
|
||||
* Next extent size class in a growing series to use when satisfying a
|
||||
* request via the extent hooks (only if !config_munmap). This limits
|
||||
@@ -247,6 +238,9 @@ struct arena_s {
|
||||
|
||||
/* bins is used to store heaps of free regions. */
|
||||
arena_bin_t bins[NBINS];
|
||||
|
||||
/* Base allocator, from which arena metadata are allocated. */
|
||||
base_t *base;
|
||||
};
|
||||
|
||||
/* Used in conjunction with tsd for fast arena-related context lookup. */
|
||||
@@ -337,7 +331,7 @@ unsigned arena_nthreads_get(arena_t *arena, bool internal);
|
||||
void arena_nthreads_inc(arena_t *arena, bool internal);
|
||||
void arena_nthreads_dec(arena_t *arena, bool internal);
|
||||
size_t arena_extent_sn_next(arena_t *arena);
|
||||
arena_t *arena_new(tsdn_t *tsdn, unsigned ind);
|
||||
arena_t *arena_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks);
|
||||
void arena_boot(void);
|
||||
void arena_prefork0(tsdn_t *tsdn, arena_t *arena);
|
||||
void arena_prefork1(tsdn_t *tsdn, arena_t *arena);
|
||||
@@ -351,9 +345,10 @@ void arena_postfork_child(tsdn_t *tsdn, arena_t *arena);
|
||||
#ifdef JEMALLOC_H_INLINES
|
||||
|
||||
#ifndef JEMALLOC_ENABLE_INLINE
|
||||
void arena_metadata_add(arena_t *arena, size_t size);
|
||||
void arena_metadata_sub(arena_t *arena, size_t size);
|
||||
size_t arena_metadata_get(arena_t *arena);
|
||||
unsigned arena_ind_get(const arena_t *arena);
|
||||
void arena_internal_add(arena_t *arena, size_t size);
|
||||
void arena_internal_sub(arena_t *arena, size_t size);
|
||||
size_t arena_internal_get(arena_t *arena);
|
||||
bool arena_prof_accum_impl(arena_t *arena, uint64_t accumbytes);
|
||||
bool arena_prof_accum_locked(arena_t *arena, uint64_t accumbytes);
|
||||
bool arena_prof_accum(tsdn_t *tsdn, arena_t *arena, uint64_t accumbytes);
|
||||
@@ -378,25 +373,32 @@ void arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size,
|
||||
|
||||
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_ARENA_C_))
|
||||
# ifdef JEMALLOC_ARENA_INLINE_A
|
||||
JEMALLOC_INLINE void
|
||||
arena_metadata_add(arena_t *arena, size_t size)
|
||||
JEMALLOC_INLINE unsigned
|
||||
arena_ind_get(const arena_t *arena)
|
||||
{
|
||||
|
||||
atomic_add_zu(&arena->stats.metadata, size);
|
||||
return (base_ind_get(arena->base));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
arena_metadata_sub(arena_t *arena, size_t size)
|
||||
arena_internal_add(arena_t *arena, size_t size)
|
||||
{
|
||||
|
||||
atomic_sub_zu(&arena->stats.metadata, size);
|
||||
atomic_add_zu(&arena->stats.internal, size);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE void
|
||||
arena_internal_sub(arena_t *arena, size_t size)
|
||||
{
|
||||
|
||||
atomic_sub_zu(&arena->stats.internal, size);
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE size_t
|
||||
arena_metadata_get(arena_t *arena)
|
||||
arena_internal_get(arena_t *arena)
|
||||
{
|
||||
|
||||
return (atomic_read_zu(&arena->stats.metadata));
|
||||
return (atomic_read_zu(&arena->stats.internal));
|
||||
}
|
||||
|
||||
JEMALLOC_INLINE bool
|
||||
@@ -499,7 +501,7 @@ arena_decay_ticks(tsdn_t *tsdn, arena_t *arena, unsigned nticks)
|
||||
if (unlikely(tsdn_null(tsdn)))
|
||||
return;
|
||||
tsd = tsdn_tsd(tsdn);
|
||||
decay_ticker = decay_ticker_get(tsd, arena->ind);
|
||||
decay_ticker = decay_ticker_get(tsd, arena_ind_get(arena));
|
||||
if (unlikely(decay_ticker == NULL))
|
||||
return;
|
||||
if (unlikely(ticker_ticks(decay_ticker, nticks)))
|
||||
|
@@ -1,25 +1,87 @@
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_TYPES
|
||||
|
||||
typedef struct base_block_s base_block_t;
|
||||
typedef struct base_s base_t;
|
||||
|
||||
#endif /* JEMALLOC_H_TYPES */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_STRUCTS
|
||||
|
||||
/* Embedded at the beginning of every block of base-managed virtual memory. */
|
||||
struct base_block_s {
|
||||
/* Total size of block's virtual memory mapping. */
|
||||
size_t size;
|
||||
|
||||
/* Next block in list of base's blocks. */
|
||||
base_block_t *next;
|
||||
|
||||
/* Tracks unused trailing space. */
|
||||
extent_t extent;
|
||||
};
|
||||
|
||||
struct base_s {
|
||||
/* Associated arena's index within the arenas array. */
|
||||
unsigned ind;
|
||||
|
||||
/* User-configurable extent hook functions. */
|
||||
union {
|
||||
extent_hooks_t *extent_hooks;
|
||||
void *extent_hooks_pun;
|
||||
};
|
||||
|
||||
/* Protects base_alloc() and base_stats_get() operations. */
|
||||
malloc_mutex_t mtx;
|
||||
|
||||
/* Serial number generation state. */
|
||||
size_t extent_sn_next;
|
||||
|
||||
/* Chain of all blocks associated with base. */
|
||||
base_block_t *blocks;
|
||||
|
||||
/* Heap of extents that track unused trailing space within blocks. */
|
||||
extent_heap_t avail[NSIZES];
|
||||
|
||||
/* Stats, only maintained if config_stats. */
|
||||
size_t allocated;
|
||||
size_t resident;
|
||||
size_t mapped;
|
||||
};
|
||||
|
||||
#endif /* JEMALLOC_H_STRUCTS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_EXTERNS
|
||||
|
||||
void *base_alloc(tsdn_t *tsdn, size_t size);
|
||||
void base_stats_get(tsdn_t *tsdn, size_t *allocated, size_t *resident,
|
||||
size_t *mapped);
|
||||
bool base_boot(void);
|
||||
void base_prefork(tsdn_t *tsdn);
|
||||
void base_postfork_parent(tsdn_t *tsdn);
|
||||
void base_postfork_child(tsdn_t *tsdn);
|
||||
base_t *b0get(void);
|
||||
base_t *base_new(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks);
|
||||
void base_delete(base_t *base);
|
||||
extent_hooks_t *base_extent_hooks_get(base_t *base);
|
||||
extent_hooks_t *base_extent_hooks_set(base_t *base,
|
||||
extent_hooks_t *extent_hooks);
|
||||
void *base_alloc(tsdn_t *tsdn, base_t *base, size_t size, size_t alignment);
|
||||
void base_stats_get(tsdn_t *tsdn, base_t *base, size_t *allocated,
|
||||
size_t *resident, size_t *mapped);
|
||||
void base_prefork(tsdn_t *tsdn, base_t *base);
|
||||
void base_postfork_parent(tsdn_t *tsdn, base_t *base);
|
||||
void base_postfork_child(tsdn_t *tsdn, base_t *base);
|
||||
bool base_boot(tsdn_t *tsdn);
|
||||
|
||||
#endif /* JEMALLOC_H_EXTERNS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_INLINES
|
||||
|
||||
#ifndef JEMALLOC_ENABLE_INLINE
|
||||
unsigned base_ind_get(const base_t *base);
|
||||
#endif
|
||||
|
||||
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_BASE_C_))
|
||||
JEMALLOC_INLINE unsigned
|
||||
base_ind_get(const base_t *base)
|
||||
{
|
||||
|
||||
return (base->ind);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* JEMALLOC_H_INLINES */
|
||||
/******************************************************************************/
|
||||
|
@@ -370,9 +370,9 @@ typedef unsigned szind_t;
|
||||
#include "jemalloc/internal/tsd.h"
|
||||
#include "jemalloc/internal/mb.h"
|
||||
#include "jemalloc/internal/extent.h"
|
||||
#include "jemalloc/internal/base.h"
|
||||
#include "jemalloc/internal/arena.h"
|
||||
#include "jemalloc/internal/bitmap.h"
|
||||
#include "jemalloc/internal/base.h"
|
||||
#include "jemalloc/internal/rtree.h"
|
||||
#include "jemalloc/internal/pages.h"
|
||||
#include "jemalloc/internal/large.h"
|
||||
@@ -403,10 +403,10 @@ typedef unsigned szind_t;
|
||||
#include "jemalloc/internal/arena.h"
|
||||
#undef JEMALLOC_ARENA_STRUCTS_A
|
||||
#include "jemalloc/internal/extent.h"
|
||||
#include "jemalloc/internal/base.h"
|
||||
#define JEMALLOC_ARENA_STRUCTS_B
|
||||
#include "jemalloc/internal/arena.h"
|
||||
#undef JEMALLOC_ARENA_STRUCTS_B
|
||||
#include "jemalloc/internal/base.h"
|
||||
#include "jemalloc/internal/rtree.h"
|
||||
#include "jemalloc/internal/pages.h"
|
||||
#include "jemalloc/internal/large.h"
|
||||
@@ -464,7 +464,7 @@ void *bootstrap_malloc(size_t size);
|
||||
void *bootstrap_calloc(size_t num, size_t size);
|
||||
void bootstrap_free(void *ptr);
|
||||
unsigned narenas_total_get(void);
|
||||
arena_t *arena_init(tsdn_t *tsdn, unsigned ind);
|
||||
arena_t *arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks);
|
||||
arena_tdata_t *arena_tdata_get_hard(tsd_t *tsd, unsigned ind);
|
||||
arena_t *arena_choose_hard(tsd_t *tsd, bool internal);
|
||||
void arena_migrate(tsd_t *tsd, unsigned oldind, unsigned newind);
|
||||
@@ -491,8 +491,8 @@ void jemalloc_postfork_child(void);
|
||||
#include "jemalloc/internal/mb.h"
|
||||
#include "jemalloc/internal/bitmap.h"
|
||||
#include "jemalloc/internal/extent.h"
|
||||
#include "jemalloc/internal/arena.h"
|
||||
#include "jemalloc/internal/base.h"
|
||||
#include "jemalloc/internal/arena.h"
|
||||
#include "jemalloc/internal/rtree.h"
|
||||
#include "jemalloc/internal/pages.h"
|
||||
#include "jemalloc/internal/large.h"
|
||||
@@ -900,8 +900,10 @@ arena_get(tsdn_t *tsdn, unsigned ind, bool init_if_missing)
|
||||
ret = arenas[ind];
|
||||
if (unlikely(ret == NULL)) {
|
||||
ret = (arena_t *)atomic_read_p((void **)&arenas[ind]);
|
||||
if (init_if_missing && unlikely(ret == NULL))
|
||||
ret = arena_init(tsdn, ind);
|
||||
if (init_if_missing && unlikely(ret == NULL)) {
|
||||
ret = arena_init(tsdn, ind,
|
||||
(extent_hooks_t *)&extent_hooks_default);
|
||||
}
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
@@ -950,17 +952,17 @@ iealloc(tsdn_t *tsdn, const void *ptr)
|
||||
arena_t *iaalloc(tsdn_t *tsdn, const void *ptr);
|
||||
size_t isalloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr);
|
||||
void *iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero,
|
||||
tcache_t *tcache, bool is_metadata, arena_t *arena, bool slow_path);
|
||||
tcache_t *tcache, bool is_internal, arena_t *arena, bool slow_path);
|
||||
void *ialloc(tsd_t *tsd, size_t size, szind_t ind, bool zero,
|
||||
bool slow_path);
|
||||
void *ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero,
|
||||
tcache_t *tcache, bool is_metadata, arena_t *arena);
|
||||
tcache_t *tcache, bool is_internal, arena_t *arena);
|
||||
void *ipalloct(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero,
|
||||
tcache_t *tcache, arena_t *arena);
|
||||
void *ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero);
|
||||
size_t ivsalloc(tsdn_t *tsdn, const void *ptr);
|
||||
void idalloctm(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache,
|
||||
bool is_metadata, bool slow_path);
|
||||
bool is_internal, bool slow_path);
|
||||
void idalloc(tsd_t *tsd, extent_t *extent, void *ptr);
|
||||
void isdalloct(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size,
|
||||
tcache_t *tcache, bool slow_path);
|
||||
@@ -1003,17 +1005,18 @@ isalloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr)
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void *
|
||||
iallocztm(tsdn_t *tsdn, size_t size, szind_t ind, bool zero, tcache_t *tcache,
|
||||
bool is_metadata, arena_t *arena, bool slow_path)
|
||||
bool is_internal, arena_t *arena, bool slow_path)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
assert(size != 0);
|
||||
assert(!is_metadata || tcache == NULL);
|
||||
assert(!is_metadata || arena == NULL || arena->ind < narenas_auto);
|
||||
assert(!is_internal || tcache == NULL);
|
||||
assert(!is_internal || arena == NULL || arena_ind_get(arena) <
|
||||
narenas_auto);
|
||||
|
||||
ret = arena_malloc(tsdn, arena, size, ind, zero, tcache, slow_path);
|
||||
if (config_stats && is_metadata && likely(ret != NULL)) {
|
||||
arena_metadata_add(iaalloc(tsdn, ret), isalloc(tsdn,
|
||||
if (config_stats && is_internal && likely(ret != NULL)) {
|
||||
arena_internal_add(iaalloc(tsdn, ret), isalloc(tsdn,
|
||||
iealloc(tsdn, ret), ret));
|
||||
}
|
||||
return (ret);
|
||||
@@ -1029,19 +1032,20 @@ ialloc(tsd_t *tsd, size_t size, szind_t ind, bool zero, bool slow_path)
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void *
|
||||
ipallocztm(tsdn_t *tsdn, size_t usize, size_t alignment, bool zero,
|
||||
tcache_t *tcache, bool is_metadata, arena_t *arena)
|
||||
tcache_t *tcache, bool is_internal, arena_t *arena)
|
||||
{
|
||||
void *ret;
|
||||
|
||||
assert(usize != 0);
|
||||
assert(usize == sa2u(usize, alignment));
|
||||
assert(!is_metadata || tcache == NULL);
|
||||
assert(!is_metadata || arena == NULL || arena->ind < narenas_auto);
|
||||
assert(!is_internal || tcache == NULL);
|
||||
assert(!is_internal || arena == NULL || arena_ind_get(arena) <
|
||||
narenas_auto);
|
||||
|
||||
ret = arena_palloc(tsdn, arena, usize, alignment, zero, tcache);
|
||||
assert(ALIGNMENT_ADDR2BASE(ret, alignment) == ret);
|
||||
if (config_stats && is_metadata && likely(ret != NULL)) {
|
||||
arena_metadata_add(iaalloc(tsdn, ret), isalloc(tsdn,
|
||||
if (config_stats && is_internal && likely(ret != NULL)) {
|
||||
arena_internal_add(iaalloc(tsdn, ret), isalloc(tsdn,
|
||||
iealloc(tsdn, ret), ret));
|
||||
}
|
||||
return (ret);
|
||||
@@ -1088,14 +1092,15 @@ ivsalloc(tsdn_t *tsdn, const void *ptr)
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
idalloctm(tsdn_t *tsdn, extent_t *extent, void *ptr, tcache_t *tcache,
|
||||
bool is_metadata, bool slow_path)
|
||||
bool is_internal, bool slow_path)
|
||||
{
|
||||
|
||||
assert(ptr != NULL);
|
||||
assert(!is_metadata || tcache == NULL);
|
||||
assert(!is_metadata || iaalloc(tsdn, ptr)->ind < narenas_auto);
|
||||
if (config_stats && is_metadata) {
|
||||
arena_metadata_sub(iaalloc(tsdn, ptr), isalloc(tsdn, extent,
|
||||
assert(!is_internal || tcache == NULL);
|
||||
assert(!is_internal || arena_ind_get(iaalloc(tsdn, ptr)) <
|
||||
narenas_auto);
|
||||
if (config_stats && is_internal) {
|
||||
arena_internal_sub(iaalloc(tsdn, ptr), isalloc(tsdn, extent,
|
||||
ptr));
|
||||
}
|
||||
|
||||
|
@@ -34,13 +34,14 @@ arena_extent_ralloc_large_shrink
|
||||
arena_extent_sn_next
|
||||
arena_get
|
||||
arena_ichoose
|
||||
arena_ind_get
|
||||
arena_init
|
||||
arena_internal_add
|
||||
arena_internal_get
|
||||
arena_internal_sub
|
||||
arena_malloc
|
||||
arena_malloc_hard
|
||||
arena_maybe_purge
|
||||
arena_metadata_add
|
||||
arena_metadata_get
|
||||
arena_metadata_sub
|
||||
arena_migrate
|
||||
arena_new
|
||||
arena_nthreads_dec
|
||||
@@ -93,8 +94,14 @@ atomic_write_u
|
||||
atomic_write_u32
|
||||
atomic_write_u64
|
||||
atomic_write_zu
|
||||
b0get
|
||||
base_alloc
|
||||
base_boot
|
||||
base_delete
|
||||
base_extent_hooks_get
|
||||
base_extent_hooks_set
|
||||
base_ind_get
|
||||
base_new
|
||||
base_postfork_child
|
||||
base_postfork_parent
|
||||
base_prefork
|
||||
|
@@ -100,8 +100,9 @@ struct arena_stats_s {
|
||||
uint64_t nmadvise;
|
||||
uint64_t purged;
|
||||
|
||||
/* Number of bytes currently allocated for internal metadata. */
|
||||
size_t metadata; /* Protected via atomic_*_zu(). */
|
||||
size_t base;
|
||||
size_t internal; /* Protected via atomic_*_zu(). */
|
||||
size_t resident;
|
||||
|
||||
size_t allocated_large;
|
||||
uint64_t nmalloc_large;
|
||||
|
Reference in New Issue
Block a user