Incorporate szind/slab into rtree leaves.
Expand and restructure the rtree API such that all common operations can be achieved with minimal work, regardless of whether the rtree leaf fields are independent versus packed into a single atomic pointer.
This commit is contained in:
parent
944c8a3383
commit
99d68445ef
@ -15,6 +15,7 @@ void *arena_malloc(tsdn_t *tsdn, arena_t *arena, size_t size, szind_t ind,
|
|||||||
bool zero, tcache_t *tcache, bool slow_path);
|
bool zero, tcache_t *tcache, bool slow_path);
|
||||||
arena_t *arena_aalloc(tsdn_t *tsdn, const void *ptr);
|
arena_t *arena_aalloc(tsdn_t *tsdn, const void *ptr);
|
||||||
size_t arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr);
|
size_t arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr);
|
||||||
|
size_t arena_vsalloc(tsdn_t *tsdn, const void *ptr);
|
||||||
void arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr,
|
void arena_dalloc(tsdn_t *tsdn, extent_t *extent, void *ptr,
|
||||||
tcache_t *tcache, bool slow_path);
|
tcache_t *tcache, bool slow_path);
|
||||||
void arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size,
|
void arena_sdalloc(tsdn_t *tsdn, extent_t *extent, void *ptr, size_t size,
|
||||||
@ -114,12 +115,60 @@ arena_aalloc(tsdn_t *tsdn, const void *ptr) {
|
|||||||
return extent_arena_get(iealloc(tsdn, ptr));
|
return extent_arena_get(iealloc(tsdn, ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the size of the allocation pointed to by ptr. */
|
|
||||||
JEMALLOC_ALWAYS_INLINE size_t
|
JEMALLOC_ALWAYS_INLINE size_t
|
||||||
arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) {
|
arena_salloc(tsdn_t *tsdn, const extent_t *extent, const void *ptr) {
|
||||||
assert(ptr != NULL);
|
assert(ptr != NULL);
|
||||||
|
|
||||||
return index2size(extent_szind_get(extent));
|
rtree_ctx_t rtree_ctx_fallback;
|
||||||
|
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
|
||||||
|
|
||||||
|
szind_t szind = rtree_szind_read(tsdn, &extents_rtree, rtree_ctx,
|
||||||
|
(uintptr_t)ptr, true);
|
||||||
|
assert(szind != NSIZES);
|
||||||
|
|
||||||
|
if (config_debug && unlikely(extent != NULL)) {
|
||||||
|
rtree_leaf_elm_t elm;
|
||||||
|
rtree_leaf_elm_read(rtree_read(tsdn, &extents_rtree, rtree_ctx,
|
||||||
|
(uintptr_t)ptr, true), true, &elm);
|
||||||
|
|
||||||
|
assert(extent == rtree_leaf_elm_extent_get(&elm));
|
||||||
|
assert(szind == extent_szind_get(extent));
|
||||||
|
}
|
||||||
|
|
||||||
|
return index2size(szind);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_ALWAYS_INLINE size_t
|
||||||
|
arena_vsalloc(tsdn_t *tsdn, const void *ptr) {
|
||||||
|
/*
|
||||||
|
* Return 0 if ptr is not within an extent managed by jemalloc. This
|
||||||
|
* function has two extra costs relative to isalloc():
|
||||||
|
* - The rtree calls cannot claim to be dependent lookups, which induces
|
||||||
|
* rtree lookup load dependencies.
|
||||||
|
* - The lookup may fail, so there is an extra branch to check for
|
||||||
|
* failure.
|
||||||
|
*/
|
||||||
|
|
||||||
|
rtree_ctx_t rtree_ctx_fallback;
|
||||||
|
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
|
||||||
|
|
||||||
|
extent_t *extent;
|
||||||
|
szind_t szind;
|
||||||
|
if (rtree_extent_szind_read(tsdn, &extents_rtree, rtree_ctx,
|
||||||
|
(uintptr_t)ptr, false, &extent, &szind)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extent == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
assert(extent_state_get(extent) == extent_state_active);
|
||||||
|
/* Only slab members should be looked up via interior pointers. */
|
||||||
|
assert(extent_addr_get(extent) == ptr || extent_slab_get(extent));
|
||||||
|
|
||||||
|
assert(szind != NSIZES);
|
||||||
|
|
||||||
|
return index2size(szind);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
|
@ -54,7 +54,7 @@ bool extent_purge_forced_wrapper(tsdn_t *tsdn, arena_t *arena,
|
|||||||
size_t length);
|
size_t length);
|
||||||
extent_t *extent_split_wrapper(tsdn_t *tsdn, arena_t *arena,
|
extent_t *extent_split_wrapper(tsdn_t *tsdn, arena_t *arena,
|
||||||
extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a,
|
extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a,
|
||||||
szind_t szind_a, size_t size_b, szind_t szind_b);
|
szind_t szind_a, bool slab_a, size_t size_b, szind_t szind_b, bool slab_b);
|
||||||
bool extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena,
|
bool extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena,
|
||||||
extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b);
|
extent_hooks_t **r_extent_hooks, extent_t *a, extent_t *b);
|
||||||
|
|
||||||
|
@ -2,11 +2,11 @@
|
|||||||
#define JEMALLOC_INTERNAL_EXTENT_INLINES_H
|
#define JEMALLOC_INTERNAL_EXTENT_INLINES_H
|
||||||
|
|
||||||
#ifndef JEMALLOC_ENABLE_INLINE
|
#ifndef JEMALLOC_ENABLE_INLINE
|
||||||
extent_t *extent_lookup(tsdn_t *tsdn, const void *ptr, bool dependent);
|
|
||||||
arena_t *extent_arena_get(const extent_t *extent);
|
arena_t *extent_arena_get(const extent_t *extent);
|
||||||
void *extent_base_get(const extent_t *extent);
|
void *extent_base_get(const extent_t *extent);
|
||||||
void *extent_addr_get(const extent_t *extent);
|
void *extent_addr_get(const extent_t *extent);
|
||||||
size_t extent_size_get(const extent_t *extent);
|
size_t extent_size_get(const extent_t *extent);
|
||||||
|
szind_t extent_szind_get_maybe_invalid(const extent_t *extent);
|
||||||
szind_t extent_szind_get(const extent_t *extent);
|
szind_t extent_szind_get(const extent_t *extent);
|
||||||
size_t extent_usize_get(const extent_t *extent);
|
size_t extent_usize_get(const extent_t *extent);
|
||||||
void *extent_before_get(const extent_t *extent);
|
void *extent_before_get(const extent_t *extent);
|
||||||
@ -47,15 +47,6 @@ int extent_snad_comp(const extent_t *a, const extent_t *b);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_EXTENT_C_))
|
#if (defined(JEMALLOC_ENABLE_INLINE) || defined(JEMALLOC_EXTENT_C_))
|
||||||
JEMALLOC_INLINE extent_t *
|
|
||||||
extent_lookup(tsdn_t *tsdn, const void *ptr, bool dependent) {
|
|
||||||
rtree_ctx_t rtree_ctx_fallback;
|
|
||||||
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
|
|
||||||
|
|
||||||
return rtree_read(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr,
|
|
||||||
dependent);
|
|
||||||
}
|
|
||||||
|
|
||||||
JEMALLOC_INLINE arena_t *
|
JEMALLOC_INLINE arena_t *
|
||||||
extent_arena_get(const extent_t *extent) {
|
extent_arena_get(const extent_t *extent) {
|
||||||
return extent->e_arena;
|
return extent->e_arena;
|
||||||
@ -81,11 +72,18 @@ extent_size_get(const extent_t *extent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_INLINE szind_t
|
JEMALLOC_INLINE szind_t
|
||||||
extent_szind_get(const extent_t *extent) {
|
extent_szind_get_maybe_invalid(const extent_t *extent) {
|
||||||
assert(extent->e_szind < NSIZES); /* Never call when "invalid". */
|
assert(extent->e_szind <= NSIZES);
|
||||||
return extent->e_szind;
|
return extent->e_szind;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE szind_t
|
||||||
|
extent_szind_get(const extent_t *extent) {
|
||||||
|
szind_t szind = extent_szind_get_maybe_invalid(extent);
|
||||||
|
assert(szind < NSIZES); /* Never call when "invalid". */
|
||||||
|
return szind;
|
||||||
|
}
|
||||||
|
|
||||||
JEMALLOC_INLINE size_t
|
JEMALLOC_INLINE size_t
|
||||||
extent_usize_get(const extent_t *extent) {
|
extent_usize_get(const extent_t *extent) {
|
||||||
return index2size(extent_szind_get(extent));
|
return index2size(extent_szind_get(extent));
|
||||||
|
@ -535,7 +535,6 @@ void jemalloc_postfork_child(void);
|
|||||||
#include "jemalloc/internal/tsd_inlines.h"
|
#include "jemalloc/internal/tsd_inlines.h"
|
||||||
#include "jemalloc/internal/witness_inlines.h"
|
#include "jemalloc/internal/witness_inlines.h"
|
||||||
#include "jemalloc/internal/mutex_inlines.h"
|
#include "jemalloc/internal/mutex_inlines.h"
|
||||||
#include "jemalloc/internal/rtree_inlines.h"
|
|
||||||
|
|
||||||
#ifndef JEMALLOC_ENABLE_INLINE
|
#ifndef JEMALLOC_ENABLE_INLINE
|
||||||
pszind_t psz2ind(size_t psz);
|
pszind_t psz2ind(size_t psz);
|
||||||
@ -934,6 +933,7 @@ decay_ticker_get(tsd_t *tsd, unsigned ind) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "jemalloc/internal/extent_inlines.h"
|
#include "jemalloc/internal/extent_inlines.h"
|
||||||
|
#include "jemalloc/internal/rtree_inlines.h"
|
||||||
#include "jemalloc/internal/base_inlines.h"
|
#include "jemalloc/internal/base_inlines.h"
|
||||||
#include "jemalloc/internal/bitmap_inlines.h"
|
#include "jemalloc/internal/bitmap_inlines.h"
|
||||||
/*
|
/*
|
||||||
@ -994,7 +994,11 @@ arena_ichoose(tsd_t *tsd, arena_t *arena) {
|
|||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE extent_t *
|
JEMALLOC_ALWAYS_INLINE extent_t *
|
||||||
iealloc(tsdn_t *tsdn, const void *ptr) {
|
iealloc(tsdn_t *tsdn, const void *ptr) {
|
||||||
return extent_lookup(tsdn, ptr, true);
|
rtree_ctx_t rtree_ctx_fallback;
|
||||||
|
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
|
||||||
|
|
||||||
|
return rtree_extent_read(tsdn, &extents_rtree, rtree_ctx,
|
||||||
|
(uintptr_t)ptr, true);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1113,25 +1117,7 @@ ipalloc(tsd_t *tsd, size_t usize, size_t alignment, bool zero) {
|
|||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE size_t
|
JEMALLOC_ALWAYS_INLINE size_t
|
||||||
ivsalloc(tsdn_t *tsdn, const void *ptr) {
|
ivsalloc(tsdn_t *tsdn, const void *ptr) {
|
||||||
extent_t *extent;
|
return arena_vsalloc(tsdn, ptr);
|
||||||
|
|
||||||
/*
|
|
||||||
* Return 0 if ptr is not within an extent managed by jemalloc. This
|
|
||||||
* function has two extra costs relative to isalloc():
|
|
||||||
* - The extent_lookup() call cannot claim to be a dependent lookup,
|
|
||||||
* which induces rtree lookup load dependencies.
|
|
||||||
* - The lookup may fail, so there is an extra branch to check for
|
|
||||||
* failure.
|
|
||||||
* */
|
|
||||||
extent = extent_lookup(tsdn, ptr, false);
|
|
||||||
if (extent == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
assert(extent_state_get(extent) == extent_state_active);
|
|
||||||
/* Only slab members should be looked up via interior pointers. */
|
|
||||||
assert(extent_addr_get(extent) == ptr || extent_slab_get(extent));
|
|
||||||
|
|
||||||
return isalloc(tsdn, extent, ptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE void
|
JEMALLOC_ALWAYS_INLINE void
|
||||||
|
@ -14,8 +14,8 @@ extern large_dalloc_junk_t *large_dalloc_junk;
|
|||||||
typedef void (large_dalloc_maybe_junk_t)(void *, size_t);
|
typedef void (large_dalloc_maybe_junk_t)(void *, size_t);
|
||||||
extern large_dalloc_maybe_junk_t *large_dalloc_maybe_junk;
|
extern large_dalloc_maybe_junk_t *large_dalloc_maybe_junk;
|
||||||
#else
|
#else
|
||||||
void large_dalloc_junk(void *ptr, size_t usize);
|
void large_dalloc_junk(void *ptr, size_t size);
|
||||||
void large_dalloc_maybe_junk(void *ptr, size_t usize);
|
void large_dalloc_maybe_junk(void *ptr, size_t size);
|
||||||
#endif
|
#endif
|
||||||
void large_dalloc_prep_junked_locked(tsdn_t *tsdn, extent_t *extent);
|
void large_dalloc_prep_junked_locked(tsdn_t *tsdn, extent_t *extent);
|
||||||
void large_dalloc_finish(tsdn_t *tsdn, extent_t *extent);
|
void large_dalloc_finish(tsdn_t *tsdn, extent_t *extent);
|
||||||
|
@ -77,6 +77,7 @@ arena_stats_merge
|
|||||||
arena_tcache_fill_small
|
arena_tcache_fill_small
|
||||||
arena_tdata_get
|
arena_tdata_get
|
||||||
arena_tdata_get_hard
|
arena_tdata_get_hard
|
||||||
|
arena_vsalloc
|
||||||
arenas
|
arenas
|
||||||
arenas_tdata_cleanup
|
arenas_tdata_cleanup
|
||||||
b0get
|
b0get
|
||||||
@ -169,7 +170,6 @@ extent_list_init
|
|||||||
extent_list_last
|
extent_list_last
|
||||||
extent_list_remove
|
extent_list_remove
|
||||||
extent_list_replace
|
extent_list_replace
|
||||||
extent_lookup
|
|
||||||
extent_merge_wrapper
|
extent_merge_wrapper
|
||||||
extent_past_get
|
extent_past_get
|
||||||
extent_prof_tctx_get
|
extent_prof_tctx_get
|
||||||
@ -192,6 +192,7 @@ extent_split_wrapper
|
|||||||
extent_state_get
|
extent_state_get
|
||||||
extent_state_set
|
extent_state_set
|
||||||
extent_szind_get
|
extent_szind_get
|
||||||
|
extent_szind_get_maybe_invalid
|
||||||
extent_szind_set
|
extent_szind_set
|
||||||
extent_usize_get
|
extent_usize_get
|
||||||
extent_zeroed_get
|
extent_zeroed_get
|
||||||
@ -413,25 +414,33 @@ psz2ind
|
|||||||
psz2u
|
psz2u
|
||||||
rtree_clear
|
rtree_clear
|
||||||
rtree_delete
|
rtree_delete
|
||||||
|
rtree_extent_read
|
||||||
|
rtree_extent_szind_read
|
||||||
rtree_leaf_alloc
|
rtree_leaf_alloc
|
||||||
rtree_leaf_dalloc
|
rtree_leaf_dalloc
|
||||||
rtree_leaf_elm_acquire
|
rtree_leaf_elm_acquire
|
||||||
|
rtree_leaf_elm_extent_read
|
||||||
|
rtree_leaf_elm_extent_write
|
||||||
rtree_leaf_elm_lookup
|
rtree_leaf_elm_lookup
|
||||||
rtree_leaf_elm_lookup_hard
|
rtree_leaf_elm_lookup_hard
|
||||||
rtree_leaf_elm_read
|
|
||||||
rtree_leaf_elm_read_acquired
|
|
||||||
rtree_leaf_elm_release
|
rtree_leaf_elm_release
|
||||||
|
rtree_leaf_elm_slab_read
|
||||||
|
rtree_leaf_elm_slab_write
|
||||||
|
rtree_leaf_elm_szind_read
|
||||||
|
rtree_leaf_elm_szind_write
|
||||||
rtree_leaf_elm_witness_access
|
rtree_leaf_elm_witness_access
|
||||||
rtree_leaf_elm_witness_acquire
|
rtree_leaf_elm_witness_acquire
|
||||||
rtree_leaf_elm_witness_release
|
rtree_leaf_elm_witness_release
|
||||||
rtree_leaf_elm_write
|
rtree_leaf_elm_write
|
||||||
rtree_leaf_elm_write_acquired
|
|
||||||
rtree_leafkey
|
rtree_leafkey
|
||||||
rtree_new
|
rtree_new
|
||||||
rtree_node_alloc
|
rtree_node_alloc
|
||||||
rtree_node_dalloc
|
rtree_node_dalloc
|
||||||
rtree_read
|
rtree_read
|
||||||
rtree_subkey
|
rtree_subkey
|
||||||
|
rtree_szind_read
|
||||||
|
rtree_szind_slab_read
|
||||||
|
rtree_szind_slab_update
|
||||||
rtree_write
|
rtree_write
|
||||||
s2u
|
s2u
|
||||||
s2u_compute
|
s2u_compute
|
||||||
|
@ -4,21 +4,40 @@
|
|||||||
#ifndef JEMALLOC_ENABLE_INLINE
|
#ifndef JEMALLOC_ENABLE_INLINE
|
||||||
uintptr_t rtree_leafkey(uintptr_t key);
|
uintptr_t rtree_leafkey(uintptr_t key);
|
||||||
uintptr_t rtree_subkey(uintptr_t key, unsigned level);
|
uintptr_t rtree_subkey(uintptr_t key, unsigned level);
|
||||||
extent_t *rtree_leaf_elm_read(rtree_leaf_elm_t *elm, bool dependent);
|
extent_t *rtree_leaf_elm_extent_read(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
void rtree_leaf_elm_write(rtree_leaf_elm_t *elm, const extent_t *extent);
|
rtree_leaf_elm_t *elm, bool acquired, bool dependent);
|
||||||
|
szind_t rtree_leaf_elm_szind_read(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
|
rtree_leaf_elm_t *elm, bool acquired, bool dependent);
|
||||||
|
bool rtree_leaf_elm_slab_read(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
|
rtree_leaf_elm_t *elm, bool acquired, bool dependent);
|
||||||
|
void rtree_leaf_elm_extent_write(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
|
rtree_leaf_elm_t *elm, bool acquired, extent_t *extent);
|
||||||
|
void rtree_leaf_elm_szind_write(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
|
rtree_leaf_elm_t *elm, bool acquired, szind_t szind);
|
||||||
|
void rtree_leaf_elm_slab_write(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
|
rtree_leaf_elm_t *elm, bool acquired, bool slab);
|
||||||
|
void rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm,
|
||||||
|
bool acquired, extent_t *extent, szind_t szind, bool slab);
|
||||||
rtree_leaf_elm_t *rtree_leaf_elm_lookup(tsdn_t *tsdn, rtree_t *rtree,
|
rtree_leaf_elm_t *rtree_leaf_elm_lookup(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing);
|
rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing);
|
||||||
bool rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
bool rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
||||||
uintptr_t key, const extent_t *extent);
|
uintptr_t key, extent_t *extent, szind_t szind, bool slab);
|
||||||
extent_t *rtree_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
rtree_leaf_elm_t *rtree_read(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
uintptr_t key, bool dependent);
|
rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent);
|
||||||
|
extent_t *rtree_extent_read(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
|
rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent);
|
||||||
|
szind_t rtree_szind_read(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
|
rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent);
|
||||||
|
bool rtree_extent_szind_read(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
|
rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, extent_t **r_extent,
|
||||||
|
szind_t *r_szind);
|
||||||
|
bool rtree_szind_slab_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
||||||
|
uintptr_t key, bool dependent, szind_t *r_szind, bool *r_slab);
|
||||||
|
void rtree_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
|
rtree_ctx_t *rtree_ctx, uintptr_t key, szind_t szind, bool slab);
|
||||||
rtree_leaf_elm_t *rtree_leaf_elm_acquire(tsdn_t *tsdn, rtree_t *rtree,
|
rtree_leaf_elm_t *rtree_leaf_elm_acquire(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing);
|
rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing);
|
||||||
extent_t *rtree_leaf_elm_read_acquired(tsdn_t *tsdn, const rtree_t *rtree,
|
void rtree_leaf_elm_release(tsdn_t *tsdn, rtree_t *rtree,
|
||||||
rtree_leaf_elm_t *elm);
|
|
||||||
void rtree_leaf_elm_write_acquired(tsdn_t *tsdn, const rtree_t *rtree,
|
|
||||||
rtree_leaf_elm_t *elm, const extent_t *extent);
|
|
||||||
void rtree_leaf_elm_release(tsdn_t *tsdn, const rtree_t *rtree,
|
|
||||||
rtree_leaf_elm_t *elm);
|
rtree_leaf_elm_t *elm);
|
||||||
void rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
void rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
||||||
uintptr_t key);
|
uintptr_t key);
|
||||||
@ -45,38 +64,104 @@ rtree_subkey(uintptr_t key, unsigned level) {
|
|||||||
return ((key >> shiftbits) & mask);
|
return ((key >> shiftbits) & mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE extent_t *
|
/*
|
||||||
rtree_leaf_elm_read(rtree_leaf_elm_t *elm, bool dependent) {
|
* Atomic getters.
|
||||||
extent_t *extent;
|
*
|
||||||
|
* dependent: Reading a value on behalf of a pointer to a valid allocation
|
||||||
if (dependent) {
|
* is guaranteed to be a clean read even without synchronization,
|
||||||
/*
|
* because the rtree update became visible in memory before the
|
||||||
* Reading a value on behalf of a pointer to a valid allocation
|
* pointer came into existence.
|
||||||
* is guaranteed to be a clean read even without
|
* !dependent: An arbitrary read, e.g. on behalf of ivsalloc(), may not be
|
||||||
* synchronization, because the rtree update became visible in
|
|
||||||
* memory before the pointer came into existence.
|
|
||||||
*/
|
|
||||||
extent = (extent_t *)atomic_load_p(&elm->extent,
|
|
||||||
ATOMIC_RELAXED);
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* An arbitrary read, e.g. on behalf of ivsalloc(), may not be
|
|
||||||
* dependent on a previous rtree write, which means a stale read
|
* dependent on a previous rtree write, which means a stale read
|
||||||
* could result if synchronization were omitted here.
|
* could result if synchronization were omitted here.
|
||||||
*/
|
*/
|
||||||
extent = (extent_t *)atomic_load_p(&elm->extent,
|
JEMALLOC_ALWAYS_INLINE extent_t *
|
||||||
ATOMIC_ACQUIRE);
|
rtree_leaf_elm_extent_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm,
|
||||||
|
bool acquired, bool dependent) {
|
||||||
|
if (config_debug && acquired) {
|
||||||
|
assert(dependent);
|
||||||
|
rtree_leaf_elm_witness_access(tsdn, rtree, elm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mask the lock bit. */
|
extent_t *extent = (extent_t *)atomic_load_p(&elm->le_extent, dependent
|
||||||
|
? ATOMIC_RELAXED : ATOMIC_ACQUIRE);
|
||||||
|
assert(!acquired || ((uintptr_t)extent & (uintptr_t)0x1) ==
|
||||||
|
(uintptr_t)0x1);
|
||||||
|
/* Mask lock bit. */
|
||||||
extent = (extent_t *)((uintptr_t)extent & ~((uintptr_t)0x1));
|
extent = (extent_t *)((uintptr_t)extent & ~((uintptr_t)0x1));
|
||||||
|
|
||||||
return extent;
|
return extent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JEMALLOC_ALWAYS_INLINE szind_t
|
||||||
|
rtree_leaf_elm_szind_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm,
|
||||||
|
bool acquired, bool dependent) {
|
||||||
|
if (config_debug && acquired) {
|
||||||
|
assert(dependent);
|
||||||
|
rtree_leaf_elm_witness_access(tsdn, rtree, elm);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (szind_t)atomic_load_u(&elm->le_szind, dependent ? ATOMIC_RELAXED
|
||||||
|
: ATOMIC_ACQUIRE);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_ALWAYS_INLINE bool
|
||||||
|
rtree_leaf_elm_slab_read(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm,
|
||||||
|
bool acquired, bool dependent) {
|
||||||
|
if (config_debug && acquired) {
|
||||||
|
assert(dependent);
|
||||||
|
rtree_leaf_elm_witness_access(tsdn, rtree, elm);
|
||||||
|
}
|
||||||
|
|
||||||
|
return atomic_load_b(&elm->le_slab, dependent ? ATOMIC_RELAXED :
|
||||||
|
ATOMIC_ACQUIRE);
|
||||||
|
}
|
||||||
|
|
||||||
JEMALLOC_INLINE void
|
JEMALLOC_INLINE void
|
||||||
rtree_leaf_elm_write(rtree_leaf_elm_t *elm, const extent_t *extent) {
|
rtree_leaf_elm_extent_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm,
|
||||||
atomic_store_p(&elm->extent, (void *)extent, ATOMIC_RELEASE);
|
bool acquired, extent_t *extent) {
|
||||||
|
if (config_debug && acquired) {
|
||||||
|
rtree_leaf_elm_witness_access(tsdn, rtree, elm);
|
||||||
|
}
|
||||||
|
assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0);
|
||||||
|
|
||||||
|
if (acquired) {
|
||||||
|
/* Overlay lock bit. */
|
||||||
|
extent = (extent_t *)((uintptr_t)extent | (uintptr_t)0x1);
|
||||||
|
}
|
||||||
|
atomic_store_p(&elm->le_extent, extent, ATOMIC_RELEASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE void
|
||||||
|
rtree_leaf_elm_szind_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm,
|
||||||
|
bool acquired, szind_t szind) {
|
||||||
|
if (config_debug && acquired) {
|
||||||
|
rtree_leaf_elm_witness_access(tsdn, rtree, elm);
|
||||||
|
}
|
||||||
|
assert(szind <= NSIZES);
|
||||||
|
|
||||||
|
atomic_store_u(&elm->le_szind, szind, ATOMIC_RELEASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE void
|
||||||
|
rtree_leaf_elm_slab_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm,
|
||||||
|
bool acquired, bool slab) {
|
||||||
|
if (config_debug && acquired) {
|
||||||
|
rtree_leaf_elm_witness_access(tsdn, rtree, elm);
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic_store_b(&elm->le_slab, slab, ATOMIC_RELEASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE void
|
||||||
|
rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm,
|
||||||
|
bool acquired, extent_t *extent, szind_t szind, bool slab) {
|
||||||
|
rtree_leaf_elm_slab_write(tsdn, rtree, elm, acquired, slab);
|
||||||
|
rtree_leaf_elm_szind_write(tsdn, rtree, elm, acquired, szind);
|
||||||
|
/*
|
||||||
|
* Write extent last, since the element is atomically considered valid
|
||||||
|
* as soon as the extent field is non-NULL.
|
||||||
|
*/
|
||||||
|
rtree_leaf_elm_extent_write(tsdn, rtree, elm, acquired, extent);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE rtree_leaf_elm_t *
|
JEMALLOC_ALWAYS_INLINE rtree_leaf_elm_t *
|
||||||
@ -124,34 +209,99 @@ rtree_leaf_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
|||||||
|
|
||||||
JEMALLOC_INLINE bool
|
JEMALLOC_INLINE bool
|
||||||
rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key,
|
rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key,
|
||||||
const extent_t *extent) {
|
extent_t *extent, szind_t szind, bool slab) {
|
||||||
rtree_leaf_elm_t *elm;
|
/* Use rtree_clear() to set the extent to NULL. */
|
||||||
|
assert(extent != NULL);
|
||||||
|
|
||||||
assert(extent != NULL); /* Use rtree_clear() for this case. */
|
rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx,
|
||||||
assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0);
|
key, false, true);
|
||||||
|
|
||||||
elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx, key, false, true);
|
|
||||||
if (elm == NULL) {
|
if (elm == NULL) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
assert(rtree_leaf_elm_read(elm, false) == NULL);
|
|
||||||
rtree_leaf_elm_write(elm, extent);
|
assert(rtree_leaf_elm_extent_read(tsdn, rtree, elm, false, false) ==
|
||||||
|
NULL);
|
||||||
|
rtree_leaf_elm_write(tsdn, rtree, elm, false, extent, szind, slab);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_ALWAYS_INLINE extent_t *
|
JEMALLOC_ALWAYS_INLINE rtree_leaf_elm_t *
|
||||||
rtree_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key,
|
rtree_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key,
|
||||||
bool dependent) {
|
bool dependent) {
|
||||||
rtree_leaf_elm_t *elm;
|
rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx,
|
||||||
|
key, dependent, false);
|
||||||
elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx, key, dependent,
|
|
||||||
false);
|
|
||||||
if (!dependent && elm == NULL) {
|
if (!dependent && elm == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
assert(elm != NULL);
|
||||||
|
return elm;
|
||||||
|
}
|
||||||
|
|
||||||
return rtree_leaf_elm_read(elm, dependent);
|
JEMALLOC_ALWAYS_INLINE extent_t *
|
||||||
|
rtree_extent_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
||||||
|
uintptr_t key, bool dependent) {
|
||||||
|
rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key,
|
||||||
|
dependent);
|
||||||
|
if (!dependent && elm == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return rtree_leaf_elm_extent_read(tsdn, rtree, elm, false, dependent);
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_ALWAYS_INLINE szind_t
|
||||||
|
rtree_szind_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
||||||
|
uintptr_t key, bool dependent) {
|
||||||
|
rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key,
|
||||||
|
dependent);
|
||||||
|
if (!dependent && elm == NULL) {
|
||||||
|
return NSIZES;
|
||||||
|
}
|
||||||
|
return rtree_leaf_elm_szind_read(tsdn, rtree, elm, false, dependent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* rtree_slab_read() is intentionally omitted because slab is always read in
|
||||||
|
* conjunction with szind, which makes rtree_szind_slab_read() a better choice.
|
||||||
|
*/
|
||||||
|
|
||||||
|
JEMALLOC_ALWAYS_INLINE bool
|
||||||
|
rtree_extent_szind_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
||||||
|
uintptr_t key, bool dependent, extent_t **r_extent, szind_t *r_szind) {
|
||||||
|
rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key,
|
||||||
|
dependent);
|
||||||
|
if (!dependent && elm == NULL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*r_extent = rtree_leaf_elm_extent_read(tsdn, rtree, elm, false,
|
||||||
|
dependent);
|
||||||
|
*r_szind = rtree_leaf_elm_szind_read(tsdn, rtree, elm, false,
|
||||||
|
dependent);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_ALWAYS_INLINE bool
|
||||||
|
rtree_szind_slab_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
||||||
|
uintptr_t key, bool dependent, szind_t *r_szind, bool *r_slab) {
|
||||||
|
rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key,
|
||||||
|
dependent);
|
||||||
|
if (!dependent && elm == NULL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*r_szind = rtree_leaf_elm_szind_read(tsdn, rtree, elm, false,
|
||||||
|
dependent);
|
||||||
|
*r_slab = rtree_leaf_elm_slab_read(tsdn, rtree, elm, false, dependent);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JEMALLOC_INLINE void
|
||||||
|
rtree_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
||||||
|
uintptr_t key, szind_t szind, bool slab) {
|
||||||
|
assert(!slab || szind < NBINS);
|
||||||
|
|
||||||
|
rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, true);
|
||||||
|
rtree_leaf_elm_slab_write(tsdn, rtree, elm, false, slab);
|
||||||
|
rtree_leaf_elm_szind_write(tsdn, rtree, elm, false, szind);
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_INLINE rtree_leaf_elm_t *
|
JEMALLOC_INLINE rtree_leaf_elm_t *
|
||||||
@ -162,18 +312,19 @@ rtree_leaf_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
|||||||
if (!dependent && elm == NULL) {
|
if (!dependent && elm == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
assert(elm != NULL);
|
||||||
|
|
||||||
spin_t spinner = SPIN_INITIALIZER;
|
spin_t spinner = SPIN_INITIALIZER;
|
||||||
while (true) {
|
while (true) {
|
||||||
/* The least significant bit serves as a lock. */
|
/* The least significant bit serves as a lock. */
|
||||||
void *extent_and_lock = atomic_load_p(&elm->extent,
|
void *extent_and_lock = atomic_load_p(&elm->le_extent,
|
||||||
ATOMIC_RELAXED);
|
ATOMIC_RELAXED);
|
||||||
if (likely(((uintptr_t)extent_and_lock & (uintptr_t)0x1) == 0))
|
if (likely(((uintptr_t)extent_and_lock & (uintptr_t)0x1) == 0))
|
||||||
{
|
{
|
||||||
void *locked = (void *)((uintptr_t)extent_and_lock
|
void *locked = (void *)((uintptr_t)extent_and_lock
|
||||||
| (uintptr_t)0x1);
|
| (uintptr_t)0x1);
|
||||||
if (likely(atomic_compare_exchange_strong_p(
|
if (likely(atomic_compare_exchange_strong_p(
|
||||||
&elm->extent, &extent_and_lock, locked,
|
&elm->le_extent, &extent_and_lock, locked,
|
||||||
ATOMIC_ACQUIRE, ATOMIC_RELAXED))) {
|
ATOMIC_ACQUIRE, ATOMIC_RELAXED))) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -188,42 +339,11 @@ rtree_leaf_elm_acquire(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
|||||||
return elm;
|
return elm;
|
||||||
}
|
}
|
||||||
|
|
||||||
JEMALLOC_INLINE extent_t *
|
|
||||||
rtree_leaf_elm_read_acquired(tsdn_t *tsdn, const rtree_t *rtree,
|
|
||||||
rtree_leaf_elm_t *elm) {
|
|
||||||
extent_t *extent;
|
|
||||||
void *ptr = atomic_load_p(&elm->extent, ATOMIC_RELAXED);
|
|
||||||
assert(((uintptr_t)ptr & (uintptr_t)0x1) == (uintptr_t)0x1);
|
|
||||||
extent = (extent_t *)((uintptr_t)ptr & ~((uintptr_t)0x1));
|
|
||||||
assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0);
|
|
||||||
|
|
||||||
if (config_debug) {
|
|
||||||
rtree_leaf_elm_witness_access(tsdn, rtree, elm);
|
|
||||||
}
|
|
||||||
|
|
||||||
return extent;
|
|
||||||
}
|
|
||||||
|
|
||||||
JEMALLOC_INLINE void
|
JEMALLOC_INLINE void
|
||||||
rtree_leaf_elm_write_acquired(tsdn_t *tsdn, const rtree_t *rtree,
|
rtree_leaf_elm_release(tsdn_t *tsdn, rtree_t *rtree, rtree_leaf_elm_t *elm) {
|
||||||
rtree_leaf_elm_t *elm, const extent_t *extent) {
|
extent_t *extent = rtree_leaf_elm_extent_read(tsdn, rtree, elm, true,
|
||||||
assert(((uintptr_t)extent & (uintptr_t)0x1) == (uintptr_t)0x0);
|
true);
|
||||||
assert(((uintptr_t)atomic_load_p(&elm->extent, ATOMIC_RELAXED)
|
rtree_leaf_elm_extent_write(tsdn, rtree, elm, false, extent);
|
||||||
& (uintptr_t)0x1) == (uintptr_t)0x1);
|
|
||||||
|
|
||||||
if (config_debug) {
|
|
||||||
rtree_leaf_elm_witness_access(tsdn, rtree, elm);
|
|
||||||
}
|
|
||||||
atomic_store_p(&elm->extent, (void *)((uintptr_t)extent |
|
|
||||||
(uintptr_t)0x1), ATOMIC_RELEASE);
|
|
||||||
assert(rtree_leaf_elm_read_acquired(tsdn, rtree, elm) == extent);
|
|
||||||
}
|
|
||||||
|
|
||||||
JEMALLOC_INLINE void
|
|
||||||
rtree_leaf_elm_release(tsdn_t *tsdn, const rtree_t *rtree,
|
|
||||||
rtree_leaf_elm_t *elm) {
|
|
||||||
rtree_leaf_elm_write(elm, rtree_leaf_elm_read_acquired(tsdn, rtree,
|
|
||||||
elm));
|
|
||||||
if (config_debug) {
|
if (config_debug) {
|
||||||
rtree_leaf_elm_witness_release(tsdn, rtree, elm);
|
rtree_leaf_elm_witness_release(tsdn, rtree, elm);
|
||||||
}
|
}
|
||||||
@ -232,10 +352,9 @@ rtree_leaf_elm_release(tsdn_t *tsdn, const rtree_t *rtree,
|
|||||||
JEMALLOC_INLINE void
|
JEMALLOC_INLINE void
|
||||||
rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
|
||||||
uintptr_t key) {
|
uintptr_t key) {
|
||||||
rtree_leaf_elm_t *elm;
|
rtree_leaf_elm_t *elm = rtree_leaf_elm_acquire(tsdn, rtree, rtree_ctx,
|
||||||
|
key, true, false);
|
||||||
elm = rtree_leaf_elm_acquire(tsdn, rtree, rtree_ctx, key, true, false);
|
rtree_leaf_elm_write(tsdn, rtree, elm, true, NULL, NSIZES, false);
|
||||||
rtree_leaf_elm_write_acquired(tsdn, rtree, elm, NULL);
|
|
||||||
rtree_leaf_elm_release(tsdn, rtree, elm);
|
rtree_leaf_elm_release(tsdn, rtree, elm);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -2,11 +2,13 @@
|
|||||||
#define JEMALLOC_INTERNAL_RTREE_STRUCTS_H
|
#define JEMALLOC_INTERNAL_RTREE_STRUCTS_H
|
||||||
|
|
||||||
struct rtree_node_elm_s {
|
struct rtree_node_elm_s {
|
||||||
atomic_p_t child;
|
atomic_p_t child; /* (rtree_{node,leaf}_elm_t *) */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rtree_leaf_elm_s {
|
struct rtree_leaf_elm_s {
|
||||||
atomic_p_t extent;
|
atomic_p_t le_extent; /* (extent_t *) */
|
||||||
|
atomic_u_t le_szind; /* (szind_t) */
|
||||||
|
atomic_b_t le_slab; /* (bool) */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rtree_leaf_elm_witness_s {
|
struct rtree_leaf_elm_witness_s {
|
||||||
|
11
src/arena.c
11
src/arena.c
@ -1468,7 +1468,12 @@ arena_prof_promote(tsdn_t *tsdn, extent_t *extent, const void *ptr,
|
|||||||
assert(isalloc(tsdn, extent, ptr) == LARGE_MINCLASS);
|
assert(isalloc(tsdn, extent, ptr) == LARGE_MINCLASS);
|
||||||
assert(usize <= SMALL_MAXCLASS);
|
assert(usize <= SMALL_MAXCLASS);
|
||||||
|
|
||||||
extent_szind_set(extent, size2index(usize));
|
szind_t szind = size2index(usize);
|
||||||
|
extent_szind_set(extent, szind);
|
||||||
|
rtree_ctx_t rtree_ctx_fallback;
|
||||||
|
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
|
||||||
|
rtree_szind_slab_update(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr,
|
||||||
|
szind, false);
|
||||||
|
|
||||||
prof_accum_cancel(tsdn, &arena->prof_accum, usize);
|
prof_accum_cancel(tsdn, &arena->prof_accum, usize);
|
||||||
|
|
||||||
@ -1481,6 +1486,10 @@ arena_prof_demote(tsdn_t *tsdn, extent_t *extent, const void *ptr) {
|
|||||||
assert(ptr != NULL);
|
assert(ptr != NULL);
|
||||||
|
|
||||||
extent_szind_set(extent, NBINS);
|
extent_szind_set(extent, NBINS);
|
||||||
|
rtree_ctx_t rtree_ctx_fallback;
|
||||||
|
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
|
||||||
|
rtree_szind_slab_update(tsdn, &extents_rtree, rtree_ctx, (uintptr_t)ptr,
|
||||||
|
NBINS, false);
|
||||||
|
|
||||||
assert(isalloc(tsdn, extent, ptr) == LARGE_MINCLASS);
|
assert(isalloc(tsdn, extent, ptr) == LARGE_MINCLASS);
|
||||||
|
|
||||||
|
127
src/extent.c
127
src/extent.c
@ -476,11 +476,12 @@ extent_rtree_acquire(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx,
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
extent_rtree_write_acquired(tsdn_t *tsdn, rtree_leaf_elm_t *elm_a,
|
extent_rtree_write_acquired(tsdn_t *tsdn, rtree_leaf_elm_t *elm_a,
|
||||||
rtree_leaf_elm_t *elm_b, const extent_t *extent) {
|
rtree_leaf_elm_t *elm_b, extent_t *extent, szind_t szind, bool slab) {
|
||||||
rtree_leaf_elm_write_acquired(tsdn, &extents_rtree, elm_a, extent);
|
rtree_leaf_elm_write(tsdn, &extents_rtree, elm_a, true, extent, szind,
|
||||||
|
slab);
|
||||||
if (elm_b != NULL) {
|
if (elm_b != NULL) {
|
||||||
rtree_leaf_elm_write_acquired(tsdn, &extents_rtree, elm_b,
|
rtree_leaf_elm_write(tsdn, &extents_rtree, elm_b, true, extent,
|
||||||
extent);
|
szind, slab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,16 +495,15 @@ extent_rtree_release(tsdn_t *tsdn, rtree_leaf_elm_t *elm_a,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
extent_interior_register(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx,
|
extent_interior_register(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx, extent_t *extent,
|
||||||
const extent_t *extent) {
|
szind_t szind) {
|
||||||
size_t i;
|
|
||||||
|
|
||||||
assert(extent_slab_get(extent));
|
assert(extent_slab_get(extent));
|
||||||
|
|
||||||
for (i = 1; i < (extent_size_get(extent) >> LG_PAGE) - 1; i++) {
|
/* Register interior. */
|
||||||
|
for (size_t i = 1; i < (extent_size_get(extent) >> LG_PAGE) - 1; i++) {
|
||||||
rtree_write(tsdn, &extents_rtree, rtree_ctx,
|
rtree_write(tsdn, &extents_rtree, rtree_ctx,
|
||||||
(uintptr_t)extent_base_get(extent) + (uintptr_t)(i <<
|
(uintptr_t)extent_base_get(extent) + (uintptr_t)(i <<
|
||||||
LG_PAGE), extent);
|
LG_PAGE), extent, szind, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -542,7 +542,7 @@ extent_gdump_sub(tsdn_t *tsdn, const extent_t *extent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
extent_register_impl(tsdn_t *tsdn, const extent_t *extent, bool gdump_add) {
|
extent_register_impl(tsdn_t *tsdn, extent_t *extent, bool gdump_add) {
|
||||||
rtree_ctx_t rtree_ctx_fallback;
|
rtree_ctx_t rtree_ctx_fallback;
|
||||||
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
|
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
|
||||||
rtree_leaf_elm_t *elm_a, *elm_b;
|
rtree_leaf_elm_t *elm_a, *elm_b;
|
||||||
@ -551,9 +551,11 @@ extent_register_impl(tsdn_t *tsdn, const extent_t *extent, bool gdump_add) {
|
|||||||
&elm_b)) {
|
&elm_b)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
extent_rtree_write_acquired(tsdn, elm_a, elm_b, extent);
|
szind_t szind = extent_szind_get_maybe_invalid(extent);
|
||||||
if (extent_slab_get(extent)) {
|
bool slab = extent_slab_get(extent);
|
||||||
extent_interior_register(tsdn, rtree_ctx, extent);
|
extent_rtree_write_acquired(tsdn, elm_a, elm_b, extent, szind, slab);
|
||||||
|
if (slab) {
|
||||||
|
extent_interior_register(tsdn, rtree_ctx, extent, szind);
|
||||||
}
|
}
|
||||||
extent_rtree_release(tsdn, elm_a, elm_b);
|
extent_rtree_release(tsdn, elm_a, elm_b);
|
||||||
|
|
||||||
@ -565,24 +567,24 @@ extent_register_impl(tsdn_t *tsdn, const extent_t *extent, bool gdump_add) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
extent_register(tsdn_t *tsdn, const extent_t *extent) {
|
extent_register(tsdn_t *tsdn, extent_t *extent) {
|
||||||
return extent_register_impl(tsdn, extent, true);
|
return extent_register_impl(tsdn, extent, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
extent_register_no_gdump_add(tsdn_t *tsdn, const extent_t *extent) {
|
extent_register_no_gdump_add(tsdn_t *tsdn, extent_t *extent) {
|
||||||
return extent_register_impl(tsdn, extent, false);
|
return extent_register_impl(tsdn, extent, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
extent_reregister(tsdn_t *tsdn, const extent_t *extent) {
|
extent_reregister(tsdn_t *tsdn, extent_t *extent) {
|
||||||
bool err = extent_register(tsdn, extent);
|
bool err = extent_register(tsdn, extent);
|
||||||
assert(!err);
|
assert(!err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
extent_interior_deregister(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx,
|
extent_interior_deregister(tsdn_t *tsdn, rtree_ctx_t *rtree_ctx,
|
||||||
const extent_t *extent) {
|
extent_t *extent) {
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
assert(extent_slab_get(extent));
|
assert(extent_slab_get(extent));
|
||||||
@ -602,7 +604,7 @@ extent_deregister(tsdn_t *tsdn, extent_t *extent) {
|
|||||||
|
|
||||||
extent_rtree_acquire(tsdn, rtree_ctx, extent, true, false, &elm_a,
|
extent_rtree_acquire(tsdn, rtree_ctx, extent, true, false, &elm_a,
|
||||||
&elm_b);
|
&elm_b);
|
||||||
extent_rtree_write_acquired(tsdn, elm_a, elm_b, NULL);
|
extent_rtree_write_acquired(tsdn, elm_a, elm_b, NULL, NSIZES, false);
|
||||||
if (extent_slab_get(extent)) {
|
if (extent_slab_get(extent)) {
|
||||||
extent_interior_deregister(tsdn, rtree_ctx, extent);
|
extent_interior_deregister(tsdn, rtree_ctx, extent);
|
||||||
extent_slab_set(extent, false);
|
extent_slab_set(extent, false);
|
||||||
@ -653,13 +655,12 @@ extent_recycle_extract(tsdn_t *tsdn, arena_t *arena,
|
|||||||
extent_hooks_assure_initialized(arena, r_extent_hooks);
|
extent_hooks_assure_initialized(arena, r_extent_hooks);
|
||||||
extent_t *extent;
|
extent_t *extent;
|
||||||
if (new_addr != NULL) {
|
if (new_addr != NULL) {
|
||||||
rtree_leaf_elm_t *elm;
|
rtree_leaf_elm_t *elm = rtree_leaf_elm_acquire(tsdn,
|
||||||
|
&extents_rtree, rtree_ctx, (uintptr_t)new_addr, false,
|
||||||
elm = rtree_leaf_elm_acquire(tsdn, &extents_rtree, rtree_ctx,
|
false);
|
||||||
(uintptr_t)new_addr, false, false);
|
|
||||||
if (elm != NULL) {
|
if (elm != NULL) {
|
||||||
extent = rtree_leaf_elm_read_acquired(tsdn,
|
extent = rtree_leaf_elm_extent_read(tsdn,
|
||||||
&extents_rtree, elm);
|
&extents_rtree, elm, true, true);
|
||||||
if (extent != NULL) {
|
if (extent != NULL) {
|
||||||
assert(extent_base_get(extent) == new_addr);
|
assert(extent_base_get(extent) == new_addr);
|
||||||
if (extent_arena_get(extent) != arena ||
|
if (extent_arena_get(extent) != arena ||
|
||||||
@ -715,7 +716,8 @@ extent_recycle_split(tsdn_t *tsdn, arena_t *arena,
|
|||||||
if (leadsize != 0) {
|
if (leadsize != 0) {
|
||||||
extent_t *lead = extent;
|
extent_t *lead = extent;
|
||||||
extent = extent_split_wrapper(tsdn, arena, r_extent_hooks,
|
extent = extent_split_wrapper(tsdn, arena, r_extent_hooks,
|
||||||
lead, leadsize, NSIZES, esize + trailsize, szind);
|
lead, leadsize, NSIZES, false, esize + trailsize, szind,
|
||||||
|
slab);
|
||||||
if (extent == NULL) {
|
if (extent == NULL) {
|
||||||
extent_deregister(tsdn, lead);
|
extent_deregister(tsdn, lead);
|
||||||
extents_leak(tsdn, arena, r_extent_hooks, extents,
|
extents_leak(tsdn, arena, r_extent_hooks, extents,
|
||||||
@ -728,7 +730,8 @@ extent_recycle_split(tsdn_t *tsdn, arena_t *arena,
|
|||||||
/* Split the trail. */
|
/* Split the trail. */
|
||||||
if (trailsize != 0) {
|
if (trailsize != 0) {
|
||||||
extent_t *trail = extent_split_wrapper(tsdn, arena,
|
extent_t *trail = extent_split_wrapper(tsdn, arena,
|
||||||
r_extent_hooks, extent, esize, szind, trailsize, NSIZES);
|
r_extent_hooks, extent, esize, szind, slab, trailsize,
|
||||||
|
NSIZES, false);
|
||||||
if (trail == NULL) {
|
if (trail == NULL) {
|
||||||
extent_deregister(tsdn, extent);
|
extent_deregister(tsdn, extent);
|
||||||
extents_leak(tsdn, arena, r_extent_hooks, extents,
|
extents_leak(tsdn, arena, r_extent_hooks, extents,
|
||||||
@ -742,6 +745,16 @@ extent_recycle_split(tsdn_t *tsdn, arena_t *arena,
|
|||||||
* splitting occurred.
|
* splitting occurred.
|
||||||
*/
|
*/
|
||||||
extent_szind_set(extent, szind);
|
extent_szind_set(extent, szind);
|
||||||
|
if (szind != NSIZES) {
|
||||||
|
rtree_szind_slab_update(tsdn, &extents_rtree, rtree_ctx,
|
||||||
|
(uintptr_t)extent_addr_get(extent), szind, slab);
|
||||||
|
if (slab && extent_size_get(extent) > PAGE) {
|
||||||
|
rtree_szind_slab_update(tsdn, &extents_rtree,
|
||||||
|
rtree_ctx,
|
||||||
|
(uintptr_t)extent_past_get(extent) -
|
||||||
|
(uintptr_t)PAGE, szind, slab);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return extent;
|
return extent;
|
||||||
@ -788,7 +801,7 @@ extent_recycle(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks,
|
|||||||
assert(extent_state_get(extent) == extent_state_active);
|
assert(extent_state_get(extent) == extent_state_active);
|
||||||
if (slab) {
|
if (slab) {
|
||||||
extent_slab_set(extent, slab);
|
extent_slab_set(extent, slab);
|
||||||
extent_interior_register(tsdn, rtree_ctx, extent);
|
extent_interior_register(tsdn, rtree_ctx, extent, szind);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*zero) {
|
if (*zero) {
|
||||||
@ -934,7 +947,7 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena,
|
|||||||
if (leadsize != 0) {
|
if (leadsize != 0) {
|
||||||
extent_t *lead = extent;
|
extent_t *lead = extent;
|
||||||
extent = extent_split_wrapper(tsdn, arena, r_extent_hooks, lead,
|
extent = extent_split_wrapper(tsdn, arena, r_extent_hooks, lead,
|
||||||
leadsize, NSIZES, esize + trailsize, szind);
|
leadsize, NSIZES, false, esize + trailsize, szind, slab);
|
||||||
if (extent == NULL) {
|
if (extent == NULL) {
|
||||||
extent_deregister(tsdn, lead);
|
extent_deregister(tsdn, lead);
|
||||||
extents_leak(tsdn, arena, r_extent_hooks, false, lead);
|
extents_leak(tsdn, arena, r_extent_hooks, false, lead);
|
||||||
@ -947,7 +960,8 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena,
|
|||||||
/* Split the trail. */
|
/* Split the trail. */
|
||||||
if (trailsize != 0) {
|
if (trailsize != 0) {
|
||||||
extent_t *trail = extent_split_wrapper(tsdn, arena,
|
extent_t *trail = extent_split_wrapper(tsdn, arena,
|
||||||
r_extent_hooks, extent, esize, szind, trailsize, NSIZES);
|
r_extent_hooks, extent, esize, szind, slab, trailsize,
|
||||||
|
NSIZES, false);
|
||||||
if (trail == NULL) {
|
if (trail == NULL) {
|
||||||
extent_deregister(tsdn, extent);
|
extent_deregister(tsdn, extent);
|
||||||
extents_leak(tsdn, arena, r_extent_hooks,
|
extents_leak(tsdn, arena, r_extent_hooks,
|
||||||
@ -961,7 +975,21 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena,
|
|||||||
* Splitting causes szind to be set as a side effect, but no
|
* Splitting causes szind to be set as a side effect, but no
|
||||||
* splitting occurred.
|
* splitting occurred.
|
||||||
*/
|
*/
|
||||||
|
rtree_ctx_t rtree_ctx_fallback;
|
||||||
|
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn,
|
||||||
|
&rtree_ctx_fallback);
|
||||||
|
|
||||||
extent_szind_set(extent, szind);
|
extent_szind_set(extent, szind);
|
||||||
|
if (szind != NSIZES) {
|
||||||
|
rtree_szind_slab_update(tsdn, &extents_rtree, rtree_ctx,
|
||||||
|
(uintptr_t)extent_addr_get(extent), szind, slab);
|
||||||
|
if (slab && extent_size_get(extent) > PAGE) {
|
||||||
|
rtree_szind_slab_update(tsdn, &extents_rtree,
|
||||||
|
rtree_ctx,
|
||||||
|
(uintptr_t)extent_past_get(extent) -
|
||||||
|
(uintptr_t)PAGE, szind, slab);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*commit && !extent_committed_get(extent)) {
|
if (*commit && !extent_committed_get(extent)) {
|
||||||
@ -987,7 +1015,7 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena,
|
|||||||
&rtree_ctx_fallback);
|
&rtree_ctx_fallback);
|
||||||
|
|
||||||
extent_slab_set(extent, true);
|
extent_slab_set(extent, true);
|
||||||
extent_interior_register(tsdn, rtree_ctx, extent);
|
extent_interior_register(tsdn, rtree_ctx, extent, szind);
|
||||||
}
|
}
|
||||||
if (*zero && !extent_zeroed_get(extent)) {
|
if (*zero && !extent_zeroed_get(extent)) {
|
||||||
void *addr = extent_base_get(extent);
|
void *addr = extent_base_get(extent);
|
||||||
@ -1162,8 +1190,8 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena,
|
|||||||
&extents_rtree, rtree_ctx,
|
&extents_rtree, rtree_ctx,
|
||||||
(uintptr_t)extent_past_get(extent), false, false);
|
(uintptr_t)extent_past_get(extent), false, false);
|
||||||
if (next_elm != NULL) {
|
if (next_elm != NULL) {
|
||||||
extent_t *next = rtree_leaf_elm_read_acquired(tsdn,
|
extent_t *next = rtree_leaf_elm_extent_read(tsdn,
|
||||||
&extents_rtree, next_elm);
|
&extents_rtree, next_elm, true, true);
|
||||||
/*
|
/*
|
||||||
* extents->mtx only protects against races for
|
* extents->mtx only protects against races for
|
||||||
* like-state extents, so call extent_can_coalesce()
|
* like-state extents, so call extent_can_coalesce()
|
||||||
@ -1188,8 +1216,8 @@ extent_try_coalesce(tsdn_t *tsdn, arena_t *arena,
|
|||||||
&extents_rtree, rtree_ctx,
|
&extents_rtree, rtree_ctx,
|
||||||
(uintptr_t)extent_before_get(extent), false, false);
|
(uintptr_t)extent_before_get(extent), false, false);
|
||||||
if (prev_elm != NULL) {
|
if (prev_elm != NULL) {
|
||||||
extent_t *prev = rtree_leaf_elm_read_acquired(tsdn,
|
extent_t *prev = rtree_leaf_elm_extent_read(tsdn,
|
||||||
&extents_rtree, prev_elm);
|
&extents_rtree, prev_elm, true, true);
|
||||||
bool can_coalesce = (prev != NULL &&
|
bool can_coalesce = (prev != NULL &&
|
||||||
extent_can_coalesce(arena, extents, extent, prev));
|
extent_can_coalesce(arena, extents, extent, prev));
|
||||||
rtree_leaf_elm_release(tsdn, &extents_rtree, prev_elm);
|
rtree_leaf_elm_release(tsdn, &extents_rtree, prev_elm);
|
||||||
@ -1231,7 +1259,8 @@ extent_record(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks,
|
|||||||
extent_slab_set(extent, false);
|
extent_slab_set(extent, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(extent_lookup(tsdn, extent_base_get(extent), true) == extent);
|
assert(rtree_extent_read(tsdn, &extents_rtree, rtree_ctx,
|
||||||
|
(uintptr_t)extent_base_get(extent), true) == extent);
|
||||||
|
|
||||||
if (!extents->delay_coalesce) {
|
if (!extents->delay_coalesce) {
|
||||||
extent = extent_try_coalesce(tsdn, arena, r_extent_hooks,
|
extent = extent_try_coalesce(tsdn, arena, r_extent_hooks,
|
||||||
@ -1467,7 +1496,7 @@ extent_split_default(extent_hooks_t *extent_hooks, void *addr, size_t size,
|
|||||||
extent_t *
|
extent_t *
|
||||||
extent_split_wrapper(tsdn_t *tsdn, arena_t *arena,
|
extent_split_wrapper(tsdn_t *tsdn, arena_t *arena,
|
||||||
extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a,
|
extent_hooks_t **r_extent_hooks, extent_t *extent, size_t size_a,
|
||||||
szind_t szind_a, size_t size_b, szind_t szind_b) {
|
szind_t szind_a, bool slab_a, size_t size_b, szind_t szind_b, bool slab_b) {
|
||||||
assert(extent_size_get(extent) == size_a + size_b);
|
assert(extent_size_get(extent) == size_a + size_b);
|
||||||
witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0);
|
witness_assert_depth_to_rank(tsdn, WITNESS_RANK_CORE, 0);
|
||||||
|
|
||||||
@ -1491,7 +1520,7 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena,
|
|||||||
extent_t lead;
|
extent_t lead;
|
||||||
|
|
||||||
extent_init(&lead, arena, extent_addr_get(extent), size_a,
|
extent_init(&lead, arena, extent_addr_get(extent), size_a,
|
||||||
extent_slab_get(extent), szind_a, extent_sn_get(extent),
|
slab_a, szind_a, extent_sn_get(extent),
|
||||||
extent_state_get(extent), extent_zeroed_get(extent),
|
extent_state_get(extent), extent_zeroed_get(extent),
|
||||||
extent_committed_get(extent));
|
extent_committed_get(extent));
|
||||||
|
|
||||||
@ -1502,9 +1531,9 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena,
|
|||||||
}
|
}
|
||||||
|
|
||||||
extent_init(trail, arena, (void *)((uintptr_t)extent_base_get(extent) +
|
extent_init(trail, arena, (void *)((uintptr_t)extent_base_get(extent) +
|
||||||
size_a), size_b, extent_slab_get(extent), szind_b,
|
size_a), size_b, slab_b, szind_b, extent_sn_get(extent),
|
||||||
extent_sn_get(extent), extent_state_get(extent),
|
extent_state_get(extent), extent_zeroed_get(extent),
|
||||||
extent_zeroed_get(extent), extent_committed_get(extent));
|
extent_committed_get(extent));
|
||||||
if (extent_rtree_acquire(tsdn, rtree_ctx, trail, false, true,
|
if (extent_rtree_acquire(tsdn, rtree_ctx, trail, false, true,
|
||||||
&trail_elm_a, &trail_elm_b)) {
|
&trail_elm_a, &trail_elm_b)) {
|
||||||
goto label_error_c;
|
goto label_error_c;
|
||||||
@ -1519,8 +1548,10 @@ extent_split_wrapper(tsdn_t *tsdn, arena_t *arena,
|
|||||||
extent_size_set(extent, size_a);
|
extent_size_set(extent, size_a);
|
||||||
extent_szind_set(extent, szind_a);
|
extent_szind_set(extent, szind_a);
|
||||||
|
|
||||||
extent_rtree_write_acquired(tsdn, lead_elm_a, lead_elm_b, extent);
|
extent_rtree_write_acquired(tsdn, lead_elm_a, lead_elm_b, extent,
|
||||||
extent_rtree_write_acquired(tsdn, trail_elm_a, trail_elm_b, trail);
|
szind_a, slab_a);
|
||||||
|
extent_rtree_write_acquired(tsdn, trail_elm_a, trail_elm_b, trail,
|
||||||
|
szind_b, slab_b);
|
||||||
|
|
||||||
extent_rtree_release(tsdn, lead_elm_a, lead_elm_b);
|
extent_rtree_release(tsdn, lead_elm_a, lead_elm_b);
|
||||||
extent_rtree_release(tsdn, trail_elm_a, trail_elm_b);
|
extent_rtree_release(tsdn, trail_elm_a, trail_elm_b);
|
||||||
@ -1599,13 +1630,13 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena,
|
|||||||
&b_elm_b);
|
&b_elm_b);
|
||||||
|
|
||||||
if (a_elm_b != NULL) {
|
if (a_elm_b != NULL) {
|
||||||
rtree_leaf_elm_write_acquired(tsdn, &extents_rtree, a_elm_b,
|
rtree_leaf_elm_write(tsdn, &extents_rtree, a_elm_b, true, NULL,
|
||||||
NULL);
|
NSIZES, false);
|
||||||
rtree_leaf_elm_release(tsdn, &extents_rtree, a_elm_b);
|
rtree_leaf_elm_release(tsdn, &extents_rtree, a_elm_b);
|
||||||
}
|
}
|
||||||
if (b_elm_b != NULL) {
|
if (b_elm_b != NULL) {
|
||||||
rtree_leaf_elm_write_acquired(tsdn, &extents_rtree, b_elm_a,
|
rtree_leaf_elm_write(tsdn, &extents_rtree, b_elm_a, true, NULL,
|
||||||
NULL);
|
NSIZES, false);
|
||||||
rtree_leaf_elm_release(tsdn, &extents_rtree, b_elm_a);
|
rtree_leaf_elm_release(tsdn, &extents_rtree, b_elm_a);
|
||||||
} else {
|
} else {
|
||||||
b_elm_b = b_elm_a;
|
b_elm_b = b_elm_a;
|
||||||
@ -1617,7 +1648,7 @@ extent_merge_wrapper(tsdn_t *tsdn, arena_t *arena,
|
|||||||
extent_sn_get(a) : extent_sn_get(b));
|
extent_sn_get(a) : extent_sn_get(b));
|
||||||
extent_zeroed_set(a, extent_zeroed_get(a) && extent_zeroed_get(b));
|
extent_zeroed_set(a, extent_zeroed_get(a) && extent_zeroed_get(b));
|
||||||
|
|
||||||
extent_rtree_write_acquired(tsdn, a_elm_a, b_elm_b, a);
|
extent_rtree_write_acquired(tsdn, a_elm_a, b_elm_b, a, NSIZES, false);
|
||||||
extent_rtree_release(tsdn, a_elm_a, b_elm_b);
|
extent_rtree_release(tsdn, a_elm_a, b_elm_b);
|
||||||
|
|
||||||
extent_dalloc(tsdn, extent_arena_get(b), b);
|
extent_dalloc(tsdn, extent_arena_get(b), b);
|
||||||
|
17
src/large.c
17
src/large.c
@ -66,8 +66,8 @@ large_palloc(tsdn_t *tsdn, arena_t *arena, size_t usize, size_t alignment,
|
|||||||
#define large_dalloc_junk JEMALLOC_N(n_large_dalloc_junk)
|
#define large_dalloc_junk JEMALLOC_N(n_large_dalloc_junk)
|
||||||
#endif
|
#endif
|
||||||
void
|
void
|
||||||
large_dalloc_junk(void *ptr, size_t usize) {
|
large_dalloc_junk(void *ptr, size_t size) {
|
||||||
memset(ptr, JEMALLOC_FREE_JUNK, usize);
|
memset(ptr, JEMALLOC_FREE_JUNK, size);
|
||||||
}
|
}
|
||||||
#ifdef JEMALLOC_JET
|
#ifdef JEMALLOC_JET
|
||||||
#undef large_dalloc_junk
|
#undef large_dalloc_junk
|
||||||
@ -80,14 +80,14 @@ large_dalloc_junk_t *large_dalloc_junk = JEMALLOC_N(n_large_dalloc_junk);
|
|||||||
#define large_dalloc_maybe_junk JEMALLOC_N(n_large_dalloc_maybe_junk)
|
#define large_dalloc_maybe_junk JEMALLOC_N(n_large_dalloc_maybe_junk)
|
||||||
#endif
|
#endif
|
||||||
void
|
void
|
||||||
large_dalloc_maybe_junk(void *ptr, size_t usize) {
|
large_dalloc_maybe_junk(void *ptr, size_t size) {
|
||||||
if (config_fill && have_dss && unlikely(opt_junk_free)) {
|
if (config_fill && have_dss && unlikely(opt_junk_free)) {
|
||||||
/*
|
/*
|
||||||
* Only bother junk filling if the extent isn't about to be
|
* Only bother junk filling if the extent isn't about to be
|
||||||
* unmapped.
|
* unmapped.
|
||||||
*/
|
*/
|
||||||
if (!config_munmap || (have_dss && extent_in_dss(ptr))) {
|
if (!config_munmap || (have_dss && extent_in_dss(ptr))) {
|
||||||
large_dalloc_junk(ptr, usize);
|
large_dalloc_junk(ptr, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -115,7 +115,7 @@ large_ralloc_no_move_shrink(tsdn_t *tsdn, extent_t *extent, size_t usize) {
|
|||||||
if (diff != 0) {
|
if (diff != 0) {
|
||||||
extent_t *trail = extent_split_wrapper(tsdn, arena,
|
extent_t *trail = extent_split_wrapper(tsdn, arena,
|
||||||
&extent_hooks, extent, usize + large_pad, size2index(usize),
|
&extent_hooks, extent, usize + large_pad, size2index(usize),
|
||||||
diff, NSIZES);
|
false, diff, NSIZES, false);
|
||||||
if (trail == NULL) {
|
if (trail == NULL) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -182,7 +182,12 @@ large_ralloc_no_move_expand(tsdn_t *tsdn, extent_t *extent, size_t usize,
|
|||||||
extent_dalloc_wrapper(tsdn, arena, &extent_hooks, trail);
|
extent_dalloc_wrapper(tsdn, arena, &extent_hooks, trail);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
extent_szind_set(extent, size2index(usize));
|
rtree_ctx_t rtree_ctx_fallback;
|
||||||
|
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
|
||||||
|
szind_t szind = size2index(usize);
|
||||||
|
extent_szind_set(extent, szind);
|
||||||
|
rtree_szind_slab_update(tsdn, &extents_rtree, rtree_ctx,
|
||||||
|
(uintptr_t)extent_addr_get(extent), szind, false);
|
||||||
|
|
||||||
if (config_stats && new_mapping) {
|
if (config_stats && new_mapping) {
|
||||||
arena_stats_mapped_add(tsdn, &arena->stats, trailsize);
|
arena_stats_mapped_add(tsdn, &arena->stats, trailsize);
|
||||||
|
@ -57,9 +57,16 @@ get_large_size(size_t ind) {
|
|||||||
/* Like ivsalloc(), but safe to call on discarded allocations. */
|
/* Like ivsalloc(), but safe to call on discarded allocations. */
|
||||||
static size_t
|
static size_t
|
||||||
vsalloc(tsdn_t *tsdn, const void *ptr) {
|
vsalloc(tsdn_t *tsdn, const void *ptr) {
|
||||||
extent_t *extent;
|
rtree_ctx_t rtree_ctx_fallback;
|
||||||
|
rtree_ctx_t *rtree_ctx = tsdn_rtree_ctx(tsdn, &rtree_ctx_fallback);
|
||||||
|
|
||||||
|
extent_t *extent;
|
||||||
|
szind_t szind;
|
||||||
|
if (rtree_extent_szind_read(tsdn, &extents_rtree, rtree_ctx,
|
||||||
|
(uintptr_t)ptr, false, &extent, &szind)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
extent = extent_lookup(tsdn, ptr, false);
|
|
||||||
if (extent == NULL) {
|
if (extent == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -67,7 +74,11 @@ vsalloc(tsdn_t *tsdn, const void *ptr) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return isalloc(tsdn, extent, ptr);
|
if (szind == NSIZES) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return index2size(szind);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned
|
static unsigned
|
||||||
|
@ -70,8 +70,8 @@ TEST_BEGIN(test_rtree_read_empty) {
|
|||||||
rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER;
|
rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER;
|
||||||
test_rtree = &rtree;
|
test_rtree = &rtree;
|
||||||
assert_false(rtree_new(&rtree), "Unexpected rtree_new() failure");
|
assert_false(rtree_new(&rtree), "Unexpected rtree_new() failure");
|
||||||
assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, PAGE, false),
|
assert_ptr_null(rtree_extent_read(tsdn, &rtree, &rtree_ctx, PAGE,
|
||||||
"rtree_read() should return NULL for empty tree");
|
false), "rtree_extent_read() should return NULL for empty tree");
|
||||||
rtree_delete(tsdn, &rtree);
|
rtree_delete(tsdn, &rtree);
|
||||||
test_rtree = NULL;
|
test_rtree = NULL;
|
||||||
}
|
}
|
||||||
@ -99,6 +99,8 @@ thd_start(void *varg) {
|
|||||||
sfmt = init_gen_rand(arg->seed);
|
sfmt = init_gen_rand(arg->seed);
|
||||||
extent = (extent_t *)malloc(sizeof(extent));
|
extent = (extent_t *)malloc(sizeof(extent));
|
||||||
assert_ptr_not_null(extent, "Unexpected malloc() failure");
|
assert_ptr_not_null(extent, "Unexpected malloc() failure");
|
||||||
|
extent_init(extent, NULL, NULL, 0, false, NSIZES, 0,
|
||||||
|
extent_state_active, false, false);
|
||||||
tsdn = tsdn_fetch();
|
tsdn = tsdn_fetch();
|
||||||
|
|
||||||
for (i = 0; i < NITERS; i++) {
|
for (i = 0; i < NITERS; i++) {
|
||||||
@ -109,18 +111,24 @@ thd_start(void *varg) {
|
|||||||
&arg->rtree, &rtree_ctx, key, false, true);
|
&arg->rtree, &rtree_ctx, key, false, true);
|
||||||
assert_ptr_not_null(elm,
|
assert_ptr_not_null(elm,
|
||||||
"Unexpected rtree_leaf_elm_acquire() failure");
|
"Unexpected rtree_leaf_elm_acquire() failure");
|
||||||
rtree_leaf_elm_write_acquired(tsdn, &arg->rtree, elm,
|
rtree_leaf_elm_write(tsdn, &arg->rtree, elm, true,
|
||||||
extent);
|
extent, NSIZES, false);
|
||||||
rtree_leaf_elm_release(tsdn, &arg->rtree, elm);
|
rtree_leaf_elm_release(tsdn, &arg->rtree, elm);
|
||||||
|
|
||||||
elm = rtree_leaf_elm_acquire(tsdn, &arg->rtree,
|
elm = rtree_leaf_elm_acquire(tsdn, &arg->rtree,
|
||||||
&rtree_ctx, key, true, false);
|
&rtree_ctx, key, true, false);
|
||||||
assert_ptr_not_null(elm,
|
assert_ptr_not_null(elm,
|
||||||
"Unexpected rtree_leaf_elm_acquire() failure");
|
"Unexpected rtree_leaf_elm_acquire() failure");
|
||||||
rtree_leaf_elm_read_acquired(tsdn, &arg->rtree, elm);
|
rtree_leaf_elm_extent_read(tsdn, &arg->rtree, elm, true,
|
||||||
|
true);
|
||||||
|
rtree_leaf_elm_szind_read(tsdn, &arg->rtree, elm, true,
|
||||||
|
true);
|
||||||
|
rtree_leaf_elm_slab_read(tsdn, &arg->rtree, elm, true,
|
||||||
|
true);
|
||||||
rtree_leaf_elm_release(tsdn, &arg->rtree, elm);
|
rtree_leaf_elm_release(tsdn, &arg->rtree, elm);
|
||||||
} else {
|
} else {
|
||||||
rtree_read(tsdn, &arg->rtree, &rtree_ctx, key, false);
|
rtree_extent_read(tsdn, &arg->rtree, &rtree_ctx, key,
|
||||||
|
false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,26 +166,33 @@ TEST_END
|
|||||||
|
|
||||||
TEST_BEGIN(test_rtree_extrema) {
|
TEST_BEGIN(test_rtree_extrema) {
|
||||||
extent_t extent_a, extent_b;
|
extent_t extent_a, extent_b;
|
||||||
tsdn_t *tsdn;
|
extent_init(&extent_a, NULL, NULL, LARGE_MINCLASS, false,
|
||||||
|
size2index(LARGE_MINCLASS), 0, extent_state_active, false, false);
|
||||||
|
extent_init(&extent_b, NULL, NULL, 0, false, NSIZES, 0,
|
||||||
|
extent_state_active, false, false);
|
||||||
|
|
||||||
tsdn = tsdn_fetch();
|
tsdn_t *tsdn = tsdn_fetch();
|
||||||
|
|
||||||
rtree_t rtree;
|
rtree_t rtree;
|
||||||
rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER;
|
rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER;
|
||||||
test_rtree = &rtree;
|
test_rtree = &rtree;
|
||||||
assert_false(rtree_new(&rtree), "Unexpected rtree_new() failure");
|
assert_false(rtree_new(&rtree), "Unexpected rtree_new() failure");
|
||||||
|
|
||||||
assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, PAGE, &extent_a),
|
assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, PAGE, &extent_a,
|
||||||
|
extent_szind_get(&extent_a), extent_slab_get(&extent_a)),
|
||||||
"Unexpected rtree_write() failure");
|
"Unexpected rtree_write() failure");
|
||||||
assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, PAGE, true),
|
rtree_szind_slab_update(tsdn, &rtree, &rtree_ctx, PAGE,
|
||||||
|
extent_szind_get(&extent_a), extent_slab_get(&extent_a));
|
||||||
|
assert_ptr_eq(rtree_extent_read(tsdn, &rtree, &rtree_ctx, PAGE, true),
|
||||||
&extent_a,
|
&extent_a,
|
||||||
"rtree_read() should return previously set value");
|
"rtree_extent_read() should return previously set value");
|
||||||
|
|
||||||
assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, ~((uintptr_t)0),
|
assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, ~((uintptr_t)0),
|
||||||
&extent_b), "Unexpected rtree_write() failure");
|
&extent_b, extent_szind_get_maybe_invalid(&extent_b),
|
||||||
assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, ~((uintptr_t)0),
|
extent_slab_get(&extent_b)), "Unexpected rtree_write() failure");
|
||||||
true), &extent_b,
|
assert_ptr_eq(rtree_extent_read(tsdn, &rtree, &rtree_ctx,
|
||||||
"rtree_read() should return previously set value");
|
~((uintptr_t)0), true), &extent_b,
|
||||||
|
"rtree_extent_read() should return previously set value");
|
||||||
|
|
||||||
rtree_delete(tsdn, &rtree);
|
rtree_delete(tsdn, &rtree);
|
||||||
test_rtree = NULL;
|
test_rtree = NULL;
|
||||||
@ -191,6 +206,9 @@ TEST_BEGIN(test_rtree_bits) {
|
|||||||
PAGE + (((uintptr_t)1) << LG_PAGE) - 1};
|
PAGE + (((uintptr_t)1) << LG_PAGE) - 1};
|
||||||
|
|
||||||
extent_t extent;
|
extent_t extent;
|
||||||
|
extent_init(&extent, NULL, NULL, 0, false, NSIZES, 0,
|
||||||
|
extent_state_active, false, false);
|
||||||
|
|
||||||
rtree_t rtree;
|
rtree_t rtree;
|
||||||
rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER;
|
rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER;
|
||||||
|
|
||||||
@ -200,16 +218,17 @@ TEST_BEGIN(test_rtree_bits) {
|
|||||||
|
|
||||||
for (unsigned i = 0; i < sizeof(keys)/sizeof(uintptr_t); i++) {
|
for (unsigned i = 0; i < sizeof(keys)/sizeof(uintptr_t); i++) {
|
||||||
assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, keys[i],
|
assert_false(rtree_write(tsdn, &rtree, &rtree_ctx, keys[i],
|
||||||
&extent), "Unexpected rtree_write() failure");
|
&extent, NSIZES, false),
|
||||||
|
"Unexpected rtree_write() failure");
|
||||||
for (unsigned j = 0; j < sizeof(keys)/sizeof(uintptr_t); j++) {
|
for (unsigned j = 0; j < sizeof(keys)/sizeof(uintptr_t); j++) {
|
||||||
assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx,
|
assert_ptr_eq(rtree_extent_read(tsdn, &rtree,
|
||||||
keys[j], true), &extent,
|
&rtree_ctx, keys[j], true),
|
||||||
"rtree_read() should return previously set "
|
&extent, "rtree_extent_read() should return "
|
||||||
"value and ignore insignificant key bits; "
|
"previously set value and ignore insignificant key "
|
||||||
"i=%u, j=%u, set key=%#"FMTxPTR", get "
|
"bits; i=%u, j=%u, set key=%#"FMTxPTR", get "
|
||||||
"key=%#"FMTxPTR, i, j, keys[i], keys[j]);
|
"key=%#"FMTxPTR, i, j, keys[i], keys[j]);
|
||||||
}
|
}
|
||||||
assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx,
|
assert_ptr_null(rtree_extent_read(tsdn, &rtree, &rtree_ctx,
|
||||||
(((uintptr_t)2) << LG_PAGE), false),
|
(((uintptr_t)2) << LG_PAGE), false),
|
||||||
"Only leftmost rtree leaf should be set; i=%u", i);
|
"Only leftmost rtree leaf should be set; i=%u", i);
|
||||||
rtree_clear(tsdn, &rtree, &rtree_ctx, keys[i]);
|
rtree_clear(tsdn, &rtree, &rtree_ctx, keys[i]);
|
||||||
@ -226,10 +245,13 @@ TEST_BEGIN(test_rtree_random) {
|
|||||||
sfmt_t *sfmt = init_gen_rand(SEED);
|
sfmt_t *sfmt = init_gen_rand(SEED);
|
||||||
tsdn_t *tsdn = tsdn_fetch();
|
tsdn_t *tsdn = tsdn_fetch();
|
||||||
uintptr_t keys[NSET];
|
uintptr_t keys[NSET];
|
||||||
extent_t extent;
|
|
||||||
rtree_t rtree;
|
rtree_t rtree;
|
||||||
rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER;
|
rtree_ctx_t rtree_ctx = RTREE_CTX_INITIALIZER;
|
||||||
|
|
||||||
|
extent_t extent;
|
||||||
|
extent_init(&extent, NULL, NULL, 0, false, NSIZES, 0,
|
||||||
|
extent_state_active, false, false);
|
||||||
|
|
||||||
test_rtree = &rtree;
|
test_rtree = &rtree;
|
||||||
assert_false(rtree_new(&rtree), "Unexpected rtree_new() failure");
|
assert_false(rtree_new(&rtree), "Unexpected rtree_new() failure");
|
||||||
|
|
||||||
@ -239,26 +261,30 @@ TEST_BEGIN(test_rtree_random) {
|
|||||||
&rtree_ctx, keys[i], false, true);
|
&rtree_ctx, keys[i], false, true);
|
||||||
assert_ptr_not_null(elm,
|
assert_ptr_not_null(elm,
|
||||||
"Unexpected rtree_leaf_elm_acquire() failure");
|
"Unexpected rtree_leaf_elm_acquire() failure");
|
||||||
rtree_leaf_elm_write_acquired(tsdn, &rtree, elm, &extent);
|
rtree_leaf_elm_write(tsdn, &rtree, elm, true, &extent, NSIZES,
|
||||||
|
false);
|
||||||
rtree_leaf_elm_release(tsdn, &rtree, elm);
|
rtree_leaf_elm_release(tsdn, &rtree, elm);
|
||||||
assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, keys[i],
|
assert_ptr_eq(rtree_extent_read(tsdn, &rtree, &rtree_ctx,
|
||||||
true), &extent,
|
keys[i], true), &extent,
|
||||||
"rtree_read() should return previously set value");
|
"rtree_extent_read() should return previously set value");
|
||||||
}
|
}
|
||||||
for (unsigned i = 0; i < NSET; i++) {
|
for (unsigned i = 0; i < NSET; i++) {
|
||||||
assert_ptr_eq(rtree_read(tsdn, &rtree, &rtree_ctx, keys[i],
|
assert_ptr_eq(rtree_extent_read(tsdn, &rtree, &rtree_ctx,
|
||||||
true), &extent,
|
keys[i], true), &extent,
|
||||||
"rtree_read() should return previously set value, i=%u", i);
|
"rtree_extent_read() should return previously set value, "
|
||||||
|
"i=%u", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned i = 0; i < NSET; i++) {
|
for (unsigned i = 0; i < NSET; i++) {
|
||||||
rtree_clear(tsdn, &rtree, &rtree_ctx, keys[i]);
|
rtree_clear(tsdn, &rtree, &rtree_ctx, keys[i]);
|
||||||
assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, keys[i],
|
assert_ptr_null(rtree_extent_read(tsdn, &rtree, &rtree_ctx,
|
||||||
true), "rtree_read() should return previously set value");
|
keys[i], true),
|
||||||
|
"rtree_extent_read() should return previously set value");
|
||||||
}
|
}
|
||||||
for (unsigned i = 0; i < NSET; i++) {
|
for (unsigned i = 0; i < NSET; i++) {
|
||||||
assert_ptr_null(rtree_read(tsdn, &rtree, &rtree_ctx, keys[i],
|
assert_ptr_null(rtree_extent_read(tsdn, &rtree, &rtree_ctx,
|
||||||
true), "rtree_read() should return previously set value");
|
keys[i], true),
|
||||||
|
"rtree_extent_read() should return previously set value");
|
||||||
}
|
}
|
||||||
|
|
||||||
rtree_delete(tsdn, &rtree);
|
rtree_delete(tsdn, &rtree);
|
||||||
|
Loading…
Reference in New Issue
Block a user