Add opt.lg_extent_max_active_fit
When allocating from dirty extents (which we always prefer if available), large active extents can get split even if the new allocation is much smaller, in which case the introduced fragmentation causes high long term damage. This new option controls the threshold to reuse and split an existing active extent. We avoid using a large extent for much smaller sizes, in order to reduce fragmentation. In some workload, adding the threshold improves virtual memory usage by >10x.
This commit is contained in:
parent
282a3faa17
commit
fac706836f
@ -1069,6 +1069,22 @@ mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
|
|||||||
for related dynamic control options.</para></listitem>
|
for related dynamic control options.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="opt.lg_extent_max_active_fit">
|
||||||
|
<term>
|
||||||
|
<mallctl>opt.lg_extent_max_active_fit</mallctl>
|
||||||
|
(<type>size_t</type>)
|
||||||
|
<literal>r-</literal>
|
||||||
|
</term>
|
||||||
|
<listitem><para>When reusing dirty extents, this determines the (log
|
||||||
|
base 2 of the) maximum ratio between the size of the active extent
|
||||||
|
selected (to split off from) and the size of the requested allocation.
|
||||||
|
This prevents the splitting of large active extents for smaller
|
||||||
|
allocations, which can reduce fragmentation over the long run
|
||||||
|
(especially for non-active extents). Lower value may reduce
|
||||||
|
fragmentation, at the cost of extra active extents. The default value
|
||||||
|
is 6, which gives a maximum ratio of 64 (2^6).</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry id="opt.stats_print">
|
<varlistentry id="opt.stats_print">
|
||||||
<term>
|
<term>
|
||||||
<mallctl>opt.stats_print</mallctl>
|
<mallctl>opt.stats_print</mallctl>
|
||||||
|
@ -6,9 +6,11 @@
|
|||||||
#include "jemalloc/internal/ph.h"
|
#include "jemalloc/internal/ph.h"
|
||||||
#include "jemalloc/internal/rtree.h"
|
#include "jemalloc/internal/rtree.h"
|
||||||
|
|
||||||
extern rtree_t extents_rtree;
|
extern size_t opt_lg_extent_max_active_fit;
|
||||||
extern const extent_hooks_t extent_hooks_default;
|
|
||||||
extern mutex_pool_t extent_mutex_pool;
|
extern rtree_t extents_rtree;
|
||||||
|
extern const extent_hooks_t extent_hooks_default;
|
||||||
|
extern mutex_pool_t extent_mutex_pool;
|
||||||
|
|
||||||
extent_t *extent_alloc(tsdn_t *tsdn, arena_t *arena);
|
extent_t *extent_alloc(tsdn_t *tsdn, arena_t *arena);
|
||||||
void extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent);
|
void extent_dalloc(tsdn_t *tsdn, arena_t *arena, extent_t *extent);
|
||||||
|
@ -8,4 +8,10 @@ typedef struct extents_s extents_t;
|
|||||||
|
|
||||||
#define EXTENT_GROW_MAX_PIND (NPSIZES - 1)
|
#define EXTENT_GROW_MAX_PIND (NPSIZES - 1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When reuse (and split) an active extent, (1U << opt_lg_extent_max_active_fit)
|
||||||
|
* is the max ratio between the size of the active extent and the new extent.
|
||||||
|
*/
|
||||||
|
#define LG_EXTENT_MAX_ACTIVE_FIT_DEFAULT 6
|
||||||
|
|
||||||
#endif /* JEMALLOC_INTERNAL_EXTENT_TYPES_H */
|
#endif /* JEMALLOC_INTERNAL_EXTENT_TYPES_H */
|
||||||
|
@ -95,6 +95,7 @@ CTL_PROTO(opt_zero)
|
|||||||
CTL_PROTO(opt_utrace)
|
CTL_PROTO(opt_utrace)
|
||||||
CTL_PROTO(opt_xmalloc)
|
CTL_PROTO(opt_xmalloc)
|
||||||
CTL_PROTO(opt_tcache)
|
CTL_PROTO(opt_tcache)
|
||||||
|
CTL_PROTO(opt_lg_extent_max_active_fit)
|
||||||
CTL_PROTO(opt_lg_tcache_max)
|
CTL_PROTO(opt_lg_tcache_max)
|
||||||
CTL_PROTO(opt_prof)
|
CTL_PROTO(opt_prof)
|
||||||
CTL_PROTO(opt_prof_prefix)
|
CTL_PROTO(opt_prof_prefix)
|
||||||
@ -293,6 +294,7 @@ static const ctl_named_node_t opt_node[] = {
|
|||||||
{NAME("utrace"), CTL(opt_utrace)},
|
{NAME("utrace"), CTL(opt_utrace)},
|
||||||
{NAME("xmalloc"), CTL(opt_xmalloc)},
|
{NAME("xmalloc"), CTL(opt_xmalloc)},
|
||||||
{NAME("tcache"), CTL(opt_tcache)},
|
{NAME("tcache"), CTL(opt_tcache)},
|
||||||
|
{NAME("lg_extent_max_active_fit"), CTL(opt_lg_extent_max_active_fit)},
|
||||||
{NAME("lg_tcache_max"), CTL(opt_lg_tcache_max)},
|
{NAME("lg_tcache_max"), CTL(opt_lg_tcache_max)},
|
||||||
{NAME("prof"), CTL(opt_prof)},
|
{NAME("prof"), CTL(opt_prof)},
|
||||||
{NAME("prof_prefix"), CTL(opt_prof_prefix)},
|
{NAME("prof_prefix"), CTL(opt_prof_prefix)},
|
||||||
@ -1597,6 +1599,8 @@ CTL_RO_NL_CGEN(config_fill, opt_zero, opt_zero, bool)
|
|||||||
CTL_RO_NL_CGEN(config_utrace, opt_utrace, opt_utrace, bool)
|
CTL_RO_NL_CGEN(config_utrace, opt_utrace, opt_utrace, bool)
|
||||||
CTL_RO_NL_CGEN(config_xmalloc, opt_xmalloc, opt_xmalloc, bool)
|
CTL_RO_NL_CGEN(config_xmalloc, opt_xmalloc, opt_xmalloc, bool)
|
||||||
CTL_RO_NL_GEN(opt_tcache, opt_tcache, bool)
|
CTL_RO_NL_GEN(opt_tcache, opt_tcache, bool)
|
||||||
|
CTL_RO_NL_GEN(opt_lg_extent_max_active_fit, opt_lg_extent_max_active_fit,
|
||||||
|
size_t)
|
||||||
CTL_RO_NL_GEN(opt_lg_tcache_max, opt_lg_tcache_max, ssize_t)
|
CTL_RO_NL_GEN(opt_lg_tcache_max, opt_lg_tcache_max, ssize_t)
|
||||||
CTL_RO_NL_CGEN(config_prof, opt_prof, opt_prof, bool)
|
CTL_RO_NL_CGEN(config_prof, opt_prof, opt_prof, bool)
|
||||||
CTL_RO_NL_CGEN(config_prof, opt_prof_prefix, opt_prof_prefix, const char *)
|
CTL_RO_NL_CGEN(config_prof, opt_prof_prefix, opt_prof_prefix, const char *)
|
||||||
|
@ -17,6 +17,8 @@ rtree_t extents_rtree;
|
|||||||
/* Keyed by the address of the extent_t being protected. */
|
/* Keyed by the address of the extent_t being protected. */
|
||||||
mutex_pool_t extent_mutex_pool;
|
mutex_pool_t extent_mutex_pool;
|
||||||
|
|
||||||
|
size_t opt_lg_extent_max_active_fit = LG_EXTENT_MAX_ACTIVE_FIT_DEFAULT;
|
||||||
|
|
||||||
static const bitmap_info_t extents_bitmap_info =
|
static const bitmap_info_t extents_bitmap_info =
|
||||||
BITMAP_INFO_INITIALIZER(NPSIZES+1);
|
BITMAP_INFO_INITIALIZER(NPSIZES+1);
|
||||||
|
|
||||||
@ -369,6 +371,13 @@ extents_best_fit_locked(tsdn_t *tsdn, arena_t *arena, extents_t *extents,
|
|||||||
pszind_t i = (pszind_t)bitmap_ffu(extents->bitmap, &extents_bitmap_info,
|
pszind_t i = (pszind_t)bitmap_ffu(extents->bitmap, &extents_bitmap_info,
|
||||||
(size_t)pind);
|
(size_t)pind);
|
||||||
if (i < NPSIZES+1) {
|
if (i < NPSIZES+1) {
|
||||||
|
/*
|
||||||
|
* In order to reduce fragmentation, avoid reusing and splitting
|
||||||
|
* large extents for much smaller sizes.
|
||||||
|
*/
|
||||||
|
if ((sz_pind2sz(i) >> opt_lg_extent_max_active_fit) > size) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
assert(!extent_heap_empty(&extents->heaps[i]));
|
assert(!extent_heap_empty(&extents->heaps[i]));
|
||||||
extent_t *extent = extent_heap_first(&extents->heaps[i]);
|
extent_t *extent = extent_heap_first(&extents->heaps[i]);
|
||||||
assert(extent_size_get(extent) >= size);
|
assert(extent_size_get(extent) >= size);
|
||||||
|
@ -1146,6 +1146,9 @@ malloc_conf_init(void) {
|
|||||||
CONF_HANDLE_BOOL(opt_xmalloc, "xmalloc")
|
CONF_HANDLE_BOOL(opt_xmalloc, "xmalloc")
|
||||||
}
|
}
|
||||||
CONF_HANDLE_BOOL(opt_tcache, "tcache")
|
CONF_HANDLE_BOOL(opt_tcache, "tcache")
|
||||||
|
CONF_HANDLE_SIZE_T(opt_lg_extent_max_active_fit,
|
||||||
|
"lg_extent_max_active_fit", 0,
|
||||||
|
(sizeof(size_t) << 3), yes, yes, false)
|
||||||
CONF_HANDLE_SSIZE_T(opt_lg_tcache_max, "lg_tcache_max",
|
CONF_HANDLE_SSIZE_T(opt_lg_tcache_max, "lg_tcache_max",
|
||||||
-1, (sizeof(size_t) << 3) - 1)
|
-1, (sizeof(size_t) << 3) - 1)
|
||||||
if (strncmp("percpu_arena", k, klen) == 0) {
|
if (strncmp("percpu_arena", k, klen) == 0) {
|
||||||
|
@ -172,6 +172,7 @@ TEST_BEGIN(test_mallctl_opt) {
|
|||||||
TEST_MALLCTL_OPT(bool, utrace, utrace);
|
TEST_MALLCTL_OPT(bool, utrace, utrace);
|
||||||
TEST_MALLCTL_OPT(bool, xmalloc, xmalloc);
|
TEST_MALLCTL_OPT(bool, xmalloc, xmalloc);
|
||||||
TEST_MALLCTL_OPT(bool, tcache, always);
|
TEST_MALLCTL_OPT(bool, tcache, always);
|
||||||
|
TEST_MALLCTL_OPT(size_t, lg_extent_max_active_fit, always);
|
||||||
TEST_MALLCTL_OPT(size_t, lg_tcache_max, always);
|
TEST_MALLCTL_OPT(size_t, lg_tcache_max, always);
|
||||||
TEST_MALLCTL_OPT(bool, prof, prof);
|
TEST_MALLCTL_OPT(bool, prof, prof);
|
||||||
TEST_MALLCTL_OPT(const char *, prof_prefix, prof);
|
TEST_MALLCTL_OPT(const char *, prof_prefix, prof);
|
||||||
|
Loading…
Reference in New Issue
Block a user