2017-01-20 13:41:41 +08:00
|
|
|
#define JEMALLOC_CTL_C_
|
2010-02-12 06:45:59 +08:00
|
|
|
#include "jemalloc/internal/jemalloc_internal.h"
|
2010-01-28 05:10:55 +08:00
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
/* Data. */
|
|
|
|
|
2010-11-25 07:44:21 +08:00
|
|
|
/*
|
|
|
|
* ctl_mtx protects the following:
|
2017-01-04 04:40:54 +08:00
|
|
|
* - ctl_stats->*
|
2010-11-25 07:44:21 +08:00
|
|
|
*/
|
2010-01-28 05:10:55 +08:00
|
|
|
static malloc_mutex_t ctl_mtx;
|
|
|
|
static bool ctl_initialized;
|
2017-01-04 04:40:54 +08:00
|
|
|
static ctl_stats_t *ctl_stats;
|
2017-01-19 15:03:37 +08:00
|
|
|
static ctl_arenas_t *ctl_arenas;
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2012-04-20 14:38:42 +08:00
|
|
|
/******************************************************************************/
|
|
|
|
/* Helpers for named and indexed nodes. */
|
|
|
|
|
2014-10-31 07:38:08 +08:00
|
|
|
JEMALLOC_INLINE_C const ctl_named_node_t *
|
2017-01-16 08:56:30 +08:00
|
|
|
ctl_named_node(const ctl_node_t *node) {
|
2012-04-20 14:38:42 +08:00
|
|
|
return ((node->named) ? (const ctl_named_node_t *)node : NULL);
|
|
|
|
}
|
|
|
|
|
2014-10-31 07:38:08 +08:00
|
|
|
JEMALLOC_INLINE_C const ctl_named_node_t *
|
2017-01-16 08:56:30 +08:00
|
|
|
ctl_named_children(const ctl_named_node_t *node, size_t index) {
|
2012-04-20 14:38:42 +08:00
|
|
|
const ctl_named_node_t *children = ctl_named_node(node->children);
|
|
|
|
|
|
|
|
return (children ? &children[index] : NULL);
|
|
|
|
}
|
|
|
|
|
2014-10-31 07:38:08 +08:00
|
|
|
JEMALLOC_INLINE_C const ctl_indexed_node_t *
|
2017-01-16 08:56:30 +08:00
|
|
|
ctl_indexed_node(const ctl_node_t *node) {
|
2014-10-04 01:16:09 +08:00
|
|
|
return (!node->named ? (const ctl_indexed_node_t *)node : NULL);
|
2012-04-20 14:38:42 +08:00
|
|
|
}
|
|
|
|
|
2010-01-28 05:10:55 +08:00
|
|
|
/******************************************************************************/
|
|
|
|
/* Function prototypes for non-inline static functions. */
|
|
|
|
|
2017-01-20 13:41:41 +08:00
|
|
|
#define CTL_PROTO(n) \
|
2016-04-14 14:36:15 +08:00
|
|
|
static int n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, \
|
|
|
|
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2017-01-20 13:41:41 +08:00
|
|
|
#define INDEX_PROTO(n) \
|
2016-05-11 13:21:10 +08:00
|
|
|
static const ctl_named_node_t *n##_index(tsdn_t *tsdn, \
|
2016-04-14 14:36:15 +08:00
|
|
|
const size_t *mib, size_t miblen, size_t i);
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2010-03-03 05:01:16 +08:00
|
|
|
CTL_PROTO(version)
|
2010-01-28 05:10:55 +08:00
|
|
|
CTL_PROTO(epoch)
|
2012-03-27 09:54:44 +08:00
|
|
|
CTL_PROTO(thread_tcache_enabled)
|
2012-03-17 08:09:32 +08:00
|
|
|
CTL_PROTO(thread_tcache_flush)
|
2014-08-19 07:22:13 +08:00
|
|
|
CTL_PROTO(thread_prof_name)
|
|
|
|
CTL_PROTO(thread_prof_active)
|
2010-08-14 06:42:29 +08:00
|
|
|
CTL_PROTO(thread_arena)
|
2010-10-21 08:39:18 +08:00
|
|
|
CTL_PROTO(thread_allocated)
|
2010-12-04 07:55:47 +08:00
|
|
|
CTL_PROTO(thread_allocatedp)
|
2010-10-21 08:39:18 +08:00
|
|
|
CTL_PROTO(thread_deallocated)
|
2010-12-04 07:55:47 +08:00
|
|
|
CTL_PROTO(thread_deallocatedp)
|
2015-07-18 07:38:25 +08:00
|
|
|
CTL_PROTO(config_cache_oblivious)
|
2010-01-28 05:10:55 +08:00
|
|
|
CTL_PROTO(config_debug)
|
|
|
|
CTL_PROTO(config_fill)
|
|
|
|
CTL_PROTO(config_lazy_lock)
|
2016-02-08 06:23:22 +08:00
|
|
|
CTL_PROTO(config_malloc_conf)
|
2012-04-17 08:52:27 +08:00
|
|
|
CTL_PROTO(config_munmap)
|
2010-02-12 05:19:21 +08:00
|
|
|
CTL_PROTO(config_prof)
|
|
|
|
CTL_PROTO(config_prof_libgcc)
|
|
|
|
CTL_PROTO(config_prof_libunwind)
|
2010-01-28 05:10:55 +08:00
|
|
|
CTL_PROTO(config_stats)
|
|
|
|
CTL_PROTO(config_tcache)
|
|
|
|
CTL_PROTO(config_tls)
|
2012-04-06 04:36:17 +08:00
|
|
|
CTL_PROTO(config_utrace)
|
2010-01-28 05:10:55 +08:00
|
|
|
CTL_PROTO(config_xmalloc)
|
|
|
|
CTL_PROTO(opt_abort)
|
2012-10-12 04:53:15 +08:00
|
|
|
CTL_PROTO(opt_dss)
|
2010-10-24 09:37:06 +08:00
|
|
|
CTL_PROTO(opt_narenas)
|
Implement per-CPU arena.
The new feature, opt.percpu_arena, determines thread-arena association
dynamically based CPU id. Three modes are supported: "percpu", "phycpu"
and disabled.
"percpu" uses the current core id (with help from sched_getcpu())
directly as the arena index, while "phycpu" will assign threads on the
same physical CPU to the same arena. In other words, "percpu" means # of
arenas == # of CPUs, while "phycpu" has # of arenas == 1/2 * (# of
CPUs). Note that no runtime check on whether hyper threading is enabled
is added yet.
When enabled, threads will be migrated between arenas when a CPU change
is detected. In the current design, to reduce overhead from reading CPU
id, each arena tracks the thread accessed most recently. When a new
thread comes in, we will read CPU id and update arena if necessary.
2017-02-03 09:02:05 +08:00
|
|
|
CTL_PROTO(opt_percpu_arena)
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
CTL_PROTO(opt_dirty_decay_time)
|
|
|
|
CTL_PROTO(opt_muzzy_decay_time)
|
2010-10-24 09:37:06 +08:00
|
|
|
CTL_PROTO(opt_stats_print)
|
2010-01-28 05:10:55 +08:00
|
|
|
CTL_PROTO(opt_junk)
|
2010-10-24 09:37:06 +08:00
|
|
|
CTL_PROTO(opt_zero)
|
2012-04-06 04:36:17 +08:00
|
|
|
CTL_PROTO(opt_utrace)
|
2010-01-28 05:10:55 +08:00
|
|
|
CTL_PROTO(opt_xmalloc)
|
2010-03-08 07:34:14 +08:00
|
|
|
CTL_PROTO(opt_tcache)
|
2012-04-05 07:16:09 +08:00
|
|
|
CTL_PROTO(opt_lg_tcache_max)
|
2010-02-12 05:19:21 +08:00
|
|
|
CTL_PROTO(opt_prof)
|
2010-10-24 09:37:06 +08:00
|
|
|
CTL_PROTO(opt_prof_prefix)
|
2010-04-01 09:43:24 +08:00
|
|
|
CTL_PROTO(opt_prof_active)
|
2014-10-04 14:25:30 +08:00
|
|
|
CTL_PROTO(opt_prof_thread_active_init)
|
2010-03-02 12:15:26 +08:00
|
|
|
CTL_PROTO(opt_lg_prof_sample)
|
2010-02-12 05:19:21 +08:00
|
|
|
CTL_PROTO(opt_lg_prof_interval)
|
2010-10-24 09:37:06 +08:00
|
|
|
CTL_PROTO(opt_prof_gdump)
|
2012-04-18 07:39:33 +08:00
|
|
|
CTL_PROTO(opt_prof_final)
|
2010-02-12 05:19:21 +08:00
|
|
|
CTL_PROTO(opt_prof_leak)
|
2010-10-03 06:18:50 +08:00
|
|
|
CTL_PROTO(opt_prof_accum)
|
2015-01-30 07:30:47 +08:00
|
|
|
CTL_PROTO(tcache_create)
|
|
|
|
CTL_PROTO(tcache_flush)
|
|
|
|
CTL_PROTO(tcache_destroy)
|
2017-01-05 02:21:53 +08:00
|
|
|
CTL_PROTO(arena_i_initialized)
|
2016-02-20 12:09:31 +08:00
|
|
|
CTL_PROTO(arena_i_decay)
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
CTL_PROTO(arena_i_purge)
|
2016-04-23 05:37:17 +08:00
|
|
|
CTL_PROTO(arena_i_reset)
|
2017-01-04 09:21:59 +08:00
|
|
|
CTL_PROTO(arena_i_destroy)
|
2012-10-12 04:53:15 +08:00
|
|
|
CTL_PROTO(arena_i_dss)
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
CTL_PROTO(arena_i_dirty_decay_time)
|
|
|
|
CTL_PROTO(arena_i_muzzy_decay_time)
|
2016-06-01 06:03:51 +08:00
|
|
|
CTL_PROTO(arena_i_extent_hooks)
|
2012-10-12 04:53:15 +08:00
|
|
|
INDEX_PROTO(arena_i)
|
2010-01-28 05:10:55 +08:00
|
|
|
CTL_PROTO(arenas_bin_i_size)
|
|
|
|
CTL_PROTO(arenas_bin_i_nregs)
|
2016-05-30 09:34:50 +08:00
|
|
|
CTL_PROTO(arenas_bin_i_slab_size)
|
2010-01-28 05:10:55 +08:00
|
|
|
INDEX_PROTO(arenas_bin_i)
|
2016-06-01 05:50:21 +08:00
|
|
|
CTL_PROTO(arenas_lextent_i_size)
|
|
|
|
INDEX_PROTO(arenas_lextent_i)
|
2010-01-28 05:10:55 +08:00
|
|
|
CTL_PROTO(arenas_narenas)
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
CTL_PROTO(arenas_dirty_decay_time)
|
|
|
|
CTL_PROTO(arenas_muzzy_decay_time)
|
2010-01-28 05:10:55 +08:00
|
|
|
CTL_PROTO(arenas_quantum)
|
2012-04-02 22:04:34 +08:00
|
|
|
CTL_PROTO(arenas_page)
|
2010-03-18 07:27:39 +08:00
|
|
|
CTL_PROTO(arenas_tcache_max)
|
2010-01-28 05:10:55 +08:00
|
|
|
CTL_PROTO(arenas_nbins)
|
2010-03-18 07:27:39 +08:00
|
|
|
CTL_PROTO(arenas_nhbins)
|
2016-06-01 05:50:21 +08:00
|
|
|
CTL_PROTO(arenas_nlextents)
|
2017-01-04 00:21:29 +08:00
|
|
|
CTL_PROTO(arenas_create)
|
2014-10-04 14:25:30 +08:00
|
|
|
CTL_PROTO(prof_thread_active_init)
|
2010-04-01 09:43:24 +08:00
|
|
|
CTL_PROTO(prof_active)
|
2010-02-12 05:19:21 +08:00
|
|
|
CTL_PROTO(prof_dump)
|
2015-01-26 13:16:57 +08:00
|
|
|
CTL_PROTO(prof_gdump)
|
2014-08-19 07:22:13 +08:00
|
|
|
CTL_PROTO(prof_reset)
|
2010-02-12 05:19:21 +08:00
|
|
|
CTL_PROTO(prof_interval)
|
2014-08-19 07:22:13 +08:00
|
|
|
CTL_PROTO(lg_prof_sample)
|
2010-01-28 05:10:55 +08:00
|
|
|
CTL_PROTO(stats_arenas_i_small_allocated)
|
|
|
|
CTL_PROTO(stats_arenas_i_small_nmalloc)
|
|
|
|
CTL_PROTO(stats_arenas_i_small_ndalloc)
|
2010-03-14 12:32:56 +08:00
|
|
|
CTL_PROTO(stats_arenas_i_small_nrequests)
|
2016-06-01 05:50:21 +08:00
|
|
|
CTL_PROTO(stats_arenas_i_large_allocated)
|
|
|
|
CTL_PROTO(stats_arenas_i_large_nmalloc)
|
|
|
|
CTL_PROTO(stats_arenas_i_large_ndalloc)
|
|
|
|
CTL_PROTO(stats_arenas_i_large_nrequests)
|
2010-03-14 12:32:56 +08:00
|
|
|
CTL_PROTO(stats_arenas_i_bins_j_nmalloc)
|
|
|
|
CTL_PROTO(stats_arenas_i_bins_j_ndalloc)
|
2010-01-28 05:10:55 +08:00
|
|
|
CTL_PROTO(stats_arenas_i_bins_j_nrequests)
|
2014-10-13 13:53:59 +08:00
|
|
|
CTL_PROTO(stats_arenas_i_bins_j_curregs)
|
2010-01-28 05:10:55 +08:00
|
|
|
CTL_PROTO(stats_arenas_i_bins_j_nfills)
|
|
|
|
CTL_PROTO(stats_arenas_i_bins_j_nflushes)
|
2016-05-30 09:34:50 +08:00
|
|
|
CTL_PROTO(stats_arenas_i_bins_j_nslabs)
|
|
|
|
CTL_PROTO(stats_arenas_i_bins_j_nreslabs)
|
|
|
|
CTL_PROTO(stats_arenas_i_bins_j_curslabs)
|
2010-01-28 05:10:55 +08:00
|
|
|
INDEX_PROTO(stats_arenas_i_bins_j)
|
2016-06-01 05:50:21 +08:00
|
|
|
CTL_PROTO(stats_arenas_i_lextents_j_nmalloc)
|
|
|
|
CTL_PROTO(stats_arenas_i_lextents_j_ndalloc)
|
|
|
|
CTL_PROTO(stats_arenas_i_lextents_j_nrequests)
|
|
|
|
CTL_PROTO(stats_arenas_i_lextents_j_curlextents)
|
|
|
|
INDEX_PROTO(stats_arenas_i_lextents_j)
|
2011-03-19 04:41:33 +08:00
|
|
|
CTL_PROTO(stats_arenas_i_nthreads)
|
2012-10-12 04:53:15 +08:00
|
|
|
CTL_PROTO(stats_arenas_i_dss)
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
CTL_PROTO(stats_arenas_i_dirty_decay_time)
|
|
|
|
CTL_PROTO(stats_arenas_i_muzzy_decay_time)
|
2010-01-28 05:10:55 +08:00
|
|
|
CTL_PROTO(stats_arenas_i_pactive)
|
|
|
|
CTL_PROTO(stats_arenas_i_pdirty)
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
CTL_PROTO(stats_arenas_i_pmuzzy)
|
2010-01-28 05:10:55 +08:00
|
|
|
CTL_PROTO(stats_arenas_i_mapped)
|
2016-05-04 13:11:35 +08:00
|
|
|
CTL_PROTO(stats_arenas_i_retained)
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
CTL_PROTO(stats_arenas_i_dirty_npurge)
|
|
|
|
CTL_PROTO(stats_arenas_i_dirty_nmadvise)
|
|
|
|
CTL_PROTO(stats_arenas_i_dirty_purged)
|
|
|
|
CTL_PROTO(stats_arenas_i_muzzy_npurge)
|
|
|
|
CTL_PROTO(stats_arenas_i_muzzy_nmadvise)
|
|
|
|
CTL_PROTO(stats_arenas_i_muzzy_purged)
|
2016-12-23 06:39:10 +08:00
|
|
|
CTL_PROTO(stats_arenas_i_base)
|
|
|
|
CTL_PROTO(stats_arenas_i_internal)
|
2016-04-23 09:37:44 +08:00
|
|
|
CTL_PROTO(stats_arenas_i_tcache_bytes)
|
2016-12-23 06:39:10 +08:00
|
|
|
CTL_PROTO(stats_arenas_i_resident)
|
2010-01-28 05:10:55 +08:00
|
|
|
INDEX_PROTO(stats_arenas_i)
|
|
|
|
CTL_PROTO(stats_allocated)
|
|
|
|
CTL_PROTO(stats_active)
|
2014-11-28 03:22:36 +08:00
|
|
|
CTL_PROTO(stats_metadata)
|
2015-03-24 08:25:57 +08:00
|
|
|
CTL_PROTO(stats_resident)
|
2010-01-28 05:10:55 +08:00
|
|
|
CTL_PROTO(stats_mapped)
|
2016-05-04 13:11:35 +08:00
|
|
|
CTL_PROTO(stats_retained)
|
2010-01-28 05:10:55 +08:00
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
/* mallctl tree. */
|
|
|
|
|
|
|
|
/* Maximum tree depth. */
|
2017-01-20 13:41:41 +08:00
|
|
|
#define CTL_MAX_DEPTH 6
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2017-01-20 13:41:41 +08:00
|
|
|
#define NAME(n) {true}, n
|
|
|
|
#define CHILD(t, c) \
|
2012-04-24 10:31:45 +08:00
|
|
|
sizeof(c##_node) / sizeof(ctl_##t##_node_t), \
|
|
|
|
(ctl_node_t *)c##_node, \
|
|
|
|
NULL
|
2017-01-20 13:41:41 +08:00
|
|
|
#define CTL(c) 0, NULL, c##_ctl
|
2010-01-28 05:10:55 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Only handles internal indexed nodes, since there are currently no external
|
|
|
|
* ones.
|
|
|
|
*/
|
2017-01-20 13:41:41 +08:00
|
|
|
#define INDEX(i) {false}, i##_index
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2014-08-19 07:22:13 +08:00
|
|
|
static const ctl_named_node_t thread_tcache_node[] = {
|
2012-03-27 09:54:44 +08:00
|
|
|
{NAME("enabled"), CTL(thread_tcache_enabled)},
|
2012-03-17 08:09:32 +08:00
|
|
|
{NAME("flush"), CTL(thread_tcache_flush)}
|
2010-01-28 05:10:55 +08:00
|
|
|
};
|
|
|
|
|
2014-08-19 07:22:13 +08:00
|
|
|
static const ctl_named_node_t thread_prof_node[] = {
|
|
|
|
{NAME("name"), CTL(thread_prof_name)},
|
|
|
|
{NAME("active"), CTL(thread_prof_active)}
|
|
|
|
};
|
|
|
|
|
2012-04-20 14:38:42 +08:00
|
|
|
static const ctl_named_node_t thread_node[] = {
|
2012-02-11 12:22:09 +08:00
|
|
|
{NAME("arena"), CTL(thread_arena)},
|
2010-10-21 08:39:18 +08:00
|
|
|
{NAME("allocated"), CTL(thread_allocated)},
|
2010-12-04 07:55:47 +08:00
|
|
|
{NAME("allocatedp"), CTL(thread_allocatedp)},
|
|
|
|
{NAME("deallocated"), CTL(thread_deallocated)},
|
2012-03-17 08:09:32 +08:00
|
|
|
{NAME("deallocatedp"), CTL(thread_deallocatedp)},
|
2014-08-19 07:22:13 +08:00
|
|
|
{NAME("tcache"), CHILD(named, thread_tcache)},
|
|
|
|
{NAME("prof"), CHILD(named, thread_prof)}
|
2010-08-14 06:42:29 +08:00
|
|
|
};
|
|
|
|
|
2012-04-20 14:38:42 +08:00
|
|
|
static const ctl_named_node_t config_node[] = {
|
2015-07-18 07:38:25 +08:00
|
|
|
{NAME("cache_oblivious"), CTL(config_cache_oblivious)},
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME("debug"), CTL(config_debug)},
|
|
|
|
{NAME("fill"), CTL(config_fill)},
|
|
|
|
{NAME("lazy_lock"), CTL(config_lazy_lock)},
|
2016-02-08 06:23:22 +08:00
|
|
|
{NAME("malloc_conf"), CTL(config_malloc_conf)},
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME("munmap"), CTL(config_munmap)},
|
|
|
|
{NAME("prof"), CTL(config_prof)},
|
|
|
|
{NAME("prof_libgcc"), CTL(config_prof_libgcc)},
|
|
|
|
{NAME("prof_libunwind"), CTL(config_prof_libunwind)},
|
|
|
|
{NAME("stats"), CTL(config_stats)},
|
|
|
|
{NAME("tcache"), CTL(config_tcache)},
|
|
|
|
{NAME("tls"), CTL(config_tls)},
|
|
|
|
{NAME("utrace"), CTL(config_utrace)},
|
|
|
|
{NAME("xmalloc"), CTL(config_xmalloc)}
|
2010-01-28 05:10:55 +08:00
|
|
|
};
|
|
|
|
|
2012-04-20 14:38:42 +08:00
|
|
|
static const ctl_named_node_t opt_node[] = {
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME("abort"), CTL(opt_abort)},
|
|
|
|
{NAME("dss"), CTL(opt_dss)},
|
|
|
|
{NAME("narenas"), CTL(opt_narenas)},
|
Implement per-CPU arena.
The new feature, opt.percpu_arena, determines thread-arena association
dynamically based CPU id. Three modes are supported: "percpu", "phycpu"
and disabled.
"percpu" uses the current core id (with help from sched_getcpu())
directly as the arena index, while "phycpu" will assign threads on the
same physical CPU to the same arena. In other words, "percpu" means # of
arenas == # of CPUs, while "phycpu" has # of arenas == 1/2 * (# of
CPUs). Note that no runtime check on whether hyper threading is enabled
is added yet.
When enabled, threads will be migrated between arenas when a CPU change
is detected. In the current design, to reduce overhead from reading CPU
id, each arena tracks the thread accessed most recently. When a new
thread comes in, we will read CPU id and update arena if necessary.
2017-02-03 09:02:05 +08:00
|
|
|
{NAME("percpu_arena"), CTL(opt_percpu_arena)},
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
{NAME("dirty_decay_time"), CTL(opt_dirty_decay_time)},
|
|
|
|
{NAME("muzzy_decay_time"), CTL(opt_muzzy_decay_time)},
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME("stats_print"), CTL(opt_stats_print)},
|
|
|
|
{NAME("junk"), CTL(opt_junk)},
|
|
|
|
{NAME("zero"), CTL(opt_zero)},
|
|
|
|
{NAME("utrace"), CTL(opt_utrace)},
|
|
|
|
{NAME("xmalloc"), CTL(opt_xmalloc)},
|
|
|
|
{NAME("tcache"), CTL(opt_tcache)},
|
|
|
|
{NAME("lg_tcache_max"), CTL(opt_lg_tcache_max)},
|
|
|
|
{NAME("prof"), CTL(opt_prof)},
|
|
|
|
{NAME("prof_prefix"), CTL(opt_prof_prefix)},
|
|
|
|
{NAME("prof_active"), CTL(opt_prof_active)},
|
2014-10-04 14:25:30 +08:00
|
|
|
{NAME("prof_thread_active_init"), CTL(opt_prof_thread_active_init)},
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME("lg_prof_sample"), CTL(opt_lg_prof_sample)},
|
|
|
|
{NAME("lg_prof_interval"), CTL(opt_lg_prof_interval)},
|
|
|
|
{NAME("prof_gdump"), CTL(opt_prof_gdump)},
|
|
|
|
{NAME("prof_final"), CTL(opt_prof_final)},
|
|
|
|
{NAME("prof_leak"), CTL(opt_prof_leak)},
|
|
|
|
{NAME("prof_accum"), CTL(opt_prof_accum)}
|
2010-01-28 05:10:55 +08:00
|
|
|
};
|
|
|
|
|
2015-01-30 07:30:47 +08:00
|
|
|
static const ctl_named_node_t tcache_node[] = {
|
|
|
|
{NAME("create"), CTL(tcache_create)},
|
|
|
|
{NAME("flush"), CTL(tcache_flush)},
|
|
|
|
{NAME("destroy"), CTL(tcache_destroy)}
|
|
|
|
};
|
|
|
|
|
2012-10-12 04:53:15 +08:00
|
|
|
static const ctl_named_node_t arena_i_node[] = {
|
2017-01-05 02:21:53 +08:00
|
|
|
{NAME("initialized"), CTL(arena_i_initialized)},
|
2016-02-20 12:09:31 +08:00
|
|
|
{NAME("decay"), CTL(arena_i_decay)},
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
{NAME("purge"), CTL(arena_i_purge)},
|
2016-04-23 05:37:17 +08:00
|
|
|
{NAME("reset"), CTL(arena_i_reset)},
|
2017-01-04 09:21:59 +08:00
|
|
|
{NAME("destroy"), CTL(arena_i_destroy)},
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME("dss"), CTL(arena_i_dss)},
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
{NAME("dirty_decay_time"), CTL(arena_i_dirty_decay_time)},
|
|
|
|
{NAME("muzzy_decay_time"), CTL(arena_i_muzzy_decay_time)},
|
2016-06-01 06:03:51 +08:00
|
|
|
{NAME("extent_hooks"), CTL(arena_i_extent_hooks)}
|
2012-10-12 04:53:15 +08:00
|
|
|
};
|
|
|
|
static const ctl_named_node_t super_arena_i_node[] = {
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME(""), CHILD(named, arena_i)}
|
2012-10-12 04:53:15 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static const ctl_indexed_node_t arena_node[] = {
|
|
|
|
{INDEX(arena_i)}
|
|
|
|
};
|
|
|
|
|
2012-04-20 14:38:42 +08:00
|
|
|
static const ctl_named_node_t arenas_bin_i_node[] = {
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME("size"), CTL(arenas_bin_i_size)},
|
|
|
|
{NAME("nregs"), CTL(arenas_bin_i_nregs)},
|
2016-05-30 09:34:50 +08:00
|
|
|
{NAME("slab_size"), CTL(arenas_bin_i_slab_size)}
|
2010-01-28 05:10:55 +08:00
|
|
|
};
|
2012-04-20 14:38:42 +08:00
|
|
|
static const ctl_named_node_t super_arenas_bin_i_node[] = {
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME(""), CHILD(named, arenas_bin_i)}
|
2010-01-28 05:10:55 +08:00
|
|
|
};
|
|
|
|
|
2012-04-20 14:38:42 +08:00
|
|
|
static const ctl_indexed_node_t arenas_bin_node[] = {
|
2010-01-28 05:10:55 +08:00
|
|
|
{INDEX(arenas_bin_i)}
|
|
|
|
};
|
|
|
|
|
2016-06-01 05:50:21 +08:00
|
|
|
static const ctl_named_node_t arenas_lextent_i_node[] = {
|
|
|
|
{NAME("size"), CTL(arenas_lextent_i_size)}
|
2014-10-13 13:53:59 +08:00
|
|
|
};
|
2016-06-01 05:50:21 +08:00
|
|
|
static const ctl_named_node_t super_arenas_lextent_i_node[] = {
|
|
|
|
{NAME(""), CHILD(named, arenas_lextent_i)}
|
2014-10-13 13:53:59 +08:00
|
|
|
};
|
|
|
|
|
2016-06-01 05:50:21 +08:00
|
|
|
static const ctl_indexed_node_t arenas_lextent_node[] = {
|
|
|
|
{INDEX(arenas_lextent_i)}
|
2014-10-13 13:53:59 +08:00
|
|
|
};
|
|
|
|
|
2012-04-20 14:38:42 +08:00
|
|
|
static const ctl_named_node_t arenas_node[] = {
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME("narenas"), CTL(arenas_narenas)},
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
{NAME("dirty_decay_time"), CTL(arenas_dirty_decay_time)},
|
|
|
|
{NAME("muzzy_decay_time"), CTL(arenas_muzzy_decay_time)},
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME("quantum"), CTL(arenas_quantum)},
|
|
|
|
{NAME("page"), CTL(arenas_page)},
|
|
|
|
{NAME("tcache_max"), CTL(arenas_tcache_max)},
|
|
|
|
{NAME("nbins"), CTL(arenas_nbins)},
|
|
|
|
{NAME("nhbins"), CTL(arenas_nhbins)},
|
|
|
|
{NAME("bin"), CHILD(indexed, arenas_bin)},
|
2016-06-01 05:50:21 +08:00
|
|
|
{NAME("nlextents"), CTL(arenas_nlextents)},
|
|
|
|
{NAME("lextent"), CHILD(indexed, arenas_lextent)},
|
2017-01-04 00:21:29 +08:00
|
|
|
{NAME("create"), CTL(arenas_create)}
|
2010-01-28 05:10:55 +08:00
|
|
|
};
|
|
|
|
|
2012-04-20 14:38:42 +08:00
|
|
|
static const ctl_named_node_t prof_node[] = {
|
2014-10-04 14:25:30 +08:00
|
|
|
{NAME("thread_active_init"), CTL(prof_thread_active_init)},
|
2010-04-01 09:43:24 +08:00
|
|
|
{NAME("active"), CTL(prof_active)},
|
2010-02-12 05:19:21 +08:00
|
|
|
{NAME("dump"), CTL(prof_dump)},
|
2015-01-26 13:16:57 +08:00
|
|
|
{NAME("gdump"), CTL(prof_gdump)},
|
2014-08-19 07:22:13 +08:00
|
|
|
{NAME("reset"), CTL(prof_reset)},
|
|
|
|
{NAME("interval"), CTL(prof_interval)},
|
|
|
|
{NAME("lg_sample"), CTL(lg_prof_sample)}
|
2010-02-12 05:19:21 +08:00
|
|
|
};
|
|
|
|
|
2012-04-20 14:38:42 +08:00
|
|
|
static const ctl_named_node_t stats_arenas_i_small_node[] = {
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME("allocated"), CTL(stats_arenas_i_small_allocated)},
|
|
|
|
{NAME("nmalloc"), CTL(stats_arenas_i_small_nmalloc)},
|
|
|
|
{NAME("ndalloc"), CTL(stats_arenas_i_small_ndalloc)},
|
|
|
|
{NAME("nrequests"), CTL(stats_arenas_i_small_nrequests)}
|
2010-01-28 05:10:55 +08:00
|
|
|
};
|
|
|
|
|
2016-06-01 05:50:21 +08:00
|
|
|
static const ctl_named_node_t stats_arenas_i_large_node[] = {
|
|
|
|
{NAME("allocated"), CTL(stats_arenas_i_large_allocated)},
|
|
|
|
{NAME("nmalloc"), CTL(stats_arenas_i_large_nmalloc)},
|
|
|
|
{NAME("ndalloc"), CTL(stats_arenas_i_large_ndalloc)},
|
|
|
|
{NAME("nrequests"), CTL(stats_arenas_i_large_nrequests)}
|
2014-05-16 13:22:27 +08:00
|
|
|
};
|
|
|
|
|
2012-04-20 14:38:42 +08:00
|
|
|
static const ctl_named_node_t stats_arenas_i_bins_j_node[] = {
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME("nmalloc"), CTL(stats_arenas_i_bins_j_nmalloc)},
|
|
|
|
{NAME("ndalloc"), CTL(stats_arenas_i_bins_j_ndalloc)},
|
|
|
|
{NAME("nrequests"), CTL(stats_arenas_i_bins_j_nrequests)},
|
|
|
|
{NAME("curregs"), CTL(stats_arenas_i_bins_j_curregs)},
|
|
|
|
{NAME("nfills"), CTL(stats_arenas_i_bins_j_nfills)},
|
|
|
|
{NAME("nflushes"), CTL(stats_arenas_i_bins_j_nflushes)},
|
2016-05-30 09:34:50 +08:00
|
|
|
{NAME("nslabs"), CTL(stats_arenas_i_bins_j_nslabs)},
|
|
|
|
{NAME("nreslabs"), CTL(stats_arenas_i_bins_j_nreslabs)},
|
|
|
|
{NAME("curslabs"), CTL(stats_arenas_i_bins_j_curslabs)}
|
2010-01-28 05:10:55 +08:00
|
|
|
};
|
2012-04-20 14:38:42 +08:00
|
|
|
static const ctl_named_node_t super_stats_arenas_i_bins_j_node[] = {
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME(""), CHILD(named, stats_arenas_i_bins_j)}
|
2010-01-28 05:10:55 +08:00
|
|
|
};
|
|
|
|
|
2012-04-20 14:38:42 +08:00
|
|
|
static const ctl_indexed_node_t stats_arenas_i_bins_node[] = {
|
2010-01-28 05:10:55 +08:00
|
|
|
{INDEX(stats_arenas_i_bins_j)}
|
|
|
|
};
|
|
|
|
|
2016-06-01 05:50:21 +08:00
|
|
|
static const ctl_named_node_t stats_arenas_i_lextents_j_node[] = {
|
|
|
|
{NAME("nmalloc"), CTL(stats_arenas_i_lextents_j_nmalloc)},
|
|
|
|
{NAME("ndalloc"), CTL(stats_arenas_i_lextents_j_ndalloc)},
|
|
|
|
{NAME("nrequests"), CTL(stats_arenas_i_lextents_j_nrequests)},
|
|
|
|
{NAME("curlextents"), CTL(stats_arenas_i_lextents_j_curlextents)}
|
2014-10-13 13:53:59 +08:00
|
|
|
};
|
2016-06-01 05:50:21 +08:00
|
|
|
static const ctl_named_node_t super_stats_arenas_i_lextents_j_node[] = {
|
|
|
|
{NAME(""), CHILD(named, stats_arenas_i_lextents_j)}
|
2014-10-13 13:53:59 +08:00
|
|
|
};
|
|
|
|
|
2016-06-01 05:50:21 +08:00
|
|
|
static const ctl_indexed_node_t stats_arenas_i_lextents_node[] = {
|
|
|
|
{INDEX(stats_arenas_i_lextents_j)}
|
2014-10-13 13:53:59 +08:00
|
|
|
};
|
|
|
|
|
2012-04-20 14:38:42 +08:00
|
|
|
static const ctl_named_node_t stats_arenas_i_node[] = {
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME("nthreads"), CTL(stats_arenas_i_nthreads)},
|
|
|
|
{NAME("dss"), CTL(stats_arenas_i_dss)},
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
{NAME("dirty_decay_time"), CTL(stats_arenas_i_dirty_decay_time)},
|
|
|
|
{NAME("muzzy_decay_time"), CTL(stats_arenas_i_muzzy_decay_time)},
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME("pactive"), CTL(stats_arenas_i_pactive)},
|
|
|
|
{NAME("pdirty"), CTL(stats_arenas_i_pdirty)},
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
{NAME("pmuzzy"), CTL(stats_arenas_i_pmuzzy)},
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME("mapped"), CTL(stats_arenas_i_mapped)},
|
2016-05-04 13:11:35 +08:00
|
|
|
{NAME("retained"), CTL(stats_arenas_i_retained)},
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
{NAME("dirty_npurge"), CTL(stats_arenas_i_dirty_npurge)},
|
|
|
|
{NAME("dirty_nmadvise"), CTL(stats_arenas_i_dirty_nmadvise)},
|
|
|
|
{NAME("dirty_purged"), CTL(stats_arenas_i_dirty_purged)},
|
|
|
|
{NAME("muzzy_npurge"), CTL(stats_arenas_i_muzzy_npurge)},
|
|
|
|
{NAME("muzzy_nmadvise"), CTL(stats_arenas_i_muzzy_nmadvise)},
|
|
|
|
{NAME("muzzy_purged"), CTL(stats_arenas_i_muzzy_purged)},
|
2016-12-23 06:39:10 +08:00
|
|
|
{NAME("base"), CTL(stats_arenas_i_base)},
|
|
|
|
{NAME("internal"), CTL(stats_arenas_i_internal)},
|
2016-04-23 09:37:44 +08:00
|
|
|
{NAME("tcache_bytes"), CTL(stats_arenas_i_tcache_bytes)},
|
2016-12-23 06:39:10 +08:00
|
|
|
{NAME("resident"), CTL(stats_arenas_i_resident)},
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME("small"), CHILD(named, stats_arenas_i_small)},
|
2016-06-01 05:50:21 +08:00
|
|
|
{NAME("large"), CHILD(named, stats_arenas_i_large)},
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME("bins"), CHILD(indexed, stats_arenas_i_bins)},
|
2016-06-01 05:50:21 +08:00
|
|
|
{NAME("lextents"), CHILD(indexed, stats_arenas_i_lextents)}
|
2010-01-28 05:10:55 +08:00
|
|
|
};
|
2012-04-20 14:38:42 +08:00
|
|
|
static const ctl_named_node_t super_stats_arenas_i_node[] = {
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME(""), CHILD(named, stats_arenas_i)}
|
2010-01-28 05:10:55 +08:00
|
|
|
};
|
|
|
|
|
2012-04-20 14:38:42 +08:00
|
|
|
static const ctl_indexed_node_t stats_arenas_node[] = {
|
2010-01-28 05:10:55 +08:00
|
|
|
{INDEX(stats_arenas_i)}
|
|
|
|
};
|
|
|
|
|
2012-04-20 14:38:42 +08:00
|
|
|
static const ctl_named_node_t stats_node[] = {
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME("allocated"), CTL(stats_allocated)},
|
|
|
|
{NAME("active"), CTL(stats_active)},
|
2014-11-28 03:22:36 +08:00
|
|
|
{NAME("metadata"), CTL(stats_metadata)},
|
2015-03-24 08:25:57 +08:00
|
|
|
{NAME("resident"), CTL(stats_resident)},
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME("mapped"), CTL(stats_mapped)},
|
2016-05-04 13:11:35 +08:00
|
|
|
{NAME("retained"), CTL(stats_retained)},
|
2014-10-13 13:53:59 +08:00
|
|
|
{NAME("arenas"), CHILD(indexed, stats_arenas)}
|
2010-01-28 05:10:55 +08:00
|
|
|
};
|
|
|
|
|
2012-04-20 14:38:42 +08:00
|
|
|
static const ctl_named_node_t root_node[] = {
|
2010-03-03 05:01:16 +08:00
|
|
|
{NAME("version"), CTL(version)},
|
2010-01-28 05:10:55 +08:00
|
|
|
{NAME("epoch"), CTL(epoch)},
|
2012-04-24 10:31:45 +08:00
|
|
|
{NAME("thread"), CHILD(named, thread)},
|
|
|
|
{NAME("config"), CHILD(named, config)},
|
|
|
|
{NAME("opt"), CHILD(named, opt)},
|
2015-01-30 07:30:47 +08:00
|
|
|
{NAME("tcache"), CHILD(named, tcache)},
|
2012-10-12 04:53:15 +08:00
|
|
|
{NAME("arena"), CHILD(indexed, arena)},
|
2012-04-24 10:31:45 +08:00
|
|
|
{NAME("arenas"), CHILD(named, arenas)},
|
|
|
|
{NAME("prof"), CHILD(named, prof)},
|
|
|
|
{NAME("stats"), CHILD(named, stats)}
|
2010-01-28 05:10:55 +08:00
|
|
|
};
|
2012-04-20 14:38:42 +08:00
|
|
|
static const ctl_named_node_t super_root_node[] = {
|
2012-04-24 10:31:45 +08:00
|
|
|
{NAME(""), CHILD(named, root)}
|
2010-01-28 05:10:55 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
#undef NAME
|
|
|
|
#undef CHILD
|
|
|
|
#undef CTL
|
|
|
|
#undef INDEX
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2017-03-09 07:56:31 +08:00
|
|
|
/*
|
|
|
|
* Sets *dst + *src non-atomically. This is safe, since everything is
|
|
|
|
* synchronized by the ctl mutex.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
accum_arena_stats_u64(arena_stats_u64_t *dst, arena_stats_u64_t *src) {
|
|
|
|
#ifdef JEMALLOC_ATOMIC_U64
|
|
|
|
uint64_t cur_dst = atomic_load_u64(dst, ATOMIC_RELAXED);
|
|
|
|
uint64_t cur_src = atomic_load_u64(src, ATOMIC_RELAXED);
|
|
|
|
atomic_store_u64(dst, cur_dst + cur_src, ATOMIC_RELAXED);
|
|
|
|
#else
|
|
|
|
*dst += *src;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Likewise: with ctl mutex synchronization, reading is simple. */
|
|
|
|
static uint64_t
|
|
|
|
arena_stats_read_u64(arena_stats_u64_t *p) {
|
|
|
|
#ifdef JEMALLOC_ATOMIC_U64
|
|
|
|
return atomic_load_u64(p, ATOMIC_RELAXED);
|
|
|
|
#else
|
|
|
|
return *p;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2017-03-14 07:18:40 +08:00
|
|
|
static void accum_atomic_zu(atomic_zu_t *dst, atomic_zu_t *src) {
|
|
|
|
size_t cur_dst = atomic_load_zu(dst, ATOMIC_RELAXED);
|
|
|
|
size_t cur_src = atomic_load_zu(src, ATOMIC_RELAXED);
|
|
|
|
atomic_store_zu(dst, cur_dst + cur_src, ATOMIC_RELAXED);
|
|
|
|
}
|
|
|
|
|
2017-03-09 07:56:31 +08:00
|
|
|
/******************************************************************************/
|
|
|
|
|
2017-01-03 23:27:42 +08:00
|
|
|
static unsigned
|
2017-01-16 08:56:30 +08:00
|
|
|
arenas_i2a_impl(size_t i, bool compat, bool validate) {
|
2017-01-03 23:27:42 +08:00
|
|
|
unsigned a;
|
|
|
|
|
|
|
|
switch (i) {
|
|
|
|
case MALLCTL_ARENAS_ALL:
|
|
|
|
a = 0;
|
|
|
|
break;
|
2017-01-04 09:21:59 +08:00
|
|
|
case MALLCTL_ARENAS_DESTROYED:
|
|
|
|
a = 1;
|
|
|
|
break;
|
2017-01-03 23:27:42 +08:00
|
|
|
default:
|
2017-01-19 15:03:37 +08:00
|
|
|
if (compat && i == ctl_arenas->narenas) {
|
2017-01-03 23:27:42 +08:00
|
|
|
/*
|
|
|
|
* Provide deprecated backward compatibility for
|
|
|
|
* accessing the merged stats at index narenas rather
|
|
|
|
* than via MALLCTL_ARENAS_ALL. This is scheduled for
|
|
|
|
* removal in 6.0.0.
|
|
|
|
*/
|
|
|
|
a = 0;
|
2017-01-16 08:56:30 +08:00
|
|
|
} else if (validate && i >= ctl_arenas->narenas) {
|
2017-01-03 23:27:42 +08:00
|
|
|
a = UINT_MAX;
|
2017-01-16 08:56:30 +08:00
|
|
|
} else {
|
2017-01-03 23:27:42 +08:00
|
|
|
/*
|
|
|
|
* This function should never be called for an index
|
|
|
|
* more than one past the range of indices that have
|
2017-01-19 15:03:37 +08:00
|
|
|
* initialized ctl data.
|
2017-01-03 23:27:42 +08:00
|
|
|
*/
|
2017-01-19 15:03:37 +08:00
|
|
|
assert(i < ctl_arenas->narenas || (!validate && i ==
|
|
|
|
ctl_arenas->narenas));
|
2017-01-04 09:21:59 +08:00
|
|
|
a = (unsigned)i + 2;
|
2017-01-03 23:27:42 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2017-01-20 10:15:45 +08:00
|
|
|
return a;
|
2017-01-03 23:27:42 +08:00
|
|
|
}
|
|
|
|
|
2017-01-04 09:21:59 +08:00
|
|
|
static unsigned
|
2017-01-16 08:56:30 +08:00
|
|
|
arenas_i2a(size_t i) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return arenas_i2a_impl(i, true, false);
|
2017-01-04 09:21:59 +08:00
|
|
|
}
|
|
|
|
|
2017-01-19 15:03:37 +08:00
|
|
|
static ctl_arena_t *
|
2017-01-16 08:56:30 +08:00
|
|
|
arenas_i_impl(tsdn_t *tsdn, size_t i, bool compat, bool init) {
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arena_t *ret;
|
2017-01-04 04:40:54 +08:00
|
|
|
|
|
|
|
assert(!compat || !init);
|
|
|
|
|
2017-01-19 15:03:37 +08:00
|
|
|
ret = ctl_arenas->arenas[arenas_i2a_impl(i, compat, false)];
|
2017-01-04 04:40:54 +08:00
|
|
|
if (init && ret == NULL) {
|
2017-01-19 15:03:37 +08:00
|
|
|
if (config_stats) {
|
|
|
|
struct container_s {
|
|
|
|
ctl_arena_t ctl_arena;
|
|
|
|
ctl_arena_stats_t astats;
|
|
|
|
};
|
|
|
|
struct container_s *cont =
|
|
|
|
(struct container_s *)base_alloc(tsdn, b0get(),
|
|
|
|
sizeof(struct container_s), QUANTUM);
|
|
|
|
if (cont == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
ret = &cont->ctl_arena;
|
|
|
|
ret->astats = &cont->astats;
|
|
|
|
} else {
|
|
|
|
ret = (ctl_arena_t *)base_alloc(tsdn, b0get(),
|
|
|
|
sizeof(ctl_arena_t), QUANTUM);
|
|
|
|
if (ret == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
2017-01-04 09:21:59 +08:00
|
|
|
ret->arena_ind = (unsigned)i;
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arenas->arenas[arenas_i2a_impl(i, compat, false)] = ret;
|
2017-01-04 04:40:54 +08:00
|
|
|
}
|
|
|
|
|
2017-01-19 15:03:37 +08:00
|
|
|
assert(ret == NULL || arenas_i2a(ret->arena_ind) == arenas_i2a(i));
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2017-01-04 04:40:54 +08:00
|
|
|
}
|
2017-01-03 23:27:42 +08:00
|
|
|
|
2017-01-19 15:03:37 +08:00
|
|
|
static ctl_arena_t *
|
2017-01-16 08:56:30 +08:00
|
|
|
arenas_i(size_t i) {
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arena_t *ret = arenas_i_impl(TSDN_NULL, i, true, false);
|
2017-01-04 04:40:54 +08:00
|
|
|
assert(ret != NULL);
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2017-01-03 23:27:42 +08:00
|
|
|
}
|
|
|
|
|
2010-01-28 05:10:55 +08:00
|
|
|
static void
|
2017-01-16 08:56:30 +08:00
|
|
|
ctl_arena_clear(ctl_arena_t *ctl_arena) {
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arena->nthreads = 0;
|
|
|
|
ctl_arena->dss = dss_prec_names[dss_prec_limit];
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
ctl_arena->dirty_decay_time = -1;
|
|
|
|
ctl_arena->muzzy_decay_time = -1;
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arena->pactive = 0;
|
|
|
|
ctl_arena->pdirty = 0;
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
ctl_arena->pmuzzy = 0;
|
2012-02-11 12:22:09 +08:00
|
|
|
if (config_stats) {
|
2017-01-19 15:03:37 +08:00
|
|
|
memset(&ctl_arena->astats->astats, 0, sizeof(arena_stats_t));
|
|
|
|
ctl_arena->astats->allocated_small = 0;
|
|
|
|
ctl_arena->astats->nmalloc_small = 0;
|
|
|
|
ctl_arena->astats->ndalloc_small = 0;
|
|
|
|
ctl_arena->astats->nrequests_small = 0;
|
|
|
|
memset(ctl_arena->astats->bstats, 0, NBINS *
|
|
|
|
sizeof(malloc_bin_stats_t));
|
|
|
|
memset(ctl_arena->astats->lstats, 0, (NSIZES - NBINS) *
|
2016-06-01 05:50:21 +08:00
|
|
|
sizeof(malloc_large_stats_t));
|
2012-02-11 12:22:09 +08:00
|
|
|
}
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
|
2010-03-14 12:32:56 +08:00
|
|
|
static void
|
2017-01-16 08:56:30 +08:00
|
|
|
ctl_arena_stats_amerge(tsdn_t *tsdn, ctl_arena_t *ctl_arena, arena_t *arena) {
|
2010-03-14 12:32:56 +08:00
|
|
|
unsigned i;
|
|
|
|
|
2016-02-28 12:40:13 +08:00
|
|
|
if (config_stats) {
|
2017-01-19 15:03:37 +08:00
|
|
|
arena_stats_merge(tsdn, arena, &ctl_arena->nthreads,
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
&ctl_arena->dss, &ctl_arena->dirty_decay_time,
|
|
|
|
&ctl_arena->muzzy_decay_time, &ctl_arena->pactive,
|
|
|
|
&ctl_arena->pdirty, &ctl_arena->pmuzzy,
|
2017-01-19 15:03:37 +08:00
|
|
|
&ctl_arena->astats->astats, ctl_arena->astats->bstats,
|
|
|
|
ctl_arena->astats->lstats);
|
2016-02-28 12:40:13 +08:00
|
|
|
|
|
|
|
for (i = 0; i < NBINS; i++) {
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arena->astats->allocated_small +=
|
|
|
|
ctl_arena->astats->bstats[i].curregs *
|
2016-02-28 12:40:13 +08:00
|
|
|
index2size(i);
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arena->astats->nmalloc_small +=
|
|
|
|
ctl_arena->astats->bstats[i].nmalloc;
|
|
|
|
ctl_arena->astats->ndalloc_small +=
|
|
|
|
ctl_arena->astats->bstats[i].ndalloc;
|
|
|
|
ctl_arena->astats->nrequests_small +=
|
|
|
|
ctl_arena->astats->bstats[i].nrequests;
|
2016-02-28 12:40:13 +08:00
|
|
|
}
|
|
|
|
} else {
|
2017-01-19 15:03:37 +08:00
|
|
|
arena_basic_stats_merge(tsdn, arena, &ctl_arena->nthreads,
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
&ctl_arena->dss, &ctl_arena->dirty_decay_time,
|
|
|
|
&ctl_arena->muzzy_decay_time, &ctl_arena->pactive,
|
|
|
|
&ctl_arena->pdirty, &ctl_arena->pmuzzy);
|
2010-03-14 12:32:56 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arena_stats_sdmerge(ctl_arena_t *ctl_sdarena, ctl_arena_t *ctl_arena,
|
2017-01-16 08:56:30 +08:00
|
|
|
bool destroyed) {
|
2010-03-14 12:32:56 +08:00
|
|
|
unsigned i;
|
|
|
|
|
2017-01-04 09:21:59 +08:00
|
|
|
if (!destroyed) {
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_sdarena->nthreads += ctl_arena->nthreads;
|
|
|
|
ctl_sdarena->pactive += ctl_arena->pactive;
|
|
|
|
ctl_sdarena->pdirty += ctl_arena->pdirty;
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
ctl_sdarena->pmuzzy += ctl_arena->pmuzzy;
|
2017-01-04 09:21:59 +08:00
|
|
|
} else {
|
2017-01-19 15:03:37 +08:00
|
|
|
assert(ctl_arena->nthreads == 0);
|
|
|
|
assert(ctl_arena->pactive == 0);
|
|
|
|
assert(ctl_arena->pdirty == 0);
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
assert(ctl_arena->pmuzzy == 0);
|
2017-01-04 09:21:59 +08:00
|
|
|
}
|
2010-03-14 12:32:56 +08:00
|
|
|
|
2016-02-28 12:40:13 +08:00
|
|
|
if (config_stats) {
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arena_stats_t *sdstats = ctl_sdarena->astats;
|
|
|
|
ctl_arena_stats_t *astats = ctl_arena->astats;
|
|
|
|
|
2017-01-04 09:21:59 +08:00
|
|
|
if (!destroyed) {
|
2017-03-14 07:18:40 +08:00
|
|
|
accum_atomic_zu(&sdstats->astats.mapped,
|
|
|
|
&astats->astats.mapped);
|
|
|
|
accum_atomic_zu(&sdstats->astats.retained,
|
|
|
|
&astats->astats.retained);
|
2017-01-04 09:21:59 +08:00
|
|
|
}
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
|
|
|
|
accum_arena_stats_u64(&sdstats->astats.decay_dirty.npurge,
|
|
|
|
&astats->astats.decay_dirty.npurge);
|
|
|
|
accum_arena_stats_u64(&sdstats->astats.decay_dirty.nmadvise,
|
|
|
|
&astats->astats.decay_dirty.nmadvise);
|
|
|
|
accum_arena_stats_u64(&sdstats->astats.decay_dirty.purged,
|
|
|
|
&astats->astats.decay_dirty.purged);
|
|
|
|
|
|
|
|
accum_arena_stats_u64(&sdstats->astats.decay_muzzy.npurge,
|
|
|
|
&astats->astats.decay_muzzy.npurge);
|
|
|
|
accum_arena_stats_u64(&sdstats->astats.decay_muzzy.nmadvise,
|
|
|
|
&astats->astats.decay_muzzy.nmadvise);
|
|
|
|
accum_arena_stats_u64(&sdstats->astats.decay_muzzy.purged,
|
|
|
|
&astats->astats.decay_muzzy.purged);
|
2017-01-04 09:21:59 +08:00
|
|
|
|
|
|
|
if (!destroyed) {
|
2017-03-14 07:18:40 +08:00
|
|
|
accum_atomic_zu(&sdstats->astats.base,
|
|
|
|
&astats->astats.base);
|
|
|
|
accum_atomic_zu(&sdstats->astats.internal,
|
|
|
|
&astats->astats.internal);
|
|
|
|
accum_atomic_zu(&sdstats->astats.resident,
|
|
|
|
&astats->astats.resident);
|
2017-01-16 08:56:30 +08:00
|
|
|
} else {
|
2017-03-14 07:18:40 +08:00
|
|
|
assert(atomic_load_zu(
|
|
|
|
&astats->astats.internal, ATOMIC_RELAXED) == 0);
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2017-01-04 09:21:59 +08:00
|
|
|
|
2017-01-16 08:56:30 +08:00
|
|
|
if (!destroyed) {
|
2017-01-04 09:21:59 +08:00
|
|
|
sdstats->allocated_small += astats->allocated_small;
|
2017-01-16 08:56:30 +08:00
|
|
|
} else {
|
2017-01-04 09:21:59 +08:00
|
|
|
assert(astats->allocated_small == 0);
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2017-01-04 09:21:59 +08:00
|
|
|
sdstats->nmalloc_small += astats->nmalloc_small;
|
|
|
|
sdstats->ndalloc_small += astats->ndalloc_small;
|
|
|
|
sdstats->nrequests_small += astats->nrequests_small;
|
|
|
|
|
|
|
|
if (!destroyed) {
|
2017-03-14 07:18:40 +08:00
|
|
|
accum_atomic_zu(&sdstats->astats.allocated_large,
|
|
|
|
&astats->astats.allocated_large);
|
2017-01-16 08:56:30 +08:00
|
|
|
} else {
|
2017-03-14 07:18:40 +08:00
|
|
|
assert(atomic_load_zu(&astats->astats.allocated_large,
|
|
|
|
ATOMIC_RELAXED) == 0);
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2017-03-09 07:56:31 +08:00
|
|
|
accum_arena_stats_u64(&sdstats->astats.nmalloc_large,
|
|
|
|
&astats->astats.nmalloc_large);
|
|
|
|
accum_arena_stats_u64(&sdstats->astats.ndalloc_large,
|
|
|
|
&astats->astats.ndalloc_large);
|
|
|
|
accum_arena_stats_u64(&sdstats->astats.nrequests_large,
|
|
|
|
&astats->astats.nrequests_large);
|
2016-02-28 12:40:13 +08:00
|
|
|
|
2016-04-23 09:37:44 +08:00
|
|
|
if (config_tcache) {
|
2017-03-14 07:18:40 +08:00
|
|
|
accum_atomic_zu(&sdstats->astats.tcache_bytes,
|
|
|
|
&astats->astats.tcache_bytes);
|
2016-04-23 09:37:44 +08:00
|
|
|
}
|
|
|
|
|
2016-02-28 12:40:13 +08:00
|
|
|
for (i = 0; i < NBINS; i++) {
|
2017-01-04 09:21:59 +08:00
|
|
|
sdstats->bstats[i].nmalloc += astats->bstats[i].nmalloc;
|
|
|
|
sdstats->bstats[i].ndalloc += astats->bstats[i].ndalloc;
|
|
|
|
sdstats->bstats[i].nrequests +=
|
2016-02-28 12:40:13 +08:00
|
|
|
astats->bstats[i].nrequests;
|
2017-01-04 09:21:59 +08:00
|
|
|
if (!destroyed) {
|
|
|
|
sdstats->bstats[i].curregs +=
|
|
|
|
astats->bstats[i].curregs;
|
2017-01-16 08:56:30 +08:00
|
|
|
} else {
|
2017-01-04 09:21:59 +08:00
|
|
|
assert(astats->bstats[i].curregs == 0);
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2016-02-28 12:40:13 +08:00
|
|
|
if (config_tcache) {
|
2017-01-04 09:21:59 +08:00
|
|
|
sdstats->bstats[i].nfills +=
|
2016-02-28 12:40:13 +08:00
|
|
|
astats->bstats[i].nfills;
|
2017-01-04 09:21:59 +08:00
|
|
|
sdstats->bstats[i].nflushes +=
|
2016-02-28 12:40:13 +08:00
|
|
|
astats->bstats[i].nflushes;
|
|
|
|
}
|
2017-01-04 09:21:59 +08:00
|
|
|
sdstats->bstats[i].nslabs += astats->bstats[i].nslabs;
|
|
|
|
sdstats->bstats[i].reslabs += astats->bstats[i].reslabs;
|
|
|
|
if (!destroyed) {
|
|
|
|
sdstats->bstats[i].curslabs +=
|
|
|
|
astats->bstats[i].curslabs;
|
2017-01-16 08:56:30 +08:00
|
|
|
} else {
|
2017-01-04 09:21:59 +08:00
|
|
|
assert(astats->bstats[i].curslabs == 0);
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2012-02-11 12:22:09 +08:00
|
|
|
}
|
2014-10-13 13:53:59 +08:00
|
|
|
|
2016-05-28 15:17:28 +08:00
|
|
|
for (i = 0; i < NSIZES - NBINS; i++) {
|
2017-03-09 07:56:31 +08:00
|
|
|
accum_arena_stats_u64(&sdstats->lstats[i].nmalloc,
|
|
|
|
&astats->lstats[i].nmalloc);
|
|
|
|
accum_arena_stats_u64(&sdstats->lstats[i].ndalloc,
|
|
|
|
&astats->lstats[i].ndalloc);
|
|
|
|
accum_arena_stats_u64(&sdstats->lstats[i].nrequests,
|
|
|
|
&astats->lstats[i].nrequests);
|
2017-01-04 09:21:59 +08:00
|
|
|
if (!destroyed) {
|
|
|
|
sdstats->lstats[i].curlextents +=
|
|
|
|
astats->lstats[i].curlextents;
|
2017-01-16 08:56:30 +08:00
|
|
|
} else {
|
2017-01-04 09:21:59 +08:00
|
|
|
assert(astats->lstats[i].curlextents == 0);
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2016-02-28 12:40:13 +08:00
|
|
|
}
|
2014-10-13 13:53:59 +08:00
|
|
|
}
|
2010-03-14 12:32:56 +08:00
|
|
|
}
|
|
|
|
|
2010-01-28 05:10:55 +08:00
|
|
|
static void
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arena_refresh(tsdn_t *tsdn, arena_t *arena, ctl_arena_t *ctl_sdarena,
|
2017-01-16 08:56:30 +08:00
|
|
|
unsigned i, bool destroyed) {
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arena_t *ctl_arena = arenas_i(i);
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arena_clear(ctl_arena);
|
|
|
|
ctl_arena_stats_amerge(tsdn, ctl_arena, arena);
|
2016-02-28 12:40:13 +08:00
|
|
|
/* Merge into sum stats as well. */
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arena_stats_sdmerge(ctl_sdarena, ctl_arena, destroyed);
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
|
2017-01-04 09:21:59 +08:00
|
|
|
static unsigned
|
2017-01-16 08:56:30 +08:00
|
|
|
ctl_arena_init(tsdn_t *tsdn, extent_hooks_t *extent_hooks) {
|
2017-01-04 09:21:59 +08:00
|
|
|
unsigned arena_ind;
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arena_t *ctl_arena;
|
2017-01-04 09:21:59 +08:00
|
|
|
|
2017-01-19 15:03:37 +08:00
|
|
|
if ((ctl_arena = ql_last(&ctl_arenas->destroyed, destroyed_link)) !=
|
|
|
|
NULL) {
|
|
|
|
ql_remove(&ctl_arenas->destroyed, ctl_arena, destroyed_link);
|
|
|
|
arena_ind = ctl_arena->arena_ind;
|
2017-01-16 08:56:30 +08:00
|
|
|
} else {
|
2017-01-19 15:03:37 +08:00
|
|
|
arena_ind = ctl_arenas->narenas;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2012-10-12 04:53:15 +08:00
|
|
|
|
2017-01-04 04:40:54 +08:00
|
|
|
/* Trigger stats allocation. */
|
2017-01-16 08:56:30 +08:00
|
|
|
if (arenas_i_impl(tsdn, arena_ind, false, true) == NULL) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return UINT_MAX;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2014-09-23 12:09:23 +08:00
|
|
|
|
2017-01-04 04:40:54 +08:00
|
|
|
/* Initialize new arena. */
|
2017-01-16 08:56:30 +08:00
|
|
|
if (arena_init(tsdn, arena_ind, extent_hooks) == NULL) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return UINT_MAX;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2012-10-12 04:53:15 +08:00
|
|
|
|
2017-01-16 08:56:30 +08:00
|
|
|
if (arena_ind == ctl_arenas->narenas) {
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arenas->narenas++;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2017-01-04 09:21:59 +08:00
|
|
|
|
2017-01-20 10:15:45 +08:00
|
|
|
return arena_ind;
|
2012-10-12 04:53:15 +08:00
|
|
|
}
|
|
|
|
|
2010-01-28 05:10:55 +08:00
|
|
|
static void
|
2017-01-16 08:56:30 +08:00
|
|
|
ctl_refresh(tsdn_t *tsdn) {
|
2010-01-28 05:10:55 +08:00
|
|
|
unsigned i;
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arena_t *ctl_sarena = arenas_i(MALLCTL_ARENAS_ALL);
|
|
|
|
VARIABLE_ARRAY(arena_t *, tarenas, ctl_arenas->narenas);
|
2010-01-28 05:10:55 +08:00
|
|
|
|
|
|
|
/*
|
2010-01-31 19:57:29 +08:00
|
|
|
* Clear sum stats, since they will be merged into by
|
2010-01-28 05:10:55 +08:00
|
|
|
* ctl_arena_refresh().
|
|
|
|
*/
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arena_clear(ctl_sarena);
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2017-01-19 15:03:37 +08:00
|
|
|
for (i = 0; i < ctl_arenas->narenas; i++) {
|
2016-05-11 13:21:10 +08:00
|
|
|
tarenas[i] = arena_get(tsdn, i, false);
|
2017-01-19 15:03:37 +08:00
|
|
|
}
|
Refactor/fix arenas manipulation.
Abstract arenas access to use arena_get() (or a0get() where appropriate)
rather than directly reading e.g. arenas[ind]. Prior to the addition of
the arenas.extend mallctl, the worst possible outcome of directly
accessing arenas was a stale read, but arenas.extend may allocate and
assign a new array to arenas.
Add a tsd-based arenas_cache, which amortizes arenas reads. This
introduces some subtle bootstrapping issues, with tsd_boot() now being
split into tsd_boot[01]() to support tsd wrapper allocation
bootstrapping, as well as an arenas_cache_bypass tsd variable which
dynamically terminates allocation of arenas_cache itself.
Promote a0malloc(), a0calloc(), and a0free() to be generally useful for
internal allocation, and use them in several places (more may be
appropriate).
Abstract arena->nthreads management and fix a missing decrement during
thread destruction (recent tsd refactoring left arenas_cleanup()
unused).
Change arena_choose() to propagate OOM, and handle OOM in all callers.
This is important for providing consistent allocation behavior when the
MALLOCX_ARENA() flag is being used. Prior to this fix, it was possible
for an OOM to result in allocation silently allocating from a different
arena than the one specified.
2014-10-08 14:14:57 +08:00
|
|
|
|
2017-01-19 15:03:37 +08:00
|
|
|
for (i = 0; i < ctl_arenas->narenas; i++) {
|
|
|
|
ctl_arena_t *ctl_arena = arenas_i(i);
|
2010-01-28 05:10:55 +08:00
|
|
|
bool initialized = (tarenas[i] != NULL);
|
|
|
|
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arena->initialized = initialized;
|
|
|
|
if (initialized) {
|
|
|
|
ctl_arena_refresh(tsdn, tarenas[i], ctl_sarena, i,
|
|
|
|
false);
|
|
|
|
}
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
|
2012-02-11 12:22:09 +08:00
|
|
|
if (config_stats) {
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_stats->allocated = ctl_sarena->astats->allocated_small +
|
2017-03-14 07:18:40 +08:00
|
|
|
atomic_load_zu(&ctl_sarena->astats->astats.allocated_large,
|
|
|
|
ATOMIC_RELAXED);
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_stats->active = (ctl_sarena->pactive << LG_PAGE);
|
2017-03-14 07:18:40 +08:00
|
|
|
ctl_stats->metadata = atomic_load_zu(
|
|
|
|
&ctl_sarena->astats->astats.base, ATOMIC_RELAXED) +
|
|
|
|
atomic_load_zu(&ctl_sarena->astats->astats.internal,
|
|
|
|
ATOMIC_RELAXED);
|
|
|
|
ctl_stats->resident = atomic_load_zu(
|
|
|
|
&ctl_sarena->astats->astats.resident, ATOMIC_RELAXED);
|
|
|
|
ctl_stats->mapped = atomic_load_zu(
|
|
|
|
&ctl_sarena->astats->astats.mapped, ATOMIC_RELAXED);
|
|
|
|
ctl_stats->retained = atomic_load_zu(
|
|
|
|
&ctl_sarena->astats->astats.retained, ATOMIC_RELAXED);
|
2012-02-11 12:22:09 +08:00
|
|
|
}
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arenas->epoch++;
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2017-01-16 08:56:30 +08:00
|
|
|
ctl_init(tsdn_t *tsdn) {
|
2010-11-25 07:44:21 +08:00
|
|
|
bool ret;
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_lock(tsdn, &ctl_mtx);
|
2014-10-04 01:16:09 +08:00
|
|
|
if (!ctl_initialized) {
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arena_t *ctl_sarena, *ctl_darena;
|
2017-01-04 04:40:54 +08:00
|
|
|
unsigned i;
|
|
|
|
|
2010-01-28 05:10:55 +08:00
|
|
|
/*
|
2017-01-19 15:03:37 +08:00
|
|
|
* Allocate demand-zeroed space for pointers to the full
|
|
|
|
* range of supported arena indices.
|
2010-01-28 05:10:55 +08:00
|
|
|
*/
|
2017-01-19 15:03:37 +08:00
|
|
|
if (ctl_arenas == NULL) {
|
|
|
|
ctl_arenas = (ctl_arenas_t *)base_alloc(tsdn,
|
|
|
|
b0get(), sizeof(ctl_arenas_t), QUANTUM);
|
|
|
|
if (ctl_arenas == NULL) {
|
|
|
|
ret = true;
|
|
|
|
goto label_return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config_stats && ctl_stats == NULL) {
|
2017-01-04 04:40:54 +08:00
|
|
|
ctl_stats = (ctl_stats_t *)base_alloc(tsdn, b0get(),
|
|
|
|
sizeof(ctl_stats_t), QUANTUM);
|
|
|
|
if (ctl_stats == NULL) {
|
|
|
|
ret = true;
|
|
|
|
goto label_return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-01-19 15:03:37 +08:00
|
|
|
* Allocate space for the current full range of arenas
|
|
|
|
* here rather than doing it lazily elsewhere, in order
|
|
|
|
* to limit when OOM-caused errors can occur.
|
2017-01-04 04:40:54 +08:00
|
|
|
*/
|
2017-01-19 15:03:37 +08:00
|
|
|
if ((ctl_sarena = arenas_i_impl(tsdn, MALLCTL_ARENAS_ALL, false,
|
|
|
|
true)) == NULL) {
|
2010-11-25 07:44:21 +08:00
|
|
|
ret = true;
|
2012-04-11 06:07:44 +08:00
|
|
|
goto label_return;
|
2010-11-25 07:44:21 +08:00
|
|
|
}
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_sarena->initialized = true;
|
2017-01-04 04:40:54 +08:00
|
|
|
|
2017-01-19 15:03:37 +08:00
|
|
|
if ((ctl_darena = arenas_i_impl(tsdn, MALLCTL_ARENAS_DESTROYED,
|
|
|
|
false, true)) == NULL) {
|
2017-01-04 09:21:59 +08:00
|
|
|
ret = true;
|
|
|
|
goto label_return;
|
|
|
|
}
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arena_clear(ctl_darena);
|
2017-01-04 09:21:59 +08:00
|
|
|
/*
|
2017-01-19 15:03:37 +08:00
|
|
|
* Don't toggle ctl_darena to initialized until an arena is
|
|
|
|
* actually destroyed, so that arena.<i>.initialized can be used
|
|
|
|
* to query whether the stats are relevant.
|
2017-01-04 09:21:59 +08:00
|
|
|
*/
|
|
|
|
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arenas->narenas = narenas_total_get();
|
|
|
|
for (i = 0; i < ctl_arenas->narenas; i++) {
|
|
|
|
if (arenas_i_impl(tsdn, i, false, true) == NULL) {
|
2017-01-04 04:40:54 +08:00
|
|
|
ret = true;
|
|
|
|
goto label_return;
|
|
|
|
}
|
|
|
|
}
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2017-01-19 15:03:37 +08:00
|
|
|
ql_new(&ctl_arenas->destroyed);
|
2016-05-11 13:21:10 +08:00
|
|
|
ctl_refresh(tsdn);
|
2017-01-19 15:03:37 +08:00
|
|
|
|
2010-01-28 05:10:55 +08:00
|
|
|
ctl_initialized = true;
|
|
|
|
}
|
|
|
|
|
2010-11-25 07:44:21 +08:00
|
|
|
ret = false;
|
2012-04-11 06:07:44 +08:00
|
|
|
label_return:
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_unlock(tsdn, &ctl_mtx);
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2016-05-11 13:21:10 +08:00
|
|
|
ctl_lookup(tsdn_t *tsdn, const char *name, ctl_node_t const **nodesp,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *mibp, size_t *depthp) {
|
2010-01-28 05:10:55 +08:00
|
|
|
int ret;
|
|
|
|
const char *elm, *tdot, *dot;
|
|
|
|
size_t elen, i, j;
|
2012-04-20 14:38:42 +08:00
|
|
|
const ctl_named_node_t *node;
|
2010-01-28 05:10:55 +08:00
|
|
|
|
|
|
|
elm = name;
|
|
|
|
/* Equivalent to strchrnul(). */
|
|
|
|
dot = ((tdot = strchr(elm, '.')) != NULL) ? tdot : strchr(elm, '\0');
|
|
|
|
elen = (size_t)((uintptr_t)dot - (uintptr_t)elm);
|
|
|
|
if (elen == 0) {
|
|
|
|
ret = ENOENT;
|
2012-04-11 06:07:44 +08:00
|
|
|
goto label_return;
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
node = super_root_node;
|
|
|
|
for (i = 0; i < *depthp; i++) {
|
2012-04-20 14:38:42 +08:00
|
|
|
assert(node);
|
|
|
|
assert(node->nchildren > 0);
|
|
|
|
if (ctl_named_node(node->children) != NULL) {
|
|
|
|
const ctl_named_node_t *pnode = node;
|
2010-01-28 05:10:55 +08:00
|
|
|
|
|
|
|
/* Children are named. */
|
2012-04-20 14:38:42 +08:00
|
|
|
for (j = 0; j < node->nchildren; j++) {
|
|
|
|
const ctl_named_node_t *child =
|
|
|
|
ctl_named_children(node, j);
|
|
|
|
if (strlen(child->name) == elen &&
|
|
|
|
strncmp(elm, child->name, elen) == 0) {
|
2010-01-28 05:10:55 +08:00
|
|
|
node = child;
|
2017-01-16 08:56:30 +08:00
|
|
|
if (nodesp != NULL) {
|
2012-04-20 14:38:42 +08:00
|
|
|
nodesp[i] =
|
|
|
|
(const ctl_node_t *)node;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2010-01-28 05:10:55 +08:00
|
|
|
mibp[i] = j;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (node == pnode) {
|
|
|
|
ret = ENOENT;
|
2012-04-11 06:07:44 +08:00
|
|
|
goto label_return;
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
} else {
|
2012-02-03 14:04:57 +08:00
|
|
|
uintmax_t index;
|
2012-04-20 14:38:42 +08:00
|
|
|
const ctl_indexed_node_t *inode;
|
2010-01-28 05:10:55 +08:00
|
|
|
|
|
|
|
/* Children are indexed. */
|
2012-02-03 14:04:57 +08:00
|
|
|
index = malloc_strtoumax(elm, NULL, 10);
|
|
|
|
if (index == UINTMAX_MAX || index > SIZE_T_MAX) {
|
2010-01-28 05:10:55 +08:00
|
|
|
ret = ENOENT;
|
2012-04-11 06:07:44 +08:00
|
|
|
goto label_return;
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
|
2012-04-20 14:38:42 +08:00
|
|
|
inode = ctl_indexed_node(node->children);
|
2016-05-11 13:21:10 +08:00
|
|
|
node = inode->index(tsdn, mibp, *depthp, (size_t)index);
|
2010-01-28 05:10:55 +08:00
|
|
|
if (node == NULL) {
|
|
|
|
ret = ENOENT;
|
2012-04-11 06:07:44 +08:00
|
|
|
goto label_return;
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
|
2017-01-16 08:56:30 +08:00
|
|
|
if (nodesp != NULL) {
|
2012-04-20 14:38:42 +08:00
|
|
|
nodesp[i] = (const ctl_node_t *)node;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2010-01-28 05:10:55 +08:00
|
|
|
mibp[i] = (size_t)index;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node->ctl != NULL) {
|
|
|
|
/* Terminal node. */
|
|
|
|
if (*dot != '\0') {
|
|
|
|
/*
|
|
|
|
* The name contains more elements than are
|
|
|
|
* in this path through the tree.
|
|
|
|
*/
|
|
|
|
ret = ENOENT;
|
2012-04-11 06:07:44 +08:00
|
|
|
goto label_return;
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
/* Complete lookup successful. */
|
|
|
|
*depthp = i + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update elm. */
|
|
|
|
if (*dot == '\0') {
|
|
|
|
/* No more elements. */
|
|
|
|
ret = ENOENT;
|
2012-04-11 06:07:44 +08:00
|
|
|
goto label_return;
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
elm = &dot[1];
|
|
|
|
dot = ((tdot = strchr(elm, '.')) != NULL) ? tdot :
|
|
|
|
strchr(elm, '\0');
|
|
|
|
elen = (size_t)((uintptr_t)dot - (uintptr_t)elm);
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
2012-04-11 06:07:44 +08:00
|
|
|
label_return:
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2016-04-14 14:36:15 +08:00
|
|
|
ctl_byname(tsd_t *tsd, const char *name, void *oldp, size_t *oldlenp,
|
2017-01-16 08:56:30 +08:00
|
|
|
void *newp, size_t newlen) {
|
2010-01-28 05:10:55 +08:00
|
|
|
int ret;
|
|
|
|
size_t depth;
|
|
|
|
ctl_node_t const *nodes[CTL_MAX_DEPTH];
|
|
|
|
size_t mib[CTL_MAX_DEPTH];
|
2012-04-20 14:38:42 +08:00
|
|
|
const ctl_named_node_t *node;
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2016-05-11 13:21:10 +08:00
|
|
|
if (!ctl_initialized && ctl_init(tsd_tsdn(tsd))) {
|
2010-01-28 05:10:55 +08:00
|
|
|
ret = EAGAIN;
|
2012-04-11 06:07:44 +08:00
|
|
|
goto label_return;
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
depth = CTL_MAX_DEPTH;
|
2016-05-11 13:21:10 +08:00
|
|
|
ret = ctl_lookup(tsd_tsdn(tsd), name, nodes, mib, &depth);
|
2017-01-16 08:56:30 +08:00
|
|
|
if (ret != 0) {
|
2012-04-11 06:07:44 +08:00
|
|
|
goto label_return;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2012-04-20 14:38:42 +08:00
|
|
|
node = ctl_named_node(nodes[depth-1]);
|
2017-01-16 08:56:30 +08:00
|
|
|
if (node != NULL && node->ctl) {
|
2016-04-14 14:36:15 +08:00
|
|
|
ret = node->ctl(tsd, mib, depth, oldp, oldlenp, newp, newlen);
|
2017-03-02 06:43:35 +08:00
|
|
|
} else {
|
2010-01-28 05:10:55 +08:00
|
|
|
/* The name refers to a partial path through the ctl tree. */
|
|
|
|
ret = ENOENT;
|
|
|
|
}
|
|
|
|
|
2012-04-11 06:07:44 +08:00
|
|
|
label_return:
|
2010-01-28 05:10:55 +08:00
|
|
|
return(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2017-01-16 08:56:30 +08:00
|
|
|
ctl_nametomib(tsdn_t *tsdn, const char *name, size_t *mibp, size_t *miblenp) {
|
2010-01-28 05:10:55 +08:00
|
|
|
int ret;
|
|
|
|
|
2016-05-11 13:21:10 +08:00
|
|
|
if (!ctl_initialized && ctl_init(tsdn)) {
|
2010-01-28 05:10:55 +08:00
|
|
|
ret = EAGAIN;
|
2012-04-11 06:07:44 +08:00
|
|
|
goto label_return;
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
|
2016-05-11 13:21:10 +08:00
|
|
|
ret = ctl_lookup(tsdn, name, NULL, mibp, miblenp);
|
2012-04-11 06:07:44 +08:00
|
|
|
label_return:
|
2010-01-28 05:10:55 +08:00
|
|
|
return(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2016-04-14 14:36:15 +08:00
|
|
|
ctl_bymib(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) {
|
2010-01-28 05:10:55 +08:00
|
|
|
int ret;
|
2012-04-20 14:38:42 +08:00
|
|
|
const ctl_named_node_t *node;
|
2010-01-28 05:10:55 +08:00
|
|
|
size_t i;
|
|
|
|
|
2016-05-11 13:21:10 +08:00
|
|
|
if (!ctl_initialized && ctl_init(tsd_tsdn(tsd))) {
|
2010-01-28 05:10:55 +08:00
|
|
|
ret = EAGAIN;
|
2012-04-11 06:07:44 +08:00
|
|
|
goto label_return;
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Iterate down the tree. */
|
|
|
|
node = super_root_node;
|
|
|
|
for (i = 0; i < miblen; i++) {
|
2012-04-20 14:38:42 +08:00
|
|
|
assert(node);
|
|
|
|
assert(node->nchildren > 0);
|
|
|
|
if (ctl_named_node(node->children) != NULL) {
|
2010-01-28 05:10:55 +08:00
|
|
|
/* Children are named. */
|
2017-01-04 23:51:49 +08:00
|
|
|
if (node->nchildren <= mib[i]) {
|
2010-01-28 05:10:55 +08:00
|
|
|
ret = ENOENT;
|
2012-04-11 06:07:44 +08:00
|
|
|
goto label_return;
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
2012-04-20 14:38:42 +08:00
|
|
|
node = ctl_named_children(node, mib[i]);
|
2010-01-28 05:10:55 +08:00
|
|
|
} else {
|
2012-04-20 14:38:42 +08:00
|
|
|
const ctl_indexed_node_t *inode;
|
2010-01-28 05:10:55 +08:00
|
|
|
|
|
|
|
/* Indexed element. */
|
2012-04-20 14:38:42 +08:00
|
|
|
inode = ctl_indexed_node(node->children);
|
2016-05-11 13:21:10 +08:00
|
|
|
node = inode->index(tsd_tsdn(tsd), mib, miblen, mib[i]);
|
2010-01-28 05:10:55 +08:00
|
|
|
if (node == NULL) {
|
|
|
|
ret = ENOENT;
|
2012-04-11 06:07:44 +08:00
|
|
|
goto label_return;
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Call the ctl function. */
|
2017-01-16 08:56:30 +08:00
|
|
|
if (node && node->ctl) {
|
2016-04-14 14:36:15 +08:00
|
|
|
ret = node->ctl(tsd, mib, miblen, oldp, oldlenp, newp, newlen);
|
2017-01-16 08:56:30 +08:00
|
|
|
} else {
|
2010-01-28 05:10:55 +08:00
|
|
|
/* Partial MIB. */
|
|
|
|
ret = ENOENT;
|
|
|
|
}
|
|
|
|
|
2012-04-11 06:07:44 +08:00
|
|
|
label_return:
|
2010-01-28 05:10:55 +08:00
|
|
|
return(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2017-01-16 08:56:30 +08:00
|
|
|
ctl_boot(void) {
|
|
|
|
if (malloc_mutex_init(&ctl_mtx, "ctl", WITNESS_RANK_CTL)) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return true;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2010-01-28 05:10:55 +08:00
|
|
|
|
|
|
|
ctl_initialized = false;
|
|
|
|
|
2017-01-20 10:15:45 +08:00
|
|
|
return false;
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
|
2012-10-10 05:46:22 +08:00
|
|
|
void
|
2017-01-16 08:56:30 +08:00
|
|
|
ctl_prefork(tsdn_t *tsdn) {
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_prefork(tsdn, &ctl_mtx);
|
2012-10-10 05:46:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-01-16 08:56:30 +08:00
|
|
|
ctl_postfork_parent(tsdn_t *tsdn) {
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_postfork_parent(tsdn, &ctl_mtx);
|
2012-10-10 05:46:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2017-01-16 08:56:30 +08:00
|
|
|
ctl_postfork_child(tsdn_t *tsdn) {
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_postfork_child(tsdn, &ctl_mtx);
|
2012-10-10 05:46:22 +08:00
|
|
|
}
|
|
|
|
|
2010-01-28 05:10:55 +08:00
|
|
|
/******************************************************************************/
|
|
|
|
/* *_ctl() functions. */
|
|
|
|
|
2017-01-20 13:41:41 +08:00
|
|
|
#define READONLY() do { \
|
2010-01-28 05:10:55 +08:00
|
|
|
if (newp != NULL || newlen != 0) { \
|
|
|
|
ret = EPERM; \
|
2012-04-26 04:12:46 +08:00
|
|
|
goto label_return; \
|
2010-01-28 05:10:55 +08:00
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2017-01-20 13:41:41 +08:00
|
|
|
#define WRITEONLY() do { \
|
2010-01-28 05:10:55 +08:00
|
|
|
if (oldp != NULL || oldlenp != NULL) { \
|
|
|
|
ret = EPERM; \
|
2012-04-26 04:12:46 +08:00
|
|
|
goto label_return; \
|
2010-01-28 05:10:55 +08:00
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2017-01-20 13:41:41 +08:00
|
|
|
#define READ_XOR_WRITE() do { \
|
2014-10-04 14:25:30 +08:00
|
|
|
if ((oldp != NULL && oldlenp != NULL) && (newp != NULL || \
|
|
|
|
newlen != 0)) { \
|
|
|
|
ret = EPERM; \
|
|
|
|
goto label_return; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2017-01-20 13:41:41 +08:00
|
|
|
#define READ(v, t) do { \
|
2010-01-28 05:10:55 +08:00
|
|
|
if (oldp != NULL && oldlenp != NULL) { \
|
|
|
|
if (*oldlenp != sizeof(t)) { \
|
|
|
|
size_t copylen = (sizeof(t) <= *oldlenp) \
|
|
|
|
? sizeof(t) : *oldlenp; \
|
2012-11-30 14:13:04 +08:00
|
|
|
memcpy(oldp, (void *)&(v), copylen); \
|
2010-01-28 05:10:55 +08:00
|
|
|
ret = EINVAL; \
|
2012-04-26 04:12:46 +08:00
|
|
|
goto label_return; \
|
Generalize chunk management hooks.
Add the "arena.<i>.chunk_hooks" mallctl, which replaces and expands on
the "arena.<i>.chunk.{alloc,dalloc,purge}" mallctls. The chunk hooks
allow control over chunk allocation/deallocation, decommit/commit,
purging, and splitting/merging, such that the application can rely on
jemalloc's internal chunk caching and retaining functionality, yet
implement a variety of chunk management mechanisms and policies.
Merge the chunks_[sz]ad_{mmap,dss} red-black trees into
chunks_[sz]ad_retained. This slightly reduces how hard jemalloc tries
to honor the dss precedence setting; prior to this change the precedence
setting was also consulted when recycling chunks.
Fix chunk purging. Don't purge chunks in arena_purge_stashed(); instead
deallocate them in arena_unstash_purged(), so that the dirty memory
linkage remains valid until after the last time it is used.
This resolves #176 and #201.
2015-07-28 23:28:19 +08:00
|
|
|
} \
|
|
|
|
*(t *)oldp = (v); \
|
2010-01-28 05:10:55 +08:00
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2017-01-20 13:41:41 +08:00
|
|
|
#define WRITE(v, t) do { \
|
2010-01-28 05:10:55 +08:00
|
|
|
if (newp != NULL) { \
|
|
|
|
if (newlen != sizeof(t)) { \
|
|
|
|
ret = EINVAL; \
|
2012-04-26 04:12:46 +08:00
|
|
|
goto label_return; \
|
2010-01-28 05:10:55 +08:00
|
|
|
} \
|
2012-11-30 14:13:04 +08:00
|
|
|
(v) = *(t *)newp; \
|
2010-01-28 05:10:55 +08:00
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2017-01-20 13:41:41 +08:00
|
|
|
#define MIB_UNSIGNED(v, i) do { \
|
2017-01-04 23:51:49 +08:00
|
|
|
if (mib[i] > UINT_MAX) { \
|
|
|
|
ret = EFAULT; \
|
|
|
|
goto label_return; \
|
|
|
|
} \
|
|
|
|
v = (unsigned)mib[i]; \
|
|
|
|
} while (0)
|
|
|
|
|
2012-02-11 12:22:09 +08:00
|
|
|
/*
|
|
|
|
* There's a lot of code duplication in the following macros due to limitations
|
|
|
|
* in how nested cpp macros are expanded.
|
|
|
|
*/
|
2017-01-20 13:41:41 +08:00
|
|
|
#define CTL_RO_CLGEN(c, l, n, v, t) \
|
2012-02-11 12:22:09 +08:00
|
|
|
static int \
|
2016-04-14 14:36:15 +08:00
|
|
|
n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) { \
|
2012-02-11 12:22:09 +08:00
|
|
|
int ret; \
|
|
|
|
t oldval; \
|
|
|
|
\
|
2017-01-16 08:56:30 +08:00
|
|
|
if (!(c)) { \
|
2017-01-20 10:15:45 +08:00
|
|
|
return ENOENT; \
|
2017-01-16 08:56:30 +08:00
|
|
|
} \
|
|
|
|
if (l) { \
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); \
|
2017-01-16 08:56:30 +08:00
|
|
|
} \
|
2012-02-11 12:22:09 +08:00
|
|
|
READONLY(); \
|
2012-11-30 14:13:04 +08:00
|
|
|
oldval = (v); \
|
2012-02-11 12:22:09 +08:00
|
|
|
READ(oldval, t); \
|
|
|
|
\
|
|
|
|
ret = 0; \
|
2012-04-26 04:12:46 +08:00
|
|
|
label_return: \
|
2017-01-16 08:56:30 +08:00
|
|
|
if (l) { \
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); \
|
2017-01-16 08:56:30 +08:00
|
|
|
} \
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret; \
|
2012-02-11 12:22:09 +08:00
|
|
|
}
|
|
|
|
|
2017-01-20 13:41:41 +08:00
|
|
|
#define CTL_RO_CGEN(c, n, v, t) \
|
2012-02-11 12:22:09 +08:00
|
|
|
static int \
|
2016-04-14 14:36:15 +08:00
|
|
|
n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) { \
|
2012-02-11 12:22:09 +08:00
|
|
|
int ret; \
|
|
|
|
t oldval; \
|
|
|
|
\
|
2017-01-16 08:56:30 +08:00
|
|
|
if (!(c)) { \
|
2017-01-20 10:15:45 +08:00
|
|
|
return ENOENT; \
|
2017-01-16 08:56:30 +08:00
|
|
|
} \
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); \
|
2012-02-11 12:22:09 +08:00
|
|
|
READONLY(); \
|
2012-11-30 14:13:04 +08:00
|
|
|
oldval = (v); \
|
2012-02-11 12:22:09 +08:00
|
|
|
READ(oldval, t); \
|
|
|
|
\
|
|
|
|
ret = 0; \
|
2012-04-26 04:12:46 +08:00
|
|
|
label_return: \
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); \
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret; \
|
2012-02-11 12:22:09 +08:00
|
|
|
}
|
|
|
|
|
2017-01-20 13:41:41 +08:00
|
|
|
#define CTL_RO_GEN(n, v, t) \
|
2010-01-28 05:10:55 +08:00
|
|
|
static int \
|
2016-04-14 14:36:15 +08:00
|
|
|
n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) { \
|
2010-11-25 07:44:21 +08:00
|
|
|
int ret; \
|
|
|
|
t oldval; \
|
|
|
|
\
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx); \
|
2010-11-25 07:44:21 +08:00
|
|
|
READONLY(); \
|
2012-11-30 14:13:04 +08:00
|
|
|
oldval = (v); \
|
2010-11-25 07:44:21 +08:00
|
|
|
READ(oldval, t); \
|
|
|
|
\
|
|
|
|
ret = 0; \
|
2012-04-26 04:12:46 +08:00
|
|
|
label_return: \
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx); \
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret; \
|
2010-11-25 07:44:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ctl_mtx is not acquired, under the assumption that no pertinent data will
|
|
|
|
* mutate during the call.
|
|
|
|
*/
|
2017-01-20 13:41:41 +08:00
|
|
|
#define CTL_RO_NL_CGEN(c, n, v, t) \
|
2010-11-25 07:44:21 +08:00
|
|
|
static int \
|
2016-04-14 14:36:15 +08:00
|
|
|
n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) { \
|
2010-01-28 05:10:55 +08:00
|
|
|
int ret; \
|
|
|
|
t oldval; \
|
|
|
|
\
|
2017-01-16 08:56:30 +08:00
|
|
|
if (!(c)) { \
|
2017-01-20 10:15:45 +08:00
|
|
|
return ENOENT; \
|
2017-01-16 08:56:30 +08:00
|
|
|
} \
|
2010-01-28 05:10:55 +08:00
|
|
|
READONLY(); \
|
2012-11-30 14:13:04 +08:00
|
|
|
oldval = (v); \
|
2010-01-28 05:10:55 +08:00
|
|
|
READ(oldval, t); \
|
|
|
|
\
|
|
|
|
ret = 0; \
|
2012-04-26 04:12:46 +08:00
|
|
|
label_return: \
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret; \
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
|
2017-01-20 13:41:41 +08:00
|
|
|
#define CTL_RO_NL_GEN(n, v, t) \
|
2010-01-28 05:10:55 +08:00
|
|
|
static int \
|
2016-04-14 14:36:15 +08:00
|
|
|
n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) { \
|
2010-01-28 05:10:55 +08:00
|
|
|
int ret; \
|
2012-02-11 12:22:09 +08:00
|
|
|
t oldval; \
|
2010-01-28 05:10:55 +08:00
|
|
|
\
|
|
|
|
READONLY(); \
|
2012-11-30 14:13:04 +08:00
|
|
|
oldval = (v); \
|
2012-02-11 12:22:09 +08:00
|
|
|
READ(oldval, t); \
|
2010-01-28 05:10:55 +08:00
|
|
|
\
|
|
|
|
ret = 0; \
|
2012-04-26 04:12:46 +08:00
|
|
|
label_return: \
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret; \
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
|
2017-01-20 13:41:41 +08:00
|
|
|
#define CTL_TSD_RO_NL_CGEN(c, n, m, t) \
|
2014-09-23 12:09:23 +08:00
|
|
|
static int \
|
2016-04-14 14:36:15 +08:00
|
|
|
n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) { \
|
2014-09-23 12:09:23 +08:00
|
|
|
int ret; \
|
|
|
|
t oldval; \
|
|
|
|
\
|
2017-01-16 08:56:30 +08:00
|
|
|
if (!(c)) { \
|
2017-01-20 10:15:45 +08:00
|
|
|
return ENOENT; \
|
2017-01-16 08:56:30 +08:00
|
|
|
} \
|
2014-09-23 12:09:23 +08:00
|
|
|
READONLY(); \
|
|
|
|
oldval = (m(tsd)); \
|
|
|
|
READ(oldval, t); \
|
|
|
|
\
|
|
|
|
ret = 0; \
|
|
|
|
label_return: \
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret; \
|
2014-09-23 12:09:23 +08:00
|
|
|
}
|
|
|
|
|
2017-01-20 13:41:41 +08:00
|
|
|
#define CTL_RO_CONFIG_GEN(n, t) \
|
2010-01-28 05:10:55 +08:00
|
|
|
static int \
|
2016-04-14 14:36:15 +08:00
|
|
|
n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp, \
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) { \
|
2010-01-28 05:10:55 +08:00
|
|
|
int ret; \
|
2016-02-08 06:23:22 +08:00
|
|
|
t oldval; \
|
2010-01-28 05:10:55 +08:00
|
|
|
\
|
|
|
|
READONLY(); \
|
2012-02-11 12:22:09 +08:00
|
|
|
oldval = n; \
|
2016-02-08 06:23:22 +08:00
|
|
|
READ(oldval, t); \
|
2010-01-28 05:10:55 +08:00
|
|
|
\
|
|
|
|
ret = 0; \
|
2012-04-26 04:12:46 +08:00
|
|
|
label_return: \
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret; \
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
|
2013-12-20 13:40:41 +08:00
|
|
|
/******************************************************************************/
|
|
|
|
|
2010-11-25 07:44:21 +08:00
|
|
|
CTL_RO_NL_GEN(version, JEMALLOC_VERSION, const char *)
|
2010-03-03 05:01:16 +08:00
|
|
|
|
2010-01-28 05:10:55 +08:00
|
|
|
static int
|
2016-04-14 14:36:15 +08:00
|
|
|
epoch_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) {
|
2010-01-28 05:10:55 +08:00
|
|
|
int ret;
|
2013-10-20 08:19:49 +08:00
|
|
|
UNUSED uint64_t newval;
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
|
2010-01-28 05:10:55 +08:00
|
|
|
WRITE(newval, uint64_t);
|
2017-01-16 08:56:30 +08:00
|
|
|
if (newp != NULL) {
|
2016-05-11 13:21:10 +08:00
|
|
|
ctl_refresh(tsd_tsdn(tsd));
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2017-01-19 15:03:37 +08:00
|
|
|
READ(ctl_arenas->epoch, uint64_t);
|
2010-01-28 05:10:55 +08:00
|
|
|
|
|
|
|
ret = 0;
|
2012-04-11 06:07:44 +08:00
|
|
|
label_return:
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
|
2013-12-20 13:40:41 +08:00
|
|
|
/******************************************************************************/
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2016-02-08 06:23:22 +08:00
|
|
|
CTL_RO_CONFIG_GEN(config_cache_oblivious, bool)
|
|
|
|
CTL_RO_CONFIG_GEN(config_debug, bool)
|
|
|
|
CTL_RO_CONFIG_GEN(config_fill, bool)
|
|
|
|
CTL_RO_CONFIG_GEN(config_lazy_lock, bool)
|
|
|
|
CTL_RO_CONFIG_GEN(config_malloc_conf, const char *)
|
|
|
|
CTL_RO_CONFIG_GEN(config_munmap, bool)
|
|
|
|
CTL_RO_CONFIG_GEN(config_prof, bool)
|
|
|
|
CTL_RO_CONFIG_GEN(config_prof_libgcc, bool)
|
|
|
|
CTL_RO_CONFIG_GEN(config_prof_libunwind, bool)
|
|
|
|
CTL_RO_CONFIG_GEN(config_stats, bool)
|
|
|
|
CTL_RO_CONFIG_GEN(config_tcache, bool)
|
|
|
|
CTL_RO_CONFIG_GEN(config_tls, bool)
|
|
|
|
CTL_RO_CONFIG_GEN(config_utrace, bool)
|
|
|
|
CTL_RO_CONFIG_GEN(config_xmalloc, bool)
|
2012-02-11 12:22:09 +08:00
|
|
|
|
2013-12-20 13:40:41 +08:00
|
|
|
/******************************************************************************/
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2013-12-20 13:40:41 +08:00
|
|
|
CTL_RO_NL_GEN(opt_abort, opt_abort, bool)
|
|
|
|
CTL_RO_NL_GEN(opt_dss, opt_dss, const char *)
|
2016-02-25 03:03:40 +08:00
|
|
|
CTL_RO_NL_GEN(opt_narenas, opt_narenas, unsigned)
|
Implement per-CPU arena.
The new feature, opt.percpu_arena, determines thread-arena association
dynamically based CPU id. Three modes are supported: "percpu", "phycpu"
and disabled.
"percpu" uses the current core id (with help from sched_getcpu())
directly as the arena index, while "phycpu" will assign threads on the
same physical CPU to the same arena. In other words, "percpu" means # of
arenas == # of CPUs, while "phycpu" has # of arenas == 1/2 * (# of
CPUs). Note that no runtime check on whether hyper threading is enabled
is added yet.
When enabled, threads will be migrated between arenas when a CPU change
is detected. In the current design, to reduce overhead from reading CPU
id, each arena tracks the thread accessed most recently. When a new
thread comes in, we will read CPU id and update arena if necessary.
2017-02-03 09:02:05 +08:00
|
|
|
CTL_RO_NL_GEN(opt_percpu_arena, opt_percpu_arena, const char *)
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
CTL_RO_NL_GEN(opt_dirty_decay_time, opt_dirty_decay_time, ssize_t)
|
|
|
|
CTL_RO_NL_GEN(opt_muzzy_decay_time, opt_muzzy_decay_time, ssize_t)
|
2013-12-20 13:40:41 +08:00
|
|
|
CTL_RO_NL_GEN(opt_stats_print, opt_stats_print, bool)
|
2014-12-09 05:12:41 +08:00
|
|
|
CTL_RO_NL_CGEN(config_fill, opt_junk, opt_junk, const char *)
|
2013-12-20 13:40:41 +08:00
|
|
|
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_xmalloc, opt_xmalloc, opt_xmalloc, bool)
|
|
|
|
CTL_RO_NL_CGEN(config_tcache, opt_tcache, opt_tcache, bool)
|
|
|
|
CTL_RO_NL_CGEN(config_tcache, 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_prefix, opt_prof_prefix, const char *)
|
2014-10-04 14:25:30 +08:00
|
|
|
CTL_RO_NL_CGEN(config_prof, opt_prof_active, opt_prof_active, bool)
|
|
|
|
CTL_RO_NL_CGEN(config_prof, opt_prof_thread_active_init,
|
|
|
|
opt_prof_thread_active_init, bool)
|
2013-12-20 13:40:41 +08:00
|
|
|
CTL_RO_NL_CGEN(config_prof, opt_lg_prof_sample, opt_lg_prof_sample, size_t)
|
|
|
|
CTL_RO_NL_CGEN(config_prof, opt_prof_accum, opt_prof_accum, bool)
|
|
|
|
CTL_RO_NL_CGEN(config_prof, opt_lg_prof_interval, opt_lg_prof_interval, ssize_t)
|
|
|
|
CTL_RO_NL_CGEN(config_prof, opt_prof_gdump, opt_prof_gdump, bool)
|
|
|
|
CTL_RO_NL_CGEN(config_prof, opt_prof_final, opt_prof_final, bool)
|
|
|
|
CTL_RO_NL_CGEN(config_prof, opt_prof_leak, opt_prof_leak, bool)
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2013-12-20 13:40:41 +08:00
|
|
|
/******************************************************************************/
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2010-08-14 06:42:29 +08:00
|
|
|
static int
|
2016-04-14 14:36:15 +08:00
|
|
|
thread_arena_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) {
|
2010-08-14 06:42:29 +08:00
|
|
|
int ret;
|
2015-01-30 07:30:47 +08:00
|
|
|
arena_t *oldarena;
|
2010-08-14 06:42:29 +08:00
|
|
|
unsigned newind, oldind;
|
|
|
|
|
2016-05-04 06:00:42 +08:00
|
|
|
oldarena = arena_choose(tsd, NULL);
|
2017-01-16 08:56:30 +08:00
|
|
|
if (oldarena == NULL) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return EAGAIN;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2016-12-23 06:39:10 +08:00
|
|
|
newind = oldind = arena_ind_get(oldarena);
|
2011-03-15 02:39:49 +08:00
|
|
|
WRITE(newind, unsigned);
|
|
|
|
READ(oldind, unsigned);
|
Implement per-CPU arena.
The new feature, opt.percpu_arena, determines thread-arena association
dynamically based CPU id. Three modes are supported: "percpu", "phycpu"
and disabled.
"percpu" uses the current core id (with help from sched_getcpu())
directly as the arena index, while "phycpu" will assign threads on the
same physical CPU to the same arena. In other words, "percpu" means # of
arenas == # of CPUs, while "phycpu" has # of arenas == 1/2 * (# of
CPUs). Note that no runtime check on whether hyper threading is enabled
is added yet.
When enabled, threads will be migrated between arenas when a CPU change
is detected. In the current design, to reduce overhead from reading CPU
id, each arena tracks the thread accessed most recently. When a new
thread comes in, we will read CPU id and update arena if necessary.
2017-02-03 09:02:05 +08:00
|
|
|
|
2010-08-14 06:42:29 +08:00
|
|
|
if (newind != oldind) {
|
2015-01-30 07:30:47 +08:00
|
|
|
arena_t *newarena;
|
|
|
|
|
2016-10-04 01:37:12 +08:00
|
|
|
if (newind >= narenas_total_get()) {
|
2010-08-14 06:42:29 +08:00
|
|
|
/* New arena index is out of range. */
|
|
|
|
ret = EFAULT;
|
2012-04-11 06:07:44 +08:00
|
|
|
goto label_return;
|
2010-08-14 06:42:29 +08:00
|
|
|
}
|
|
|
|
|
Implement per-CPU arena.
The new feature, opt.percpu_arena, determines thread-arena association
dynamically based CPU id. Three modes are supported: "percpu", "phycpu"
and disabled.
"percpu" uses the current core id (with help from sched_getcpu())
directly as the arena index, while "phycpu" will assign threads on the
same physical CPU to the same arena. In other words, "percpu" means # of
arenas == # of CPUs, while "phycpu" has # of arenas == 1/2 * (# of
CPUs). Note that no runtime check on whether hyper threading is enabled
is added yet.
When enabled, threads will be migrated between arenas when a CPU change
is detected. In the current design, to reduce overhead from reading CPU
id, each arena tracks the thread accessed most recently. When a new
thread comes in, we will read CPU id and update arena if necessary.
2017-02-03 09:02:05 +08:00
|
|
|
if (have_percpu_arena &&
|
|
|
|
(percpu_arena_mode != percpu_arena_disabled)) {
|
|
|
|
if (newind < percpu_arena_ind_limit()) {
|
|
|
|
/*
|
|
|
|
* If perCPU arena is enabled, thread_arena
|
|
|
|
* control is not allowed for the auto arena
|
|
|
|
* range.
|
|
|
|
*/
|
|
|
|
ret = EPERM;
|
|
|
|
goto label_return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-14 06:42:29 +08:00
|
|
|
/* Initialize arena if necessary. */
|
2016-05-11 13:21:10 +08:00
|
|
|
newarena = arena_get(tsd_tsdn(tsd), newind, true);
|
2015-01-30 07:30:47 +08:00
|
|
|
if (newarena == NULL) {
|
2010-08-14 06:42:29 +08:00
|
|
|
ret = EAGAIN;
|
2012-04-11 06:07:44 +08:00
|
|
|
goto label_return;
|
2010-08-14 06:42:29 +08:00
|
|
|
}
|
Refactor/fix arenas manipulation.
Abstract arenas access to use arena_get() (or a0get() where appropriate)
rather than directly reading e.g. arenas[ind]. Prior to the addition of
the arenas.extend mallctl, the worst possible outcome of directly
accessing arenas was a stale read, but arenas.extend may allocate and
assign a new array to arenas.
Add a tsd-based arenas_cache, which amortizes arenas reads. This
introduces some subtle bootstrapping issues, with tsd_boot() now being
split into tsd_boot[01]() to support tsd wrapper allocation
bootstrapping, as well as an arenas_cache_bypass tsd variable which
dynamically terminates allocation of arenas_cache itself.
Promote a0malloc(), a0calloc(), and a0free() to be generally useful for
internal allocation, and use them in several places (more may be
appropriate).
Abstract arena->nthreads management and fix a missing decrement during
thread destruction (recent tsd refactoring left arenas_cleanup()
unused).
Change arena_choose() to propagate OOM, and handle OOM in all callers.
This is important for providing consistent allocation behavior when the
MALLOCX_ARENA() flag is being used. Prior to this fix, it was possible
for an OOM to result in allocation silently allocating from a different
arena than the one specified.
2014-10-08 14:14:57 +08:00
|
|
|
/* Set new arena/tcache associations. */
|
|
|
|
arena_migrate(tsd, oldind, newind);
|
2012-02-11 12:22:09 +08:00
|
|
|
if (config_tcache) {
|
2014-09-23 12:09:23 +08:00
|
|
|
tcache_t *tcache = tsd_tcache_get(tsd);
|
2015-01-30 07:30:47 +08:00
|
|
|
if (tcache != NULL) {
|
2016-05-11 13:21:10 +08:00
|
|
|
tcache_arena_reassociate(tsd_tsdn(tsd), tcache,
|
2017-03-07 04:51:41 +08:00
|
|
|
newarena);
|
2015-01-30 07:30:47 +08:00
|
|
|
}
|
2010-12-30 04:21:05 +08:00
|
|
|
}
|
2010-08-14 06:42:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
2012-04-11 06:07:44 +08:00
|
|
|
label_return:
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2010-08-14 06:42:29 +08:00
|
|
|
}
|
|
|
|
|
2014-09-23 12:09:23 +08:00
|
|
|
CTL_TSD_RO_NL_CGEN(config_stats, thread_allocated, tsd_thread_allocated_get,
|
|
|
|
uint64_t)
|
|
|
|
CTL_TSD_RO_NL_CGEN(config_stats, thread_allocatedp, tsd_thread_allocatedp_get,
|
|
|
|
uint64_t *)
|
|
|
|
CTL_TSD_RO_NL_CGEN(config_stats, thread_deallocated, tsd_thread_deallocated_get,
|
|
|
|
uint64_t)
|
|
|
|
CTL_TSD_RO_NL_CGEN(config_stats, thread_deallocatedp,
|
|
|
|
tsd_thread_deallocatedp_get, uint64_t *)
|
2010-10-21 08:39:18 +08:00
|
|
|
|
2013-12-20 13:40:41 +08:00
|
|
|
static int
|
2016-04-14 14:36:15 +08:00
|
|
|
thread_tcache_enabled_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
|
2017-01-16 08:56:30 +08:00
|
|
|
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
|
2013-12-20 13:40:41 +08:00
|
|
|
int ret;
|
|
|
|
bool oldval;
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2017-01-16 08:56:30 +08:00
|
|
|
if (!config_tcache) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return ENOENT;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2013-12-20 13:40:41 +08:00
|
|
|
oldval = tcache_enabled_get();
|
|
|
|
if (newp != NULL) {
|
|
|
|
if (newlen != sizeof(bool)) {
|
|
|
|
ret = EINVAL;
|
|
|
|
goto label_return;
|
|
|
|
}
|
|
|
|
tcache_enabled_set(*(bool *)newp);
|
|
|
|
}
|
|
|
|
READ(oldval, bool);
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2013-12-20 13:40:41 +08:00
|
|
|
ret = 0;
|
|
|
|
label_return:
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2013-12-20 13:40:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2016-04-14 14:36:15 +08:00
|
|
|
thread_tcache_flush_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
|
2017-01-16 08:56:30 +08:00
|
|
|
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
|
2013-12-20 13:40:41 +08:00
|
|
|
int ret;
|
|
|
|
|
2017-01-16 08:56:30 +08:00
|
|
|
if (!config_tcache) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return ENOENT;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2013-12-20 13:40:41 +08:00
|
|
|
|
|
|
|
READONLY();
|
|
|
|
WRITEONLY();
|
|
|
|
|
|
|
|
tcache_flush();
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
label_return:
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2013-12-20 13:40:41 +08:00
|
|
|
}
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2014-08-19 07:22:13 +08:00
|
|
|
static int
|
2016-04-14 14:36:15 +08:00
|
|
|
thread_prof_name_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) {
|
2014-08-19 07:22:13 +08:00
|
|
|
int ret;
|
|
|
|
|
2017-01-16 08:56:30 +08:00
|
|
|
if (!config_prof) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return ENOENT;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2014-08-19 07:22:13 +08:00
|
|
|
|
2014-10-04 14:25:30 +08:00
|
|
|
READ_XOR_WRITE();
|
|
|
|
|
2014-08-19 07:22:13 +08:00
|
|
|
if (newp != NULL) {
|
|
|
|
if (newlen != sizeof(const char *)) {
|
|
|
|
ret = EINVAL;
|
|
|
|
goto label_return;
|
|
|
|
}
|
2014-09-23 12:09:23 +08:00
|
|
|
|
2014-10-04 14:25:30 +08:00
|
|
|
if ((ret = prof_thread_name_set(tsd, *(const char **)newp)) !=
|
2017-01-16 08:56:30 +08:00
|
|
|
0) {
|
2014-08-19 07:22:13 +08:00
|
|
|
goto label_return;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2014-10-04 14:25:30 +08:00
|
|
|
} else {
|
2016-04-14 14:36:15 +08:00
|
|
|
const char *oldname = prof_thread_name_get(tsd);
|
2014-10-04 14:25:30 +08:00
|
|
|
READ(oldname, const char *);
|
2014-08-19 07:22:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
label_return:
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2014-08-19 07:22:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2016-04-14 14:36:15 +08:00
|
|
|
thread_prof_active_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) {
|
2014-08-19 07:22:13 +08:00
|
|
|
int ret;
|
|
|
|
bool oldval;
|
|
|
|
|
2017-01-16 08:56:30 +08:00
|
|
|
if (!config_prof) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return ENOENT;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2014-08-19 07:22:13 +08:00
|
|
|
|
2016-04-14 14:36:15 +08:00
|
|
|
oldval = prof_thread_active_get(tsd);
|
2014-08-19 07:22:13 +08:00
|
|
|
if (newp != NULL) {
|
|
|
|
if (newlen != sizeof(bool)) {
|
|
|
|
ret = EINVAL;
|
|
|
|
goto label_return;
|
|
|
|
}
|
2016-04-14 14:36:15 +08:00
|
|
|
if (prof_thread_active_set(tsd, *(bool *)newp)) {
|
2014-08-19 07:22:13 +08:00
|
|
|
ret = EAGAIN;
|
|
|
|
goto label_return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
READ(oldval, bool);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
label_return:
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2014-08-19 07:22:13 +08:00
|
|
|
}
|
|
|
|
|
2012-10-12 04:53:15 +08:00
|
|
|
/******************************************************************************/
|
|
|
|
|
2015-01-30 07:30:47 +08:00
|
|
|
static int
|
2016-04-14 14:36:15 +08:00
|
|
|
tcache_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) {
|
2015-01-30 07:30:47 +08:00
|
|
|
int ret;
|
|
|
|
unsigned tcache_ind;
|
|
|
|
|
2017-01-16 08:56:30 +08:00
|
|
|
if (!config_tcache) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return ENOENT;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2015-01-30 07:30:47 +08:00
|
|
|
|
|
|
|
READONLY();
|
2016-10-21 14:59:12 +08:00
|
|
|
if (tcaches_create(tsd, &tcache_ind)) {
|
2015-01-30 07:30:47 +08:00
|
|
|
ret = EFAULT;
|
|
|
|
goto label_return;
|
|
|
|
}
|
|
|
|
READ(tcache_ind, unsigned);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
label_return:
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2015-01-30 07:30:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2016-04-14 14:36:15 +08:00
|
|
|
tcache_flush_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) {
|
2015-01-30 07:30:47 +08:00
|
|
|
int ret;
|
|
|
|
unsigned tcache_ind;
|
|
|
|
|
2017-01-16 08:56:30 +08:00
|
|
|
if (!config_tcache) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return ENOENT;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2015-01-30 07:30:47 +08:00
|
|
|
|
|
|
|
WRITEONLY();
|
|
|
|
tcache_ind = UINT_MAX;
|
|
|
|
WRITE(tcache_ind, unsigned);
|
|
|
|
if (tcache_ind == UINT_MAX) {
|
|
|
|
ret = EFAULT;
|
|
|
|
goto label_return;
|
|
|
|
}
|
|
|
|
tcaches_flush(tsd, tcache_ind);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
label_return:
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2015-01-30 07:30:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2016-04-14 14:36:15 +08:00
|
|
|
tcache_destroy_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) {
|
2015-01-30 07:30:47 +08:00
|
|
|
int ret;
|
|
|
|
unsigned tcache_ind;
|
|
|
|
|
2017-01-16 08:56:30 +08:00
|
|
|
if (!config_tcache) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return ENOENT;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2015-01-30 07:30:47 +08:00
|
|
|
|
|
|
|
WRITEONLY();
|
|
|
|
tcache_ind = UINT_MAX;
|
|
|
|
WRITE(tcache_ind, unsigned);
|
|
|
|
if (tcache_ind == UINT_MAX) {
|
|
|
|
ret = EFAULT;
|
|
|
|
goto label_return;
|
|
|
|
}
|
|
|
|
tcaches_destroy(tsd, tcache_ind);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
label_return:
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2015-01-30 07:30:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2017-01-05 02:21:53 +08:00
|
|
|
static int
|
|
|
|
arena_i_initialized_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
|
2017-01-16 08:56:30 +08:00
|
|
|
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
|
2017-01-05 02:21:53 +08:00
|
|
|
int ret;
|
|
|
|
tsdn_t *tsdn = tsd_tsdn(tsd);
|
|
|
|
unsigned arena_ind;
|
|
|
|
bool initialized;
|
|
|
|
|
|
|
|
READONLY();
|
|
|
|
MIB_UNSIGNED(arena_ind, 1);
|
|
|
|
|
|
|
|
malloc_mutex_lock(tsdn, &ctl_mtx);
|
2017-01-19 15:03:37 +08:00
|
|
|
initialized = arenas_i(arena_ind)->initialized;
|
2017-01-05 02:21:53 +08:00
|
|
|
malloc_mutex_unlock(tsdn, &ctl_mtx);
|
|
|
|
|
|
|
|
READ(initialized, bool);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
label_return:
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2017-01-05 02:21:53 +08:00
|
|
|
}
|
|
|
|
|
2012-11-04 12:18:28 +08:00
|
|
|
static void
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
arena_i_decay(tsdn_t *tsdn, unsigned arena_ind, bool all) {
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_lock(tsdn, &ctl_mtx);
|
2016-02-20 12:09:31 +08:00
|
|
|
{
|
2017-01-19 15:03:37 +08:00
|
|
|
unsigned narenas = ctl_arenas->narenas;
|
2016-02-20 12:09:31 +08:00
|
|
|
|
2017-01-03 23:27:42 +08:00
|
|
|
/*
|
|
|
|
* Access via index narenas is deprecated, and scheduled for
|
|
|
|
* removal in 6.0.0.
|
|
|
|
*/
|
|
|
|
if (arena_ind == MALLCTL_ARENAS_ALL || arena_ind == narenas) {
|
2016-02-20 12:09:31 +08:00
|
|
|
unsigned i;
|
|
|
|
VARIABLE_ARRAY(arena_t *, tarenas, narenas);
|
|
|
|
|
2017-01-16 08:56:30 +08:00
|
|
|
for (i = 0; i < narenas; i++) {
|
2016-05-11 13:21:10 +08:00
|
|
|
tarenas[i] = arena_get(tsdn, i, false);
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2016-02-20 12:09:31 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* No further need to hold ctl_mtx, since narenas and
|
|
|
|
* tarenas contain everything needed below.
|
|
|
|
*/
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_unlock(tsdn, &ctl_mtx);
|
2016-02-20 12:09:31 +08:00
|
|
|
|
|
|
|
for (i = 0; i < narenas; i++) {
|
2017-01-16 08:56:30 +08:00
|
|
|
if (tarenas[i] != NULL) {
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
arena_decay(tsdn, tarenas[i], all);
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2016-02-20 12:09:31 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
arena_t *tarena;
|
|
|
|
|
|
|
|
assert(arena_ind < narenas);
|
|
|
|
|
2016-05-11 13:21:10 +08:00
|
|
|
tarena = arena_get(tsdn, arena_ind, false);
|
2012-10-12 04:53:15 +08:00
|
|
|
|
2016-02-20 12:09:31 +08:00
|
|
|
/* No further need to hold ctl_mtx. */
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_unlock(tsdn, &ctl_mtx);
|
2016-02-20 12:09:31 +08:00
|
|
|
|
2017-01-16 08:56:30 +08:00
|
|
|
if (tarena != NULL) {
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
arena_decay(tsdn, tarena, all);
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2012-10-12 04:53:15 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
arena_i_decay_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) {
|
2012-10-12 04:53:15 +08:00
|
|
|
int ret;
|
2017-01-04 23:51:49 +08:00
|
|
|
unsigned arena_ind;
|
2012-10-12 04:53:15 +08:00
|
|
|
|
|
|
|
READONLY();
|
|
|
|
WRITEONLY();
|
2017-01-04 23:51:49 +08:00
|
|
|
MIB_UNSIGNED(arena_ind, 1);
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
arena_i_decay(tsd_tsdn(tsd), arena_ind, false);
|
2016-02-20 12:09:31 +08:00
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
label_return:
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2016-02-20 12:09:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
arena_i_purge_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) {
|
2016-02-20 12:09:31 +08:00
|
|
|
int ret;
|
2017-01-04 23:51:49 +08:00
|
|
|
unsigned arena_ind;
|
2016-02-20 12:09:31 +08:00
|
|
|
|
|
|
|
READONLY();
|
|
|
|
WRITEONLY();
|
2017-01-04 23:51:49 +08:00
|
|
|
MIB_UNSIGNED(arena_ind, 1);
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
arena_i_decay(tsd_tsdn(tsd), arena_ind, true);
|
2012-10-12 04:53:15 +08:00
|
|
|
|
2012-11-04 12:18:28 +08:00
|
|
|
ret = 0;
|
2012-10-12 04:53:15 +08:00
|
|
|
label_return:
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2012-10-12 04:53:15 +08:00
|
|
|
}
|
|
|
|
|
2016-04-23 05:37:17 +08:00
|
|
|
static int
|
2017-01-04 09:21:59 +08:00
|
|
|
arena_i_reset_destroy_helper(tsd_t *tsd, const size_t *mib, size_t miblen,
|
|
|
|
void *oldp, size_t *oldlenp, void *newp, size_t newlen, unsigned *arena_ind,
|
2017-01-16 08:56:30 +08:00
|
|
|
arena_t **arena) {
|
2016-04-23 05:37:17 +08:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
READONLY();
|
|
|
|
WRITEONLY();
|
2017-01-04 09:21:59 +08:00
|
|
|
MIB_UNSIGNED(*arena_ind, 1);
|
2016-04-23 05:37:17 +08:00
|
|
|
|
2017-01-04 09:21:59 +08:00
|
|
|
if (*arena_ind < narenas_auto) {
|
|
|
|
ret = EFAULT;
|
|
|
|
goto label_return;
|
2016-04-23 05:37:17 +08:00
|
|
|
}
|
|
|
|
|
2017-01-04 09:21:59 +08:00
|
|
|
*arena = arena_get(tsd_tsdn(tsd), *arena_ind, false);
|
|
|
|
if (*arena == NULL) {
|
2017-01-03 23:27:42 +08:00
|
|
|
ret = EFAULT;
|
|
|
|
goto label_return;
|
|
|
|
}
|
2016-04-23 05:37:17 +08:00
|
|
|
|
2017-01-04 09:21:59 +08:00
|
|
|
ret = 0;
|
|
|
|
label_return:
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2017-01-04 09:21:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
arena_i_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) {
|
2017-01-04 09:21:59 +08:00
|
|
|
int ret;
|
|
|
|
unsigned arena_ind;
|
|
|
|
arena_t *arena;
|
|
|
|
|
|
|
|
ret = arena_i_reset_destroy_helper(tsd, mib, miblen, oldp, oldlenp,
|
|
|
|
newp, newlen, &arena_ind, &arena);
|
2017-01-16 08:56:30 +08:00
|
|
|
if (ret != 0) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2017-01-04 09:21:59 +08:00
|
|
|
|
2016-04-23 05:37:17 +08:00
|
|
|
arena_reset(tsd, arena);
|
|
|
|
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2017-01-04 09:21:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
arena_i_destroy_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) {
|
2017-01-04 09:21:59 +08:00
|
|
|
int ret;
|
|
|
|
unsigned arena_ind;
|
|
|
|
arena_t *arena;
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arena_t *ctl_darena, *ctl_arena;
|
2017-01-04 09:21:59 +08:00
|
|
|
|
|
|
|
ret = arena_i_reset_destroy_helper(tsd, mib, miblen, oldp, oldlenp,
|
|
|
|
newp, newlen, &arena_ind, &arena);
|
2017-01-16 08:56:30 +08:00
|
|
|
if (ret != 0) {
|
2017-01-04 09:21:59 +08:00
|
|
|
goto label_return;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2017-01-04 09:21:59 +08:00
|
|
|
|
|
|
|
if (arena_nthreads_get(arena, false) != 0 || arena_nthreads_get(arena,
|
|
|
|
true) != 0) {
|
|
|
|
ret = EFAULT;
|
|
|
|
goto label_return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Merge stats after resetting and purging arena. */
|
|
|
|
arena_reset(tsd, arena);
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
arena_decay(tsd_tsdn(tsd), arena, true);
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_darena = arenas_i(MALLCTL_ARENAS_DESTROYED);
|
|
|
|
ctl_darena->initialized = true;
|
|
|
|
ctl_arena_refresh(tsd_tsdn(tsd), arena, ctl_darena, arena_ind, true);
|
2017-01-04 09:21:59 +08:00
|
|
|
/* Destroy arena. */
|
|
|
|
arena_destroy(tsd, arena);
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arena = arenas_i(arena_ind);
|
|
|
|
ctl_arena->initialized = false;
|
2017-01-04 09:21:59 +08:00
|
|
|
/* Record arena index for later recycling via arenas.create. */
|
2017-01-19 15:03:37 +08:00
|
|
|
ql_elm_new(ctl_arena, destroyed_link);
|
|
|
|
ql_tail_insert(&ctl_arenas->destroyed, ctl_arena, destroyed_link);
|
2017-01-04 09:21:59 +08:00
|
|
|
|
|
|
|
assert(ret == 0);
|
2016-04-23 05:37:17 +08:00
|
|
|
label_return:
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2016-04-23 05:37:17 +08:00
|
|
|
}
|
|
|
|
|
2012-10-12 04:53:15 +08:00
|
|
|
static int
|
2016-04-14 14:36:15 +08:00
|
|
|
arena_i_dss_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) {
|
2014-08-16 03:20:20 +08:00
|
|
|
int ret;
|
|
|
|
const char *dss = NULL;
|
2017-01-04 23:51:49 +08:00
|
|
|
unsigned arena_ind;
|
2012-10-12 04:53:15 +08:00
|
|
|
dss_prec_t dss_prec_old = dss_prec_limit;
|
|
|
|
dss_prec_t dss_prec = dss_prec_limit;
|
|
|
|
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
|
2012-10-12 04:53:15 +08:00
|
|
|
WRITE(dss, const char *);
|
2017-01-04 23:51:49 +08:00
|
|
|
MIB_UNSIGNED(arena_ind, 1);
|
2014-08-16 03:20:20 +08:00
|
|
|
if (dss != NULL) {
|
|
|
|
int i;
|
|
|
|
bool match = false;
|
|
|
|
|
|
|
|
for (i = 0; i < dss_prec_limit; i++) {
|
|
|
|
if (strcmp(dss_prec_names[i], dss) == 0) {
|
|
|
|
dss_prec = i;
|
|
|
|
match = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-04 01:16:09 +08:00
|
|
|
if (!match) {
|
2014-08-16 03:20:20 +08:00
|
|
|
ret = EINVAL;
|
|
|
|
goto label_return;
|
2012-10-12 04:53:15 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-03 23:27:42 +08:00
|
|
|
/*
|
|
|
|
* Access via index narenas is deprecated, and scheduled for removal in
|
|
|
|
* 6.0.0.
|
|
|
|
*/
|
2017-01-04 04:40:54 +08:00
|
|
|
if (arena_ind == MALLCTL_ARENAS_ALL || arena_ind ==
|
2017-01-19 15:03:37 +08:00
|
|
|
ctl_arenas->narenas) {
|
2017-01-03 23:27:42 +08:00
|
|
|
if (dss_prec != dss_prec_limit &&
|
|
|
|
extent_dss_prec_set(dss_prec)) {
|
2014-08-16 03:20:20 +08:00
|
|
|
ret = EFAULT;
|
|
|
|
goto label_return;
|
|
|
|
}
|
2017-01-03 23:27:42 +08:00
|
|
|
dss_prec_old = extent_dss_prec_get();
|
2012-10-12 04:53:15 +08:00
|
|
|
} else {
|
2017-01-03 23:27:42 +08:00
|
|
|
arena_t *arena = arena_get(tsd_tsdn(tsd), arena_ind, false);
|
|
|
|
if (arena == NULL || (dss_prec != dss_prec_limit &&
|
2017-02-13 08:34:36 +08:00
|
|
|
arena_dss_prec_set(arena, dss_prec))) {
|
2014-08-16 03:20:20 +08:00
|
|
|
ret = EFAULT;
|
|
|
|
goto label_return;
|
|
|
|
}
|
2017-02-13 08:34:36 +08:00
|
|
|
dss_prec_old = arena_dss_prec_get(arena);
|
2012-10-12 04:53:15 +08:00
|
|
|
}
|
2014-08-16 03:20:20 +08:00
|
|
|
|
2012-10-12 04:53:15 +08:00
|
|
|
dss = dss_prec_names[dss_prec_old];
|
|
|
|
READ(dss, const char *);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
label_return:
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2012-10-12 04:53:15 +08:00
|
|
|
}
|
|
|
|
|
2016-02-20 12:09:31 +08:00
|
|
|
static int
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
arena_i_decay_time_ctl_impl(tsd_t *tsd, const size_t *mib, size_t miblen,
|
|
|
|
void *oldp, size_t *oldlenp, void *newp, size_t newlen, bool dirty) {
|
2016-02-20 12:09:31 +08:00
|
|
|
int ret;
|
2017-01-04 23:51:49 +08:00
|
|
|
unsigned arena_ind;
|
2016-02-20 12:09:31 +08:00
|
|
|
arena_t *arena;
|
|
|
|
|
2017-01-04 23:51:49 +08:00
|
|
|
MIB_UNSIGNED(arena_ind, 1);
|
2016-05-11 13:21:10 +08:00
|
|
|
arena = arena_get(tsd_tsdn(tsd), arena_ind, false);
|
2016-02-20 12:09:31 +08:00
|
|
|
if (arena == NULL) {
|
|
|
|
ret = EFAULT;
|
|
|
|
goto label_return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (oldp != NULL && oldlenp != NULL) {
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
size_t oldval = dirty ? arena_dirty_decay_time_get(arena) :
|
|
|
|
arena_muzzy_decay_time_get(arena);
|
2016-02-20 12:09:31 +08:00
|
|
|
READ(oldval, ssize_t);
|
|
|
|
}
|
|
|
|
if (newp != NULL) {
|
|
|
|
if (newlen != sizeof(ssize_t)) {
|
|
|
|
ret = EINVAL;
|
|
|
|
goto label_return;
|
|
|
|
}
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
if (dirty ? arena_dirty_decay_time_set(tsd_tsdn(tsd), arena,
|
|
|
|
*(ssize_t *)newp) :
|
|
|
|
arena_muzzy_decay_time_set(tsd_tsdn(tsd), arena,
|
2016-05-11 13:21:10 +08:00
|
|
|
*(ssize_t *)newp)) {
|
2016-02-20 12:09:31 +08:00
|
|
|
ret = EFAULT;
|
|
|
|
goto label_return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
label_return:
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2016-02-20 12:09:31 +08:00
|
|
|
}
|
|
|
|
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
static int
|
|
|
|
arena_i_dirty_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
|
|
|
|
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
|
|
|
|
return arena_i_decay_time_ctl_impl(tsd, mib, miblen, oldp, oldlenp,
|
|
|
|
newp, newlen, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
arena_i_muzzy_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
|
|
|
|
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
|
|
|
|
return arena_i_decay_time_ctl_impl(tsd, mib, miblen, oldp, oldlenp,
|
|
|
|
newp, newlen, false);
|
|
|
|
}
|
|
|
|
|
Generalize chunk management hooks.
Add the "arena.<i>.chunk_hooks" mallctl, which replaces and expands on
the "arena.<i>.chunk.{alloc,dalloc,purge}" mallctls. The chunk hooks
allow control over chunk allocation/deallocation, decommit/commit,
purging, and splitting/merging, such that the application can rely on
jemalloc's internal chunk caching and retaining functionality, yet
implement a variety of chunk management mechanisms and policies.
Merge the chunks_[sz]ad_{mmap,dss} red-black trees into
chunks_[sz]ad_retained. This slightly reduces how hard jemalloc tries
to honor the dss precedence setting; prior to this change the precedence
setting was also consulted when recycling chunks.
Fix chunk purging. Don't purge chunks in arena_purge_stashed(); instead
deallocate them in arena_unstash_purged(), so that the dirty memory
linkage remains valid until after the last time it is used.
This resolves #176 and #201.
2015-07-28 23:28:19 +08:00
|
|
|
static int
|
2016-06-01 06:03:51 +08:00
|
|
|
arena_i_extent_hooks_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
|
2017-01-16 08:56:30 +08:00
|
|
|
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
|
Generalize chunk management hooks.
Add the "arena.<i>.chunk_hooks" mallctl, which replaces and expands on
the "arena.<i>.chunk.{alloc,dalloc,purge}" mallctls. The chunk hooks
allow control over chunk allocation/deallocation, decommit/commit,
purging, and splitting/merging, such that the application can rely on
jemalloc's internal chunk caching and retaining functionality, yet
implement a variety of chunk management mechanisms and policies.
Merge the chunks_[sz]ad_{mmap,dss} red-black trees into
chunks_[sz]ad_retained. This slightly reduces how hard jemalloc tries
to honor the dss precedence setting; prior to this change the precedence
setting was also consulted when recycling chunks.
Fix chunk purging. Don't purge chunks in arena_purge_stashed(); instead
deallocate them in arena_unstash_purged(), so that the dirty memory
linkage remains valid until after the last time it is used.
This resolves #176 and #201.
2015-07-28 23:28:19 +08:00
|
|
|
int ret;
|
2017-01-04 23:51:49 +08:00
|
|
|
unsigned arena_ind;
|
Generalize chunk management hooks.
Add the "arena.<i>.chunk_hooks" mallctl, which replaces and expands on
the "arena.<i>.chunk.{alloc,dalloc,purge}" mallctls. The chunk hooks
allow control over chunk allocation/deallocation, decommit/commit,
purging, and splitting/merging, such that the application can rely on
jemalloc's internal chunk caching and retaining functionality, yet
implement a variety of chunk management mechanisms and policies.
Merge the chunks_[sz]ad_{mmap,dss} red-black trees into
chunks_[sz]ad_retained. This slightly reduces how hard jemalloc tries
to honor the dss precedence setting; prior to this change the precedence
setting was also consulted when recycling chunks.
Fix chunk purging. Don't purge chunks in arena_purge_stashed(); instead
deallocate them in arena_unstash_purged(), so that the dirty memory
linkage remains valid until after the last time it is used.
This resolves #176 and #201.
2015-07-28 23:28:19 +08:00
|
|
|
arena_t *arena;
|
|
|
|
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
|
2017-01-04 23:51:49 +08:00
|
|
|
MIB_UNSIGNED(arena_ind, 1);
|
Generalize chunk management hooks.
Add the "arena.<i>.chunk_hooks" mallctl, which replaces and expands on
the "arena.<i>.chunk.{alloc,dalloc,purge}" mallctls. The chunk hooks
allow control over chunk allocation/deallocation, decommit/commit,
purging, and splitting/merging, such that the application can rely on
jemalloc's internal chunk caching and retaining functionality, yet
implement a variety of chunk management mechanisms and policies.
Merge the chunks_[sz]ad_{mmap,dss} red-black trees into
chunks_[sz]ad_retained. This slightly reduces how hard jemalloc tries
to honor the dss precedence setting; prior to this change the precedence
setting was also consulted when recycling chunks.
Fix chunk purging. Don't purge chunks in arena_purge_stashed(); instead
deallocate them in arena_unstash_purged(), so that the dirty memory
linkage remains valid until after the last time it is used.
This resolves #176 and #201.
2015-07-28 23:28:19 +08:00
|
|
|
if (arena_ind < narenas_total_get() && (arena =
|
2016-05-11 13:21:10 +08:00
|
|
|
arena_get(tsd_tsdn(tsd), arena_ind, false)) != NULL) {
|
Generalize chunk management hooks.
Add the "arena.<i>.chunk_hooks" mallctl, which replaces and expands on
the "arena.<i>.chunk.{alloc,dalloc,purge}" mallctls. The chunk hooks
allow control over chunk allocation/deallocation, decommit/commit,
purging, and splitting/merging, such that the application can rely on
jemalloc's internal chunk caching and retaining functionality, yet
implement a variety of chunk management mechanisms and policies.
Merge the chunks_[sz]ad_{mmap,dss} red-black trees into
chunks_[sz]ad_retained. This slightly reduces how hard jemalloc tries
to honor the dss precedence setting; prior to this change the precedence
setting was also consulted when recycling chunks.
Fix chunk purging. Don't purge chunks in arena_purge_stashed(); instead
deallocate them in arena_unstash_purged(), so that the dirty memory
linkage remains valid until after the last time it is used.
This resolves #176 and #201.
2015-07-28 23:28:19 +08:00
|
|
|
if (newp != NULL) {
|
2016-06-04 10:39:14 +08:00
|
|
|
extent_hooks_t *old_extent_hooks;
|
|
|
|
extent_hooks_t *new_extent_hooks
|
|
|
|
JEMALLOC_CC_SILENCE_INIT(NULL);
|
2016-06-04 03:05:53 +08:00
|
|
|
WRITE(new_extent_hooks, extent_hooks_t *);
|
|
|
|
old_extent_hooks = extent_hooks_set(arena,
|
|
|
|
new_extent_hooks);
|
|
|
|
READ(old_extent_hooks, extent_hooks_t *);
|
Generalize chunk management hooks.
Add the "arena.<i>.chunk_hooks" mallctl, which replaces and expands on
the "arena.<i>.chunk.{alloc,dalloc,purge}" mallctls. The chunk hooks
allow control over chunk allocation/deallocation, decommit/commit,
purging, and splitting/merging, such that the application can rely on
jemalloc's internal chunk caching and retaining functionality, yet
implement a variety of chunk management mechanisms and policies.
Merge the chunks_[sz]ad_{mmap,dss} red-black trees into
chunks_[sz]ad_retained. This slightly reduces how hard jemalloc tries
to honor the dss precedence setting; prior to this change the precedence
setting was also consulted when recycling chunks.
Fix chunk purging. Don't purge chunks in arena_purge_stashed(); instead
deallocate them in arena_unstash_purged(), so that the dirty memory
linkage remains valid until after the last time it is used.
This resolves #176 and #201.
2015-07-28 23:28:19 +08:00
|
|
|
} else {
|
2016-06-04 03:05:53 +08:00
|
|
|
extent_hooks_t *old_extent_hooks =
|
|
|
|
extent_hooks_get(arena);
|
|
|
|
READ(old_extent_hooks, extent_hooks_t *);
|
Generalize chunk management hooks.
Add the "arena.<i>.chunk_hooks" mallctl, which replaces and expands on
the "arena.<i>.chunk.{alloc,dalloc,purge}" mallctls. The chunk hooks
allow control over chunk allocation/deallocation, decommit/commit,
purging, and splitting/merging, such that the application can rely on
jemalloc's internal chunk caching and retaining functionality, yet
implement a variety of chunk management mechanisms and policies.
Merge the chunks_[sz]ad_{mmap,dss} red-black trees into
chunks_[sz]ad_retained. This slightly reduces how hard jemalloc tries
to honor the dss precedence setting; prior to this change the precedence
setting was also consulted when recycling chunks.
Fix chunk purging. Don't purge chunks in arena_purge_stashed(); instead
deallocate them in arena_unstash_purged(), so that the dirty memory
linkage remains valid until after the last time it is used.
This resolves #176 and #201.
2015-07-28 23:28:19 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ret = EFAULT;
|
|
|
|
goto label_return;
|
|
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
label_return:
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2015-03-19 09:55:33 +08:00
|
|
|
}
|
|
|
|
|
2012-10-12 04:53:15 +08:00
|
|
|
static const ctl_named_node_t *
|
2017-01-16 08:56:30 +08:00
|
|
|
arena_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) {
|
2016-04-14 14:36:15 +08:00
|
|
|
const ctl_named_node_t *ret;
|
2012-10-12 04:53:15 +08:00
|
|
|
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_lock(tsdn, &ctl_mtx);
|
2017-01-04 09:21:59 +08:00
|
|
|
switch (i) {
|
|
|
|
case MALLCTL_ARENAS_ALL:
|
|
|
|
case MALLCTL_ARENAS_DESTROYED:
|
|
|
|
break;
|
|
|
|
default:
|
2017-01-19 15:03:37 +08:00
|
|
|
if (i > ctl_arenas->narenas) {
|
2017-01-04 09:21:59 +08:00
|
|
|
ret = NULL;
|
|
|
|
goto label_return;
|
|
|
|
}
|
|
|
|
break;
|
2012-10-12 04:53:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = super_arena_i_node;
|
|
|
|
label_return:
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_unlock(tsdn, &ctl_mtx);
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2012-10-12 04:53:15 +08:00
|
|
|
}
|
|
|
|
|
2010-01-28 05:10:55 +08:00
|
|
|
/******************************************************************************/
|
|
|
|
|
2012-10-12 04:53:15 +08:00
|
|
|
static int
|
2016-04-14 14:36:15 +08:00
|
|
|
arenas_narenas_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) {
|
2012-10-12 04:53:15 +08:00
|
|
|
int ret;
|
|
|
|
unsigned narenas;
|
|
|
|
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
|
2012-10-12 04:53:15 +08:00
|
|
|
READONLY();
|
|
|
|
if (*oldlenp != sizeof(unsigned)) {
|
|
|
|
ret = EINVAL;
|
|
|
|
goto label_return;
|
|
|
|
}
|
2017-01-19 15:03:37 +08:00
|
|
|
narenas = ctl_arenas->narenas;
|
2012-10-12 04:53:15 +08:00
|
|
|
READ(narenas, unsigned);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
label_return:
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2012-10-12 04:53:15 +08:00
|
|
|
}
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2016-02-20 12:09:31 +08:00
|
|
|
static int
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
arenas_decay_time_ctl_impl(tsd_t *tsd, const size_t *mib, size_t miblen,
|
|
|
|
void *oldp, size_t *oldlenp, void *newp, size_t newlen, bool dirty) {
|
2016-02-20 12:09:31 +08:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (oldp != NULL && oldlenp != NULL) {
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
size_t oldval = (dirty ? arena_dirty_decay_time_default_get() :
|
|
|
|
arena_muzzy_decay_time_default_get());
|
2016-02-20 12:09:31 +08:00
|
|
|
READ(oldval, ssize_t);
|
|
|
|
}
|
|
|
|
if (newp != NULL) {
|
|
|
|
if (newlen != sizeof(ssize_t)) {
|
|
|
|
ret = EINVAL;
|
|
|
|
goto label_return;
|
|
|
|
}
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
if (dirty ? arena_dirty_decay_time_default_set(*(ssize_t *)newp)
|
|
|
|
: arena_muzzy_decay_time_default_set(*(ssize_t *)newp)) {
|
2016-02-20 12:09:31 +08:00
|
|
|
ret = EFAULT;
|
|
|
|
goto label_return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
label_return:
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2016-02-20 12:09:31 +08:00
|
|
|
}
|
|
|
|
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
static int
|
|
|
|
arenas_dirty_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
|
|
|
|
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
|
|
|
|
return arenas_decay_time_ctl_impl(tsd, mib, miblen, oldp, oldlenp, newp,
|
|
|
|
newlen, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
arenas_muzzy_decay_time_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
|
|
|
|
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
|
|
|
|
return arenas_decay_time_ctl_impl(tsd, mib, miblen, oldp, oldlenp, newp,
|
|
|
|
newlen, false);
|
|
|
|
}
|
|
|
|
|
2010-11-25 07:44:21 +08:00
|
|
|
CTL_RO_NL_GEN(arenas_quantum, QUANTUM, size_t)
|
2012-04-02 22:04:34 +08:00
|
|
|
CTL_RO_NL_GEN(arenas_page, PAGE, size_t)
|
2012-02-11 12:22:09 +08:00
|
|
|
CTL_RO_NL_CGEN(config_tcache, arenas_tcache_max, tcache_maxclass, size_t)
|
2012-02-29 08:50:47 +08:00
|
|
|
CTL_RO_NL_GEN(arenas_nbins, NBINS, unsigned)
|
2012-02-11 12:22:09 +08:00
|
|
|
CTL_RO_NL_CGEN(config_tcache, arenas_nhbins, nhbins, unsigned)
|
2013-12-20 13:40:41 +08:00
|
|
|
CTL_RO_NL_GEN(arenas_bin_i_size, arena_bin_info[mib[2]].reg_size, size_t)
|
|
|
|
CTL_RO_NL_GEN(arenas_bin_i_nregs, arena_bin_info[mib[2]].nregs, uint32_t)
|
2016-05-30 09:34:50 +08:00
|
|
|
CTL_RO_NL_GEN(arenas_bin_i_slab_size, arena_bin_info[mib[2]].slab_size, size_t)
|
2013-12-20 13:40:41 +08:00
|
|
|
static const ctl_named_node_t *
|
2017-01-16 08:56:30 +08:00
|
|
|
arenas_bin_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) {
|
|
|
|
if (i > NBINS) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return NULL;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2017-01-20 10:15:45 +08:00
|
|
|
return super_arenas_bin_i_node;
|
2013-12-20 13:40:41 +08:00
|
|
|
}
|
|
|
|
|
2016-06-01 05:50:21 +08:00
|
|
|
CTL_RO_NL_GEN(arenas_nlextents, NSIZES - NBINS, unsigned)
|
|
|
|
CTL_RO_NL_GEN(arenas_lextent_i_size, index2size(NBINS+(szind_t)mib[2]), size_t)
|
2014-10-13 13:53:59 +08:00
|
|
|
static const ctl_named_node_t *
|
2017-01-16 08:56:30 +08:00
|
|
|
arenas_lextent_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen,
|
|
|
|
size_t i) {
|
|
|
|
if (i > NSIZES - NBINS) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return NULL;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2017-01-20 10:15:45 +08:00
|
|
|
return super_arenas_lextent_i_node;
|
2014-10-13 13:53:59 +08:00
|
|
|
}
|
|
|
|
|
2012-10-12 04:53:15 +08:00
|
|
|
static int
|
2017-01-04 00:21:29 +08:00
|
|
|
arenas_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) {
|
2012-10-12 04:53:15 +08:00
|
|
|
int ret;
|
2016-12-23 06:39:10 +08:00
|
|
|
extent_hooks_t *extent_hooks;
|
2017-01-04 09:21:59 +08:00
|
|
|
unsigned arena_ind;
|
2012-10-12 04:53:15 +08:00
|
|
|
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_lock(tsd_tsdn(tsd), &ctl_mtx);
|
2016-12-23 06:39:10 +08:00
|
|
|
|
|
|
|
extent_hooks = (extent_hooks_t *)&extent_hooks_default;
|
|
|
|
WRITE(extent_hooks, extent_hooks_t *);
|
2017-01-04 09:21:59 +08:00
|
|
|
if ((arena_ind = ctl_arena_init(tsd_tsdn(tsd), extent_hooks)) ==
|
|
|
|
UINT_MAX) {
|
2012-10-12 04:53:15 +08:00
|
|
|
ret = EAGAIN;
|
|
|
|
goto label_return;
|
2010-10-01 07:55:08 +08:00
|
|
|
}
|
2017-01-04 09:21:59 +08:00
|
|
|
READ(arena_ind, unsigned);
|
2010-10-01 07:55:08 +08:00
|
|
|
|
|
|
|
ret = 0;
|
2012-04-11 06:07:44 +08:00
|
|
|
label_return:
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_unlock(tsd_tsdn(tsd), &ctl_mtx);
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2010-10-01 07:55:08 +08:00
|
|
|
}
|
|
|
|
|
2010-01-28 05:10:55 +08:00
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-10-04 14:25:30 +08:00
|
|
|
static int
|
2016-04-14 14:36:15 +08:00
|
|
|
prof_thread_active_init_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
|
2017-01-16 08:56:30 +08:00
|
|
|
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
|
2014-10-04 14:25:30 +08:00
|
|
|
int ret;
|
|
|
|
bool oldval;
|
|
|
|
|
2017-01-16 08:56:30 +08:00
|
|
|
if (!config_prof) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return ENOENT;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2014-10-04 14:25:30 +08:00
|
|
|
|
|
|
|
if (newp != NULL) {
|
|
|
|
if (newlen != sizeof(bool)) {
|
|
|
|
ret = EINVAL;
|
|
|
|
goto label_return;
|
|
|
|
}
|
2016-05-11 13:21:10 +08:00
|
|
|
oldval = prof_thread_active_init_set(tsd_tsdn(tsd),
|
|
|
|
*(bool *)newp);
|
2017-01-16 08:56:30 +08:00
|
|
|
} else {
|
2016-05-11 13:21:10 +08:00
|
|
|
oldval = prof_thread_active_init_get(tsd_tsdn(tsd));
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2014-10-04 14:25:30 +08:00
|
|
|
READ(oldval, bool);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
label_return:
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2014-10-04 14:25:30 +08:00
|
|
|
}
|
|
|
|
|
2010-04-01 09:43:24 +08:00
|
|
|
static int
|
2016-04-14 14:36:15 +08:00
|
|
|
prof_active_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) {
|
2010-04-01 09:43:24 +08:00
|
|
|
int ret;
|
|
|
|
bool oldval;
|
|
|
|
|
2017-01-16 08:56:30 +08:00
|
|
|
if (!config_prof) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return ENOENT;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2012-02-11 12:22:09 +08:00
|
|
|
|
2010-04-01 09:43:24 +08:00
|
|
|
if (newp != NULL) {
|
2014-10-04 14:25:30 +08:00
|
|
|
if (newlen != sizeof(bool)) {
|
|
|
|
ret = EINVAL;
|
|
|
|
goto label_return;
|
|
|
|
}
|
2016-05-11 13:21:10 +08:00
|
|
|
oldval = prof_active_set(tsd_tsdn(tsd), *(bool *)newp);
|
2017-01-16 08:56:30 +08:00
|
|
|
} else {
|
2016-05-11 13:21:10 +08:00
|
|
|
oldval = prof_active_get(tsd_tsdn(tsd));
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2010-04-01 09:43:24 +08:00
|
|
|
READ(oldval, bool);
|
|
|
|
|
|
|
|
ret = 0;
|
2012-04-11 06:07:44 +08:00
|
|
|
label_return:
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2010-04-01 09:43:24 +08:00
|
|
|
}
|
|
|
|
|
2010-02-12 05:19:21 +08:00
|
|
|
static int
|
2016-04-14 14:36:15 +08:00
|
|
|
prof_dump_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) {
|
2010-02-12 05:19:21 +08:00
|
|
|
int ret;
|
2010-03-03 03:57:30 +08:00
|
|
|
const char *filename = NULL;
|
2010-02-12 05:19:21 +08:00
|
|
|
|
2017-01-16 08:56:30 +08:00
|
|
|
if (!config_prof) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return ENOENT;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2012-02-11 12:22:09 +08:00
|
|
|
|
2010-03-03 03:57:30 +08:00
|
|
|
WRITEONLY();
|
|
|
|
WRITE(filename, const char *);
|
2010-02-12 05:19:21 +08:00
|
|
|
|
2016-04-14 14:36:15 +08:00
|
|
|
if (prof_mdump(tsd, filename)) {
|
2010-03-03 03:57:30 +08:00
|
|
|
ret = EFAULT;
|
2012-04-11 06:07:44 +08:00
|
|
|
goto label_return;
|
2010-03-03 03:57:30 +08:00
|
|
|
}
|
2010-02-12 05:19:21 +08:00
|
|
|
|
|
|
|
ret = 0;
|
2012-04-11 06:07:44 +08:00
|
|
|
label_return:
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2010-02-12 05:19:21 +08:00
|
|
|
}
|
|
|
|
|
2015-01-26 13:16:57 +08:00
|
|
|
static int
|
2016-04-14 14:36:15 +08:00
|
|
|
prof_gdump_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) {
|
2015-01-26 13:16:57 +08:00
|
|
|
int ret;
|
|
|
|
bool oldval;
|
|
|
|
|
2017-01-16 08:56:30 +08:00
|
|
|
if (!config_prof) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return ENOENT;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2015-01-26 13:16:57 +08:00
|
|
|
|
|
|
|
if (newp != NULL) {
|
|
|
|
if (newlen != sizeof(bool)) {
|
|
|
|
ret = EINVAL;
|
|
|
|
goto label_return;
|
|
|
|
}
|
2016-05-11 13:21:10 +08:00
|
|
|
oldval = prof_gdump_set(tsd_tsdn(tsd), *(bool *)newp);
|
2017-01-16 08:56:30 +08:00
|
|
|
} else {
|
2016-05-11 13:21:10 +08:00
|
|
|
oldval = prof_gdump_get(tsd_tsdn(tsd));
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2015-01-26 13:16:57 +08:00
|
|
|
READ(oldval, bool);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
label_return:
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2015-01-26 13:16:57 +08:00
|
|
|
}
|
|
|
|
|
2014-08-19 07:22:13 +08:00
|
|
|
static int
|
2016-04-14 14:36:15 +08:00
|
|
|
prof_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t *oldlenp, void *newp, size_t newlen) {
|
2014-08-19 07:22:13 +08:00
|
|
|
int ret;
|
|
|
|
size_t lg_sample = lg_prof_sample;
|
|
|
|
|
2017-01-16 08:56:30 +08:00
|
|
|
if (!config_prof) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return ENOENT;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2014-08-19 07:22:13 +08:00
|
|
|
|
|
|
|
WRITEONLY();
|
|
|
|
WRITE(lg_sample, size_t);
|
2017-01-16 08:56:30 +08:00
|
|
|
if (lg_sample >= (sizeof(uint64_t) << 3)) {
|
2014-08-19 07:22:13 +08:00
|
|
|
lg_sample = (sizeof(uint64_t) << 3) - 1;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2014-08-19 07:22:13 +08:00
|
|
|
|
2016-10-21 14:59:12 +08:00
|
|
|
prof_reset(tsd, lg_sample);
|
2014-08-19 07:22:13 +08:00
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
label_return:
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2014-08-19 07:22:13 +08:00
|
|
|
}
|
|
|
|
|
2012-02-11 12:22:09 +08:00
|
|
|
CTL_RO_NL_CGEN(config_prof, prof_interval, prof_interval, uint64_t)
|
2014-08-19 07:22:13 +08:00
|
|
|
CTL_RO_NL_CGEN(config_prof, lg_prof_sample, lg_prof_sample, size_t)
|
2010-02-12 05:19:21 +08:00
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2017-01-04 04:40:54 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_allocated, ctl_stats->allocated, size_t)
|
|
|
|
CTL_RO_CGEN(config_stats, stats_active, ctl_stats->active, size_t)
|
|
|
|
CTL_RO_CGEN(config_stats, stats_metadata, ctl_stats->metadata, size_t)
|
|
|
|
CTL_RO_CGEN(config_stats, stats_resident, ctl_stats->resident, size_t)
|
|
|
|
CTL_RO_CGEN(config_stats, stats_mapped, ctl_stats->mapped, size_t)
|
|
|
|
CTL_RO_CGEN(config_stats, stats_retained, ctl_stats->retained, size_t)
|
2013-12-20 13:40:41 +08:00
|
|
|
|
2017-01-19 15:03:37 +08:00
|
|
|
CTL_RO_GEN(stats_arenas_i_dss, arenas_i(mib[2])->dss, const char *)
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
CTL_RO_GEN(stats_arenas_i_dirty_decay_time, arenas_i(mib[2])->dirty_decay_time,
|
|
|
|
ssize_t)
|
|
|
|
CTL_RO_GEN(stats_arenas_i_muzzy_decay_time, arenas_i(mib[2])->muzzy_decay_time,
|
2016-02-20 12:09:31 +08:00
|
|
|
ssize_t)
|
2017-01-19 15:03:37 +08:00
|
|
|
CTL_RO_GEN(stats_arenas_i_nthreads, arenas_i(mib[2])->nthreads, unsigned)
|
|
|
|
CTL_RO_GEN(stats_arenas_i_pactive, arenas_i(mib[2])->pactive, size_t)
|
|
|
|
CTL_RO_GEN(stats_arenas_i_pdirty, arenas_i(mib[2])->pdirty, size_t)
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
CTL_RO_GEN(stats_arenas_i_pmuzzy, arenas_i(mib[2])->pmuzzy, size_t)
|
2013-12-20 13:40:41 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_mapped,
|
2017-03-14 07:18:40 +08:00
|
|
|
atomic_load_zu(&arenas_i(mib[2])->astats->astats.mapped, ATOMIC_RELAXED),
|
|
|
|
size_t)
|
2016-05-04 13:11:35 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_retained,
|
2017-03-14 07:18:40 +08:00
|
|
|
atomic_load_zu(&arenas_i(mib[2])->astats->astats.retained, ATOMIC_RELAXED),
|
|
|
|
size_t)
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
|
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_dirty_npurge,
|
|
|
|
arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.decay_dirty.npurge),
|
|
|
|
uint64_t)
|
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_dirty_nmadvise,
|
|
|
|
arena_stats_read_u64(
|
|
|
|
&arenas_i(mib[2])->astats->astats.decay_dirty.nmadvise), uint64_t)
|
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_dirty_purged,
|
|
|
|
arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.decay_dirty.purged),
|
|
|
|
uint64_t)
|
|
|
|
|
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_muzzy_npurge,
|
|
|
|
arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.decay_muzzy.npurge),
|
|
|
|
uint64_t)
|
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_muzzy_nmadvise,
|
|
|
|
arena_stats_read_u64(
|
|
|
|
&arenas_i(mib[2])->astats->astats.decay_muzzy.nmadvise), uint64_t)
|
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_muzzy_purged,
|
|
|
|
arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.decay_muzzy.purged),
|
|
|
|
uint64_t)
|
|
|
|
|
2016-12-23 06:39:10 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_base,
|
2017-03-14 07:18:40 +08:00
|
|
|
atomic_load_zu(&arenas_i(mib[2])->astats->astats.base, ATOMIC_RELAXED),
|
|
|
|
size_t)
|
2016-12-23 06:39:10 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_internal,
|
2017-03-14 07:18:40 +08:00
|
|
|
atomic_load_zu(&arenas_i(mib[2])->astats->astats.internal, ATOMIC_RELAXED),
|
|
|
|
size_t)
|
2016-04-23 09:37:44 +08:00
|
|
|
CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_tcache_bytes,
|
2017-03-14 07:18:40 +08:00
|
|
|
atomic_load_zu(&arenas_i(mib[2])->astats->astats.tcache_bytes,
|
|
|
|
ATOMIC_RELAXED), size_t)
|
2016-12-23 06:39:10 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_resident,
|
2017-03-14 07:18:40 +08:00
|
|
|
atomic_load_zu(&arenas_i(mib[2])->astats->astats.resident, ATOMIC_RELAXED),
|
|
|
|
size_t)
|
2013-12-20 13:40:41 +08:00
|
|
|
|
2012-02-11 12:22:09 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_small_allocated,
|
2017-01-19 15:03:37 +08:00
|
|
|
arenas_i(mib[2])->astats->allocated_small, size_t)
|
2012-02-11 12:22:09 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_small_nmalloc,
|
2017-01-19 15:03:37 +08:00
|
|
|
arenas_i(mib[2])->astats->nmalloc_small, uint64_t)
|
2012-02-11 12:22:09 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_small_ndalloc,
|
2017-01-19 15:03:37 +08:00
|
|
|
arenas_i(mib[2])->astats->ndalloc_small, uint64_t)
|
2012-02-11 12:22:09 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_small_nrequests,
|
2017-01-19 15:03:37 +08:00
|
|
|
arenas_i(mib[2])->astats->nrequests_small, uint64_t)
|
2016-06-01 05:50:21 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_large_allocated,
|
2017-03-14 07:18:40 +08:00
|
|
|
atomic_load_zu(&arenas_i(mib[2])->astats->astats.allocated_large,
|
|
|
|
ATOMIC_RELAXED), size_t)
|
2016-06-01 05:50:21 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_large_nmalloc,
|
2017-03-09 07:56:31 +08:00
|
|
|
arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.nmalloc_large),
|
|
|
|
uint64_t)
|
2016-06-01 05:50:21 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_large_ndalloc,
|
2017-03-09 07:56:31 +08:00
|
|
|
arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.ndalloc_large),
|
|
|
|
uint64_t)
|
2016-06-01 05:50:21 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_large_nrequests,
|
2017-03-09 07:56:31 +08:00
|
|
|
arena_stats_read_u64(&arenas_i(mib[2])->astats->astats.nmalloc_large),
|
|
|
|
uint64_t) /* Intentional. */
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2012-02-11 12:22:09 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nmalloc,
|
2017-01-19 15:03:37 +08:00
|
|
|
arenas_i(mib[2])->astats->bstats[mib[4]].nmalloc, uint64_t)
|
2012-02-11 12:22:09 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_ndalloc,
|
2017-01-19 15:03:37 +08:00
|
|
|
arenas_i(mib[2])->astats->bstats[mib[4]].ndalloc, uint64_t)
|
2012-02-11 12:22:09 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nrequests,
|
2017-01-19 15:03:37 +08:00
|
|
|
arenas_i(mib[2])->astats->bstats[mib[4]].nrequests, uint64_t)
|
2014-10-13 13:53:59 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curregs,
|
2017-01-19 15:03:37 +08:00
|
|
|
arenas_i(mib[2])->astats->bstats[mib[4]].curregs, size_t)
|
2012-02-11 12:22:09 +08:00
|
|
|
CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nfills,
|
2017-01-19 15:03:37 +08:00
|
|
|
arenas_i(mib[2])->astats->bstats[mib[4]].nfills, uint64_t)
|
2012-02-11 12:22:09 +08:00
|
|
|
CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nflushes,
|
2017-01-19 15:03:37 +08:00
|
|
|
arenas_i(mib[2])->astats->bstats[mib[4]].nflushes, uint64_t)
|
2016-05-30 09:34:50 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nslabs,
|
2017-01-19 15:03:37 +08:00
|
|
|
arenas_i(mib[2])->astats->bstats[mib[4]].nslabs, uint64_t)
|
2016-05-30 09:34:50 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nreslabs,
|
2017-01-19 15:03:37 +08:00
|
|
|
arenas_i(mib[2])->astats->bstats[mib[4]].reslabs, uint64_t)
|
2016-05-30 09:34:50 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curslabs,
|
2017-01-19 15:03:37 +08:00
|
|
|
arenas_i(mib[2])->astats->bstats[mib[4]].curslabs, size_t)
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2012-10-12 04:53:15 +08:00
|
|
|
static const ctl_named_node_t *
|
2016-05-11 13:21:10 +08:00
|
|
|
stats_arenas_i_bins_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t j) {
|
|
|
|
if (j > NBINS) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return NULL;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2017-01-20 10:15:45 +08:00
|
|
|
return super_stats_arenas_i_bins_j_node;
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|
|
|
|
|
2016-06-01 05:50:21 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_nmalloc,
|
2017-03-09 07:56:31 +08:00
|
|
|
arena_stats_read_u64(&arenas_i(mib[2])->astats->lstats[mib[4]].nmalloc),
|
|
|
|
uint64_t)
|
2016-06-01 05:50:21 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_ndalloc,
|
2017-03-09 07:56:31 +08:00
|
|
|
arena_stats_read_u64(&arenas_i(mib[2])->astats->lstats[mib[4]].ndalloc),
|
|
|
|
uint64_t)
|
2016-06-01 05:50:21 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_nrequests,
|
Implement two-phase decay-based purging.
Split decay-based purging into two phases, the first of which uses lazy
purging to convert dirty pages to "muzzy", and the second of which uses
forced purging, decommit, or unmapping to convert pages to clean or
destroy them altogether. Not all operating systems support lazy
purging, yet the application may provide extent hooks that implement
lazy purging, so care must be taken to dynamically omit the first phase
when necessary.
The mallctl interfaces change as follows:
- opt.decay_time --> opt.{dirty,muzzy}_decay_time
- arena.<i>.decay_time --> arena.<i>.{dirty,muzzy}_decay_time
- arenas.decay_time --> arenas.{dirty,muzzy}_decay_time
- stats.arenas.<i>.pdirty --> stats.arenas.<i>.p{dirty,muzzy}
- stats.arenas.<i>.{npurge,nmadvise,purged} -->
stats.arenas.<i>.{dirty,muzzy}_{npurge,nmadvise,purged}
This resolves #521.
2017-03-09 14:42:57 +08:00
|
|
|
arena_stats_read_u64(&arenas_i(mib[2])->astats->lstats[mib[4]].nrequests),
|
|
|
|
uint64_t)
|
2016-06-01 05:50:21 +08:00
|
|
|
CTL_RO_CGEN(config_stats, stats_arenas_i_lextents_j_curlextents,
|
2017-01-19 15:03:37 +08:00
|
|
|
arenas_i(mib[2])->astats->lstats[mib[4]].curlextents, size_t)
|
2014-10-13 13:53:59 +08:00
|
|
|
|
|
|
|
static const ctl_named_node_t *
|
2016-06-01 05:50:21 +08:00
|
|
|
stats_arenas_i_lextents_j_index(tsdn_t *tsdn, const size_t *mib, size_t miblen,
|
2017-01-16 08:56:30 +08:00
|
|
|
size_t j) {
|
|
|
|
if (j > NSIZES - NBINS) {
|
2017-01-20 10:15:45 +08:00
|
|
|
return NULL;
|
2017-01-16 08:56:30 +08:00
|
|
|
}
|
2017-01-20 10:15:45 +08:00
|
|
|
return super_stats_arenas_i_lextents_j_node;
|
2014-10-13 13:53:59 +08:00
|
|
|
}
|
|
|
|
|
2012-10-12 04:53:15 +08:00
|
|
|
static const ctl_named_node_t *
|
2017-01-16 08:56:30 +08:00
|
|
|
stats_arenas_i_index(tsdn_t *tsdn, const size_t *mib, size_t miblen, size_t i) {
|
2017-01-03 23:27:42 +08:00
|
|
|
const ctl_named_node_t *ret;
|
|
|
|
size_t a;
|
2010-01-28 05:10:55 +08:00
|
|
|
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_lock(tsdn, &ctl_mtx);
|
2017-01-19 15:03:37 +08:00
|
|
|
a = arenas_i2a_impl(i, true, true);
|
|
|
|
if (a == UINT_MAX || !ctl_arenas->arenas[a]->initialized) {
|
2010-11-25 07:44:21 +08:00
|
|
|
ret = NULL;
|
2012-04-11 06:07:44 +08:00
|
|
|
goto label_return;
|
2010-11-25 07:44:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = super_stats_arenas_i_node;
|
2012-04-11 06:07:44 +08:00
|
|
|
label_return:
|
2016-05-11 13:21:10 +08:00
|
|
|
malloc_mutex_unlock(tsdn, &ctl_mtx);
|
2017-01-20 10:15:45 +08:00
|
|
|
return ret;
|
2010-01-28 05:10:55 +08:00
|
|
|
}
|