Track the leaked VM space via the abandoned_vm counter.
The counter is 0 unless metadata allocation failed (indicates OOM), and is mainly for sanity checking.
This commit is contained in:
parent
42807fcd9e
commit
4e36ce34c1
@ -112,6 +112,9 @@ struct arena_stats_s {
|
|||||||
arena_stats_u64_t nflushes_large; /* Derived. */
|
arena_stats_u64_t nflushes_large; /* Derived. */
|
||||||
arena_stats_u64_t nrequests_large; /* Derived. */
|
arena_stats_u64_t nrequests_large; /* Derived. */
|
||||||
|
|
||||||
|
/* VM space had to be leaked (undocumented). Normally 0. */
|
||||||
|
atomic_zu_t abandoned_vm;
|
||||||
|
|
||||||
/* Number of bytes cached in tcache associated with this arena. */
|
/* Number of bytes cached in tcache associated with this arena. */
|
||||||
atomic_zu_t tcache_bytes; /* Derived. */
|
atomic_zu_t tcache_bytes; /* Derived. */
|
||||||
|
|
||||||
|
@ -132,6 +132,8 @@ arena_stats_merge(tsdn_t *tsdn, arena_t *arena, unsigned *nthreads,
|
|||||||
(((atomic_load_zu(&arena->nactive, ATOMIC_RELAXED) +
|
(((atomic_load_zu(&arena->nactive, ATOMIC_RELAXED) +
|
||||||
extents_npages_get(&arena->extents_dirty) +
|
extents_npages_get(&arena->extents_dirty) +
|
||||||
extents_npages_get(&arena->extents_muzzy)) << LG_PAGE)));
|
extents_npages_get(&arena->extents_muzzy)) << LG_PAGE)));
|
||||||
|
arena_stats_accum_zu(&astats->abandoned_vm, atomic_load_zu(
|
||||||
|
&arena->stats.abandoned_vm, ATOMIC_RELAXED));
|
||||||
|
|
||||||
for (szind_t i = 0; i < SC_NSIZES - SC_NBINS; i++) {
|
for (szind_t i = 0; i < SC_NSIZES - SC_NBINS; i++) {
|
||||||
uint64_t nmalloc = arena_stats_read_u64(tsdn, &arena->stats,
|
uint64_t nmalloc = arena_stats_read_u64(tsdn, &arena->stats,
|
||||||
|
@ -210,6 +210,7 @@ CTL_PROTO(stats_arenas_i_internal)
|
|||||||
CTL_PROTO(stats_arenas_i_metadata_thp)
|
CTL_PROTO(stats_arenas_i_metadata_thp)
|
||||||
CTL_PROTO(stats_arenas_i_tcache_bytes)
|
CTL_PROTO(stats_arenas_i_tcache_bytes)
|
||||||
CTL_PROTO(stats_arenas_i_resident)
|
CTL_PROTO(stats_arenas_i_resident)
|
||||||
|
CTL_PROTO(stats_arenas_i_abandoned_vm)
|
||||||
INDEX_PROTO(stats_arenas_i)
|
INDEX_PROTO(stats_arenas_i)
|
||||||
CTL_PROTO(stats_allocated)
|
CTL_PROTO(stats_allocated)
|
||||||
CTL_PROTO(stats_active)
|
CTL_PROTO(stats_active)
|
||||||
@ -543,6 +544,7 @@ static const ctl_named_node_t stats_arenas_i_node[] = {
|
|||||||
{NAME("metadata_thp"), CTL(stats_arenas_i_metadata_thp)},
|
{NAME("metadata_thp"), CTL(stats_arenas_i_metadata_thp)},
|
||||||
{NAME("tcache_bytes"), CTL(stats_arenas_i_tcache_bytes)},
|
{NAME("tcache_bytes"), CTL(stats_arenas_i_tcache_bytes)},
|
||||||
{NAME("resident"), CTL(stats_arenas_i_resident)},
|
{NAME("resident"), CTL(stats_arenas_i_resident)},
|
||||||
|
{NAME("abandoned_vm"), CTL(stats_arenas_i_abandoned_vm)},
|
||||||
{NAME("small"), CHILD(named, stats_arenas_i_small)},
|
{NAME("small"), CHILD(named, stats_arenas_i_small)},
|
||||||
{NAME("large"), CHILD(named, stats_arenas_i_large)},
|
{NAME("large"), CHILD(named, stats_arenas_i_large)},
|
||||||
{NAME("bins"), CHILD(indexed, stats_arenas_i_bins)},
|
{NAME("bins"), CHILD(indexed, stats_arenas_i_bins)},
|
||||||
@ -913,6 +915,8 @@ MUTEX_PROF_ARENA_MUTEXES
|
|||||||
&astats->astats.ndalloc_large);
|
&astats->astats.ndalloc_large);
|
||||||
ctl_accum_arena_stats_u64(&sdstats->astats.nrequests_large,
|
ctl_accum_arena_stats_u64(&sdstats->astats.nrequests_large,
|
||||||
&astats->astats.nrequests_large);
|
&astats->astats.nrequests_large);
|
||||||
|
accum_atomic_zu(&sdstats->astats.abandoned_vm,
|
||||||
|
&astats->astats.abandoned_vm);
|
||||||
|
|
||||||
accum_atomic_zu(&sdstats->astats.tcache_bytes,
|
accum_atomic_zu(&sdstats->astats.tcache_bytes,
|
||||||
&astats->astats.tcache_bytes);
|
&astats->astats.tcache_bytes);
|
||||||
@ -2871,6 +2875,9 @@ CTL_RO_CGEN(config_stats, stats_arenas_i_tcache_bytes,
|
|||||||
CTL_RO_CGEN(config_stats, stats_arenas_i_resident,
|
CTL_RO_CGEN(config_stats, stats_arenas_i_resident,
|
||||||
atomic_load_zu(&arenas_i(mib[2])->astats->astats.resident, ATOMIC_RELAXED),
|
atomic_load_zu(&arenas_i(mib[2])->astats->astats.resident, ATOMIC_RELAXED),
|
||||||
size_t)
|
size_t)
|
||||||
|
CTL_RO_CGEN(config_stats, stats_arenas_i_abandoned_vm,
|
||||||
|
atomic_load_zu(&arenas_i(mib[2])->astats->astats.abandoned_vm,
|
||||||
|
ATOMIC_RELAXED), size_t)
|
||||||
|
|
||||||
CTL_RO_CGEN(config_stats, stats_arenas_i_small_allocated,
|
CTL_RO_CGEN(config_stats, stats_arenas_i_small_allocated,
|
||||||
arenas_i(mib[2])->astats->allocated_small, size_t)
|
arenas_i(mib[2])->astats->allocated_small, size_t)
|
||||||
|
16
src/extent.c
16
src/extent.c
@ -619,16 +619,24 @@ label_return:
|
|||||||
return extent;
|
return extent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This can only happen when we fail to allocate a new extent struct (which
|
||||||
|
* indicates OOM), e.g. when trying to split an existing extent.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
extents_leak(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks,
|
extents_abandon_vm(tsdn_t *tsdn, arena_t *arena, extent_hooks_t **r_extent_hooks,
|
||||||
extents_t *extents, extent_t *extent, bool growing_retained) {
|
extents_t *extents, extent_t *extent, bool growing_retained) {
|
||||||
|
size_t sz = extent_size_get(extent);
|
||||||
|
if (config_stats) {
|
||||||
|
arena_stats_accum_zu(&arena->stats.abandoned_vm, sz);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Leak extent after making sure its pages have already been purged, so
|
* Leak extent after making sure its pages have already been purged, so
|
||||||
* that this is only a virtual memory leak.
|
* that this is only a virtual memory leak.
|
||||||
*/
|
*/
|
||||||
if (extents_state_get(extents) == extent_state_dirty) {
|
if (extents_state_get(extents) == extent_state_dirty) {
|
||||||
if (extent_purge_lazy_impl(tsdn, arena, r_extent_hooks,
|
if (extent_purge_lazy_impl(tsdn, arena, r_extent_hooks,
|
||||||
extent, 0, extent_size_get(extent), growing_retained)) {
|
extent, 0, sz, growing_retained)) {
|
||||||
extent_purge_forced_impl(tsdn, arena, r_extent_hooks,
|
extent_purge_forced_impl(tsdn, arena, r_extent_hooks,
|
||||||
extent, 0, extent_size_get(extent),
|
extent, 0, extent_size_get(extent),
|
||||||
growing_retained);
|
growing_retained);
|
||||||
@ -1083,7 +1091,7 @@ extent_recycle_split(tsdn_t *tsdn, arena_t *arena,
|
|||||||
if (to_leak != NULL) {
|
if (to_leak != NULL) {
|
||||||
void *leak = extent_base_get(to_leak);
|
void *leak = extent_base_get(to_leak);
|
||||||
extent_deregister_no_gdump_sub(tsdn, to_leak);
|
extent_deregister_no_gdump_sub(tsdn, to_leak);
|
||||||
extents_leak(tsdn, arena, r_extent_hooks, extents,
|
extents_abandon_vm(tsdn, arena, r_extent_hooks, extents,
|
||||||
to_leak, growing_retained);
|
to_leak, growing_retained);
|
||||||
assert(extent_lock_from_addr(tsdn, rtree_ctx, leak,
|
assert(extent_lock_from_addr(tsdn, rtree_ctx, leak,
|
||||||
false) == NULL);
|
false) == NULL);
|
||||||
@ -1382,7 +1390,7 @@ extent_grow_retained(tsdn_t *tsdn, arena_t *arena,
|
|||||||
}
|
}
|
||||||
if (to_leak != NULL) {
|
if (to_leak != NULL) {
|
||||||
extent_deregister_no_gdump_sub(tsdn, to_leak);
|
extent_deregister_no_gdump_sub(tsdn, to_leak);
|
||||||
extents_leak(tsdn, arena, r_extent_hooks,
|
extents_abandon_vm(tsdn, arena, r_extent_hooks,
|
||||||
&arena->extents_retained, to_leak, true);
|
&arena->extents_retained, to_leak, true);
|
||||||
}
|
}
|
||||||
goto label_err;
|
goto label_err;
|
||||||
|
@ -673,7 +673,7 @@ stats_arena_print(emitter_t *emitter, unsigned i, bool bins, bool large,
|
|||||||
size_t large_allocated;
|
size_t large_allocated;
|
||||||
uint64_t large_nmalloc, large_ndalloc, large_nrequests, large_nfills,
|
uint64_t large_nmalloc, large_ndalloc, large_nrequests, large_nfills,
|
||||||
large_nflushes;
|
large_nflushes;
|
||||||
size_t tcache_bytes;
|
size_t tcache_bytes, abandoned_vm;
|
||||||
uint64_t uptime;
|
uint64_t uptime;
|
||||||
|
|
||||||
CTL_GET("arenas.page", &page, size_t);
|
CTL_GET("arenas.page", &page, size_t);
|
||||||
@ -963,6 +963,7 @@ stats_arena_print(emitter_t *emitter, unsigned i, bool bins, bool large,
|
|||||||
GET_AND_EMIT_MEM_STAT(metadata_thp)
|
GET_AND_EMIT_MEM_STAT(metadata_thp)
|
||||||
GET_AND_EMIT_MEM_STAT(tcache_bytes)
|
GET_AND_EMIT_MEM_STAT(tcache_bytes)
|
||||||
GET_AND_EMIT_MEM_STAT(resident)
|
GET_AND_EMIT_MEM_STAT(resident)
|
||||||
|
GET_AND_EMIT_MEM_STAT(abandoned_vm)
|
||||||
GET_AND_EMIT_MEM_STAT(extent_avail)
|
GET_AND_EMIT_MEM_STAT(extent_avail)
|
||||||
#undef GET_AND_EMIT_MEM_STAT
|
#undef GET_AND_EMIT_MEM_STAT
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user