This commit is contained in:
Slobodan Predolac 2026-05-28 22:18:36 -04:00 committed by GitHub
commit 2512efbe5a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
49 changed files with 4171 additions and 4241 deletions

View file

@ -109,6 +109,15 @@ C_SRCS := $(srcroot)src/jemalloc.c \
$(srcroot)src/ckh.c \
$(srcroot)src/counter.c \
$(srcroot)src/ctl.c \
$(srcroot)src/ctl_arena.c \
$(srcroot)src/ctl_background_thread.c \
$(srcroot)src/ctl_config.c \
$(srcroot)src/ctl_opt.c \
$(srcroot)src/ctl_prof.c \
$(srcroot)src/ctl_stats.c \
$(srcroot)src/ctl_thread.c \
$(srcroot)src/ctl_tcache.c \
$(srcroot)src/ctl_utilization.c \
$(srcroot)src/decay.c \
$(srcroot)src/div.c \
$(srcroot)src/ecache.c \

View file

@ -115,7 +115,11 @@ bool ctl_boot(void);
void ctl_prefork(tsdn_t *tsdn);
void ctl_postfork_parent(tsdn_t *tsdn);
void ctl_postfork_child(tsdn_t *tsdn);
void ctl_mtx_lock(tsdn_t *tsdn);
void ctl_mtx_unlock(tsdn_t *tsdn);
void ctl_mtx_assert_held(tsdn_t *tsdn);
void ctl_mtx_prof_read(tsdn_t *tsdn, mutex_prof_data_t *mutex_prof_data);
void ctl_mtx_prof_data_reset(tsdn_t *tsdn);
#define xmallctl(name, oldp, oldlenp, newp, newlen) \
do { \

View file

@ -0,0 +1,54 @@
#ifndef JEMALLOC_INTERNAL_CTL_ARENA_H
#define JEMALLOC_INTERNAL_CTL_ARENA_H
#include "jemalloc/internal/ctl_mallctl.h"
#define CTL_ARENA_PROTO(n) \
int n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, \
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
CTL_ARENA_PROTO(arena_i_initialized)
CTL_ARENA_PROTO(arena_i_decay)
CTL_ARENA_PROTO(arena_i_purge)
CTL_ARENA_PROTO(arena_i_reset)
CTL_ARENA_PROTO(arena_i_destroy)
CTL_ARENA_PROTO(arena_i_dss)
CTL_ARENA_PROTO(arena_i_oversize_threshold)
CTL_ARENA_PROTO(arena_i_dirty_decay_ms)
CTL_ARENA_PROTO(arena_i_muzzy_decay_ms)
CTL_ARENA_PROTO(arena_i_extent_hooks)
CTL_ARENA_PROTO(arena_i_retain_grow_limit)
CTL_ARENA_PROTO(arena_i_name)
CTL_ARENA_PROTO(arenas_narenas)
CTL_ARENA_PROTO(arenas_dirty_decay_ms)
CTL_ARENA_PROTO(arenas_muzzy_decay_ms)
CTL_ARENA_PROTO(arenas_quantum)
CTL_ARENA_PROTO(arenas_page)
CTL_ARENA_PROTO(arenas_hugepage)
CTL_ARENA_PROTO(arenas_tcache_max)
CTL_ARENA_PROTO(arenas_nbins)
CTL_ARENA_PROTO(arenas_nhbins)
CTL_ARENA_PROTO(arenas_bin_i_size)
CTL_ARENA_PROTO(arenas_bin_i_nregs)
CTL_ARENA_PROTO(arenas_bin_i_slab_size)
CTL_ARENA_PROTO(arenas_bin_i_nshards)
CTL_ARENA_PROTO(arenas_nlextents)
CTL_ARENA_PROTO(arenas_lextent_i_size)
CTL_ARENA_PROTO(arenas_create)
CTL_ARENA_PROTO(arenas_lookup)
CTL_ARENA_PROTO(experimental_arenas_create_ext)
#undef CTL_ARENA_PROTO
bool ctl_arenas_init(tsd_t *tsd);
ctl_arena_t *ctl_arenas_refresh(tsdn_t *tsdn);
ctl_arena_t *ctl_arenas_i(size_t i);
uint64_t ctl_arenas_epoch_get(void);
void ctl_arenas_epoch_advance(void);
bool ctl_arena_i_indexable(tsdn_t *tsdn, size_t i);
bool ctl_arenas_i_verify(size_t i);
int ctl_arena_create(tsd_t *tsd, void *oldp, size_t *oldlenp,
const arena_config_t *config);
#endif /* JEMALLOC_INTERNAL_CTL_ARENA_H */

View file

@ -0,0 +1,11 @@
#ifndef JEMALLOC_INTERNAL_CTL_BACKGROUND_THREAD_H
#define JEMALLOC_INTERNAL_CTL_BACKGROUND_THREAD_H
#include "jemalloc/internal/ctl_mallctl.h"
int background_thread_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int max_background_threads_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
#endif /* JEMALLOC_INTERNAL_CTL_BACKGROUND_THREAD_H */

View file

@ -0,0 +1,33 @@
#ifndef JEMALLOC_INTERNAL_CTL_CONFIG_H
#define JEMALLOC_INTERNAL_CTL_CONFIG_H
#include "jemalloc/internal/ctl_mallctl.h"
int config_cache_oblivious_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int config_debug_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen);
int config_fill_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen);
int config_lazy_lock_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int config_malloc_conf_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int config_opt_safety_checks_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int config_prof_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen);
int config_prof_libgcc_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int config_prof_libunwind_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int config_prof_frameptr_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int config_stats_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen);
int config_utrace_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen);
int config_xmalloc_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen);
#endif /* JEMALLOC_INTERNAL_CTL_CONFIG_H */

View file

@ -0,0 +1,170 @@
#ifndef JEMALLOC_INTERNAL_CTL_MALLCTL_H
#define JEMALLOC_INTERNAL_CTL_MALLCTL_H
#include "jemalloc/internal/ctl.h"
#define READONLY() \
do { \
if (newp != NULL || newlen != 0) { \
ret = EPERM; \
goto label_return; \
} \
} while (0)
#define WRITEONLY() \
do { \
if (oldp != NULL || oldlenp != NULL) { \
ret = EPERM; \
goto label_return; \
} \
} while (0)
/* Can read or write, but not both. */
#define READ_XOR_WRITE() \
do { \
if ((oldp != NULL && oldlenp != NULL) \
&& (newp != NULL || newlen != 0)) { \
ret = EPERM; \
goto label_return; \
} \
} while (0)
/* Can neither read nor write. */
#define NEITHER_READ_NOR_WRITE() \
do { \
if (oldp != NULL || oldlenp != NULL || newp != NULL \
|| newlen != 0) { \
ret = EPERM; \
goto label_return; \
} \
} while (0)
/* Verify that the space provided is enough. */
#define VERIFY_READ(t) \
do { \
if (oldp == NULL || oldlenp == NULL \
|| *oldlenp != sizeof(t)) { \
if (oldlenp != NULL) { \
*oldlenp = 0; \
} \
ret = EINVAL; \
goto label_return; \
} \
} while (0)
#define READ(v, t) \
do { \
if (oldp != NULL && oldlenp != NULL) { \
if (*oldlenp != sizeof(t)) { \
size_t copylen = (sizeof(t) <= *oldlenp) \
? sizeof(t) \
: *oldlenp; \
memcpy(oldp, (void *)&(v), copylen); \
*oldlenp = copylen; \
ret = EINVAL; \
goto label_return; \
} \
*(t *)oldp = (v); \
} \
} while (0)
#define WRITE(v, t) \
do { \
if (newp != NULL) { \
if (newlen != sizeof(t)) { \
ret = EINVAL; \
goto label_return; \
} \
(v) = *(t *)newp; \
} \
} while (0)
#define ASSURED_WRITE(v, t) \
do { \
if (newp == NULL || newlen != sizeof(t)) { \
ret = EINVAL; \
goto label_return; \
} \
(v) = *(t *)newp; \
} while (0)
#define MIB_UNSIGNED(v, i) \
do { \
if (mib[i] > UINT_MAX) { \
ret = EFAULT; \
goto label_return; \
} \
v = (unsigned)mib[i]; \
} while (0)
#define CTL_RO_NL_GEN_PUBLIC(n, v, t) \
int n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, \
void *oldp, size_t *oldlenp, void *newp, size_t newlen) { \
int ret; \
t oldval; \
\
READONLY(); \
oldval = (v); \
READ(oldval, t); \
\
ret = 0; \
label_return: \
return ret; \
}
#define CTL_RO_GEN_PUBLIC(n, v, t) \
int n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, \
void *oldp, size_t *oldlenp, void *newp, size_t newlen) { \
int ret; \
t oldval; \
\
READONLY(); \
ctl_mtx_lock(tsd_tsdn(tsd)); \
oldval = (v); \
READ(oldval, t); \
\
ret = 0; \
label_return: \
ctl_mtx_unlock(tsd_tsdn(tsd)); \
return ret; \
}
#define CTL_RO_NL_CGEN_PUBLIC(c, n, v, t) \
int n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, \
void *oldp, size_t *oldlenp, void *newp, size_t newlen) { \
int ret; \
t oldval; \
\
if (!(c)) { \
return ENOENT; \
} \
READONLY(); \
oldval = (v); \
READ(oldval, t); \
\
ret = 0; \
label_return: \
return ret; \
}
#define CTL_RO_CGEN_PUBLIC(c, n, v, t) \
int n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, \
void *oldp, size_t *oldlenp, void *newp, size_t newlen) { \
int ret; \
t oldval; \
\
if (!(c)) { \
return ENOENT; \
} \
READONLY(); \
ctl_mtx_lock(tsd_tsdn(tsd)); \
oldval = (v); \
READ(oldval, t); \
\
ret = 0; \
label_return: \
ctl_mtx_unlock(tsd_tsdn(tsd)); \
return ret; \
}
#endif /* JEMALLOC_INTERNAL_CTL_MALLCTL_H */

View file

@ -0,0 +1,93 @@
#ifndef JEMALLOC_INTERNAL_CTL_OPT_H
#define JEMALLOC_INTERNAL_CTL_OPT_H
#include "jemalloc/internal/ctl_mallctl.h"
#define CTL_OPT_PROTO(n) \
int n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, \
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
CTL_OPT_PROTO(opt_abort)
CTL_OPT_PROTO(opt_abort_conf)
CTL_OPT_PROTO(opt_cache_oblivious)
CTL_OPT_PROTO(opt_debug_double_free_max_scan)
CTL_OPT_PROTO(opt_trust_madvise)
CTL_OPT_PROTO(opt_experimental_hpa_start_huge_if_thp_always)
CTL_OPT_PROTO(opt_experimental_hpa_enforce_hugify)
CTL_OPT_PROTO(opt_confirm_conf)
CTL_OPT_PROTO(opt_hpa)
CTL_OPT_PROTO(opt_hpa_slab_max_alloc)
CTL_OPT_PROTO(opt_hpa_hugification_threshold)
CTL_OPT_PROTO(opt_hpa_hugify_delay_ms)
CTL_OPT_PROTO(opt_hpa_hugify_sync)
CTL_OPT_PROTO(opt_hpa_min_purge_interval_ms)
CTL_OPT_PROTO(opt_experimental_hpa_max_purge_nhp)
CTL_OPT_PROTO(opt_hpa_purge_threshold)
CTL_OPT_PROTO(opt_hpa_min_purge_delay_ms)
CTL_OPT_PROTO(opt_hpa_hugify_style)
CTL_OPT_PROTO(opt_hpa_dirty_mult)
CTL_OPT_PROTO(opt_hpa_sec_nshards)
CTL_OPT_PROTO(opt_hpa_sec_max_alloc)
CTL_OPT_PROTO(opt_hpa_sec_max_bytes)
CTL_OPT_PROTO(opt_huge_arena_pac_thp)
CTL_OPT_PROTO(opt_metadata_thp)
CTL_OPT_PROTO(opt_retain)
CTL_OPT_PROTO(opt_dss)
CTL_OPT_PROTO(opt_narenas)
CTL_OPT_PROTO(opt_percpu_arena)
CTL_OPT_PROTO(opt_oversize_threshold)
CTL_OPT_PROTO(opt_background_thread)
CTL_OPT_PROTO(opt_mutex_max_spin)
CTL_OPT_PROTO(opt_max_background_threads)
CTL_OPT_PROTO(opt_dirty_decay_ms)
CTL_OPT_PROTO(opt_muzzy_decay_ms)
CTL_OPT_PROTO(opt_stats_print)
CTL_OPT_PROTO(opt_stats_print_opts)
CTL_OPT_PROTO(opt_stats_interval)
CTL_OPT_PROTO(opt_stats_interval_opts)
CTL_OPT_PROTO(opt_junk)
CTL_OPT_PROTO(opt_zero)
CTL_OPT_PROTO(opt_utrace)
CTL_OPT_PROTO(opt_xmalloc)
CTL_OPT_PROTO(opt_experimental_infallible_new)
CTL_OPT_PROTO(opt_experimental_tcache_gc)
CTL_OPT_PROTO(opt_tcache)
CTL_OPT_PROTO(opt_tcache_max)
CTL_OPT_PROTO(opt_tcache_nslots_small_min)
CTL_OPT_PROTO(opt_tcache_nslots_small_max)
CTL_OPT_PROTO(opt_tcache_nslots_large)
CTL_OPT_PROTO(opt_lg_tcache_nslots_mul)
CTL_OPT_PROTO(opt_tcache_gc_incr_bytes)
CTL_OPT_PROTO(opt_tcache_gc_delay_bytes)
CTL_OPT_PROTO(opt_lg_tcache_flush_small_div)
CTL_OPT_PROTO(opt_lg_tcache_flush_large_div)
CTL_OPT_PROTO(opt_thp)
CTL_OPT_PROTO(opt_lg_extent_max_active_fit)
CTL_OPT_PROTO(opt_prof)
CTL_OPT_PROTO(opt_prof_prefix)
CTL_OPT_PROTO(opt_prof_active)
CTL_OPT_PROTO(opt_prof_thread_active_init)
CTL_OPT_PROTO(opt_prof_bt_max)
CTL_OPT_PROTO(opt_lg_prof_sample)
CTL_OPT_PROTO(opt_lg_prof_interval)
CTL_OPT_PROTO(opt_prof_gdump)
CTL_OPT_PROTO(opt_prof_final)
CTL_OPT_PROTO(opt_prof_leak)
CTL_OPT_PROTO(opt_prof_leak_error)
CTL_OPT_PROTO(opt_prof_accum)
CTL_OPT_PROTO(opt_prof_pid_namespace)
CTL_OPT_PROTO(opt_prof_recent_alloc_max)
CTL_OPT_PROTO(opt_prof_stats)
CTL_OPT_PROTO(opt_prof_sys_thread_name)
CTL_OPT_PROTO(opt_prof_time_res)
CTL_OPT_PROTO(opt_lg_san_uaf_align)
CTL_OPT_PROTO(opt_zero_realloc)
CTL_OPT_PROTO(opt_disable_large_size_classes)
CTL_OPT_PROTO(opt_process_madvise_max_batch)
CTL_OPT_PROTO(opt_malloc_conf_symlink)
CTL_OPT_PROTO(opt_malloc_conf_env_var)
CTL_OPT_PROTO(opt_malloc_conf_global_var)
#undef CTL_OPT_PROTO
#endif /* JEMALLOC_INTERNAL_CTL_OPT_H */

View file

@ -0,0 +1,33 @@
#ifndef JEMALLOC_INTERNAL_CTL_PROF_H
#define JEMALLOC_INTERNAL_CTL_PROF_H
#include "jemalloc/internal/ctl_mallctl.h"
#define CTL_PROF_PROTO(n) \
int n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, \
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
CTL_PROF_PROTO(prof_thread_active_init)
CTL_PROF_PROTO(prof_active)
CTL_PROF_PROTO(prof_dump)
CTL_PROF_PROTO(prof_gdump)
CTL_PROF_PROTO(prof_prefix)
CTL_PROF_PROTO(prof_reset)
CTL_PROF_PROTO(prof_interval)
CTL_PROF_PROTO(lg_prof_sample)
CTL_PROF_PROTO(prof_log_start)
CTL_PROF_PROTO(prof_log_stop)
CTL_PROF_PROTO(prof_stats_bins_i_live)
CTL_PROF_PROTO(prof_stats_bins_i_accum)
CTL_PROF_PROTO(prof_stats_lextents_i_live)
CTL_PROF_PROTO(prof_stats_lextents_i_accum)
CTL_PROF_PROTO(experimental_hooks_prof_backtrace)
CTL_PROF_PROTO(experimental_hooks_prof_dump)
CTL_PROF_PROTO(experimental_hooks_prof_sample)
CTL_PROF_PROTO(experimental_hooks_prof_sample_free)
CTL_PROF_PROTO(experimental_prof_recent_alloc_max)
CTL_PROF_PROTO(experimental_prof_recent_alloc_dump)
#undef CTL_PROF_PROTO
#endif /* JEMALLOC_INTERNAL_CTL_PROF_H */

View file

@ -0,0 +1,179 @@
#ifndef JEMALLOC_INTERNAL_CTL_STATS_H
#define JEMALLOC_INTERNAL_CTL_STATS_H
#include "jemalloc/internal/ctl_mallctl.h"
#define CTL_STATS_PROTO(n) \
int n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, \
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
CTL_STATS_PROTO(stats_arenas_i_small_allocated)
CTL_STATS_PROTO(stats_arenas_i_small_nmalloc)
CTL_STATS_PROTO(stats_arenas_i_small_ndalloc)
CTL_STATS_PROTO(stats_arenas_i_small_nrequests)
CTL_STATS_PROTO(stats_arenas_i_small_nfills)
CTL_STATS_PROTO(stats_arenas_i_small_nflushes)
CTL_STATS_PROTO(stats_arenas_i_large_allocated)
CTL_STATS_PROTO(stats_arenas_i_large_nmalloc)
CTL_STATS_PROTO(stats_arenas_i_large_ndalloc)
CTL_STATS_PROTO(stats_arenas_i_large_nrequests)
CTL_STATS_PROTO(stats_arenas_i_large_nfills)
CTL_STATS_PROTO(stats_arenas_i_large_nflushes)
CTL_STATS_PROTO(stats_arenas_i_bins_j_nmalloc)
CTL_STATS_PROTO(stats_arenas_i_bins_j_ndalloc)
CTL_STATS_PROTO(stats_arenas_i_bins_j_nrequests)
CTL_STATS_PROTO(stats_arenas_i_bins_j_curregs)
CTL_STATS_PROTO(stats_arenas_i_bins_j_nfills)
CTL_STATS_PROTO(stats_arenas_i_bins_j_nflushes)
CTL_STATS_PROTO(stats_arenas_i_bins_j_nslabs)
CTL_STATS_PROTO(stats_arenas_i_bins_j_nreslabs)
CTL_STATS_PROTO(stats_arenas_i_bins_j_curslabs)
CTL_STATS_PROTO(stats_arenas_i_bins_j_nonfull_slabs)
CTL_STATS_PROTO(stats_arenas_i_lextents_j_nmalloc)
CTL_STATS_PROTO(stats_arenas_i_lextents_j_ndalloc)
CTL_STATS_PROTO(stats_arenas_i_lextents_j_nrequests)
CTL_STATS_PROTO(stats_arenas_i_lextents_j_curlextents)
CTL_STATS_PROTO(stats_arenas_i_extents_j_ndirty)
CTL_STATS_PROTO(stats_arenas_i_extents_j_nmuzzy)
CTL_STATS_PROTO(stats_arenas_i_extents_j_nretained)
CTL_STATS_PROTO(stats_arenas_i_extents_j_npinned)
CTL_STATS_PROTO(stats_arenas_i_extents_j_dirty_bytes)
CTL_STATS_PROTO(stats_arenas_i_extents_j_muzzy_bytes)
CTL_STATS_PROTO(stats_arenas_i_extents_j_retained_bytes)
CTL_STATS_PROTO(stats_arenas_i_extents_j_pinned_bytes)
/* Merged set of stats for HPA shard. */
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_npageslabs)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_nactive)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_ndirty)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_npurge_passes)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_npurges)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_nhugifies)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_nhugify_failures)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_ndehugifies)
/* Set of stats for non-hugified and hugified slabs. */
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_slabs_npageslabs_nonhuge)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_slabs_npageslabs_huge)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_slabs_nactive_nonhuge)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_slabs_nactive_huge)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_slabs_ndirty_nonhuge)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_slabs_ndirty_huge)
/* A parallel set of stats for full slabs. */
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_full_slabs_npageslabs_nonhuge)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_full_slabs_npageslabs_huge)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_full_slabs_nactive_nonhuge)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_full_slabs_nactive_huge)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_full_slabs_ndirty_nonhuge)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_full_slabs_ndirty_huge)
/* A parallel set for the empty slabs. */
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_empty_slabs_npageslabs_nonhuge)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_empty_slabs_npageslabs_huge)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_empty_slabs_nactive_nonhuge)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_empty_slabs_nactive_huge)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_empty_slabs_ndirty_nonhuge)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_empty_slabs_ndirty_huge)
/*
* And one for the slabs that are neither empty nor full, but indexed by how
* full they are.
*/
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_nonfull_slabs_j_npageslabs_nonhuge)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_nonfull_slabs_j_npageslabs_huge)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_nonfull_slabs_j_nactive_nonhuge)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_nonfull_slabs_j_nactive_huge)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_nonfull_slabs_j_ndirty_nonhuge)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_nonfull_slabs_j_ndirty_huge)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_alloc_j_min_extents)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_alloc_j_max_extents)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_alloc_j_extents)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_alloc_j_ps)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_alloc_j_pages_per_ps)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_alloc_j_extents_per_ps)
CTL_STATS_PROTO(stats_arenas_i_hpa_shard_alloc_j_total_elapsed_ns_per_ps)
CTL_STATS_PROTO(stats_arenas_i_nthreads)
CTL_STATS_PROTO(stats_arenas_i_uptime)
CTL_STATS_PROTO(stats_arenas_i_dss)
CTL_STATS_PROTO(stats_arenas_i_dirty_decay_ms)
CTL_STATS_PROTO(stats_arenas_i_muzzy_decay_ms)
CTL_STATS_PROTO(stats_arenas_i_pactive)
CTL_STATS_PROTO(stats_arenas_i_pdirty)
CTL_STATS_PROTO(stats_arenas_i_pmuzzy)
CTL_STATS_PROTO(stats_arenas_i_mapped)
CTL_STATS_PROTO(stats_arenas_i_retained)
CTL_STATS_PROTO(stats_arenas_i_pinned)
CTL_STATS_PROTO(stats_arenas_i_extent_avail)
CTL_STATS_PROTO(stats_arenas_i_dirty_npurge)
CTL_STATS_PROTO(stats_arenas_i_dirty_nmadvise)
CTL_STATS_PROTO(stats_arenas_i_dirty_purged)
CTL_STATS_PROTO(stats_arenas_i_muzzy_npurge)
CTL_STATS_PROTO(stats_arenas_i_muzzy_nmadvise)
CTL_STATS_PROTO(stats_arenas_i_muzzy_purged)
CTL_STATS_PROTO(stats_arenas_i_base)
CTL_STATS_PROTO(stats_arenas_i_internal)
CTL_STATS_PROTO(stats_arenas_i_metadata_edata)
CTL_STATS_PROTO(stats_arenas_i_metadata_rtree)
CTL_STATS_PROTO(stats_arenas_i_metadata_thp)
CTL_STATS_PROTO(stats_arenas_i_tcache_bytes)
CTL_STATS_PROTO(stats_arenas_i_tcache_stashed_bytes)
CTL_STATS_PROTO(stats_arenas_i_resident)
CTL_STATS_PROTO(stats_arenas_i_abandoned_vm)
CTL_STATS_PROTO(stats_arenas_i_hpa_sec_bytes)
CTL_STATS_PROTO(stats_arenas_i_hpa_sec_hits)
CTL_STATS_PROTO(stats_arenas_i_hpa_sec_misses)
CTL_STATS_PROTO(stats_arenas_i_hpa_sec_dalloc_flush)
CTL_STATS_PROTO(stats_arenas_i_hpa_sec_dalloc_noflush)
CTL_STATS_PROTO(stats_arenas_i_hpa_sec_overfills)
CTL_STATS_PROTO(stats_allocated)
CTL_STATS_PROTO(stats_active)
CTL_STATS_PROTO(stats_background_thread_num_threads)
CTL_STATS_PROTO(stats_background_thread_num_runs)
CTL_STATS_PROTO(stats_background_thread_run_interval)
CTL_STATS_PROTO(stats_metadata)
CTL_STATS_PROTO(stats_metadata_edata)
CTL_STATS_PROTO(stats_metadata_rtree)
CTL_STATS_PROTO(stats_metadata_thp)
CTL_STATS_PROTO(stats_resident)
CTL_STATS_PROTO(stats_mapped)
CTL_STATS_PROTO(stats_retained)
CTL_STATS_PROTO(stats_pinned)
CTL_STATS_PROTO(stats_zero_reallocs)
CTL_STATS_PROTO(approximate_stats_active)
#define MUTEX_STATS_CTL_PROTO_GEN(n) \
CTL_STATS_PROTO(stats_##n##_num_ops) \
CTL_STATS_PROTO(stats_##n##_num_wait) \
CTL_STATS_PROTO(stats_##n##_num_spin_acq) \
CTL_STATS_PROTO(stats_##n##_num_owner_switch) \
CTL_STATS_PROTO(stats_##n##_total_wait_time) \
CTL_STATS_PROTO(stats_##n##_max_wait_time) \
CTL_STATS_PROTO(stats_##n##_max_num_thds)
/* Global mutexes. */
#define OP(mtx) MUTEX_STATS_CTL_PROTO_GEN(mutexes_##mtx)
MUTEX_PROF_GLOBAL_MUTEXES
#undef OP
/* Per arena mutexes. */
#define OP(mtx) MUTEX_STATS_CTL_PROTO_GEN(arenas_i_mutexes_##mtx)
MUTEX_PROF_ARENA_MUTEXES
#undef OP
/* Arena bin mutexes. */
MUTEX_STATS_CTL_PROTO_GEN(arenas_i_bins_j_mutex)
#undef MUTEX_STATS_CTL_PROTO_GEN
CTL_STATS_PROTO(stats_mutexes_reset)
#undef CTL_STATS_PROTO
bool ctl_stats_init(tsdn_t *tsdn);
void ctl_stats_refresh(tsdn_t *tsdn, ctl_arena_t *ctl_sarena);
#endif /* JEMALLOC_INTERNAL_CTL_STATS_H */

View file

@ -0,0 +1,13 @@
#ifndef JEMALLOC_INTERNAL_CTL_TCACHE_H
#define JEMALLOC_INTERNAL_CTL_TCACHE_H
#include "jemalloc/internal/ctl_mallctl.h"
int tcache_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen);
int tcache_flush_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen);
int tcache_destroy_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen);
#endif /* JEMALLOC_INTERNAL_CTL_TCACHE_H */

View file

@ -0,0 +1,39 @@
#ifndef JEMALLOC_INTERNAL_CTL_THREAD_H
#define JEMALLOC_INTERNAL_CTL_THREAD_H
#include "jemalloc/internal/ctl_mallctl.h"
int thread_tcache_enabled_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int thread_tcache_max_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int thread_tcache_flush_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int thread_tcache_ncached_max_write_ctl(tsd_t *tsd, const size_t *mib,
size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int thread_tcache_ncached_max_read_sizeclass_ctl(tsd_t *tsd, const size_t *mib,
size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int thread_peak_read_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int thread_peak_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int thread_prof_name_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int thread_prof_active_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int thread_arena_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen);
int thread_allocated_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int thread_allocatedp_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int thread_deallocated_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int thread_deallocatedp_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen);
int thread_idle_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen);
int experimental_hooks_thread_event_ctl(tsd_t *tsd, const size_t *mib,
size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
#endif /* JEMALLOC_INTERNAL_CTL_THREAD_H */

View file

@ -0,0 +1,9 @@
#ifndef JEMALLOC_INTERNAL_CTL_UTILIZATION_H
#define JEMALLOC_INTERNAL_CTL_UTILIZATION_H
#include "jemalloc/internal/ctl_mallctl.h"
int experimental_utilization_batch_query_ctl(tsd_t *tsd, const size_t *mib,
size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
#endif /* JEMALLOC_INTERNAL_CTL_UTILIZATION_H */

View file

@ -11,9 +11,8 @@
*/
/*
* The following two structs are for experimental purposes. See
* experimental_utilization_query_ctl and
* experimental_utilization_batch_query_ctl in src/ctl.c.
* The following struct is for experimental purposes. See
* experimental_utilization_batch_query_ctl in src/ctl_utilization.c.
*/
typedef struct inspect_extent_util_stats_s inspect_extent_util_stats_t;
struct inspect_extent_util_stats_s {
@ -22,22 +21,7 @@ struct inspect_extent_util_stats_s {
size_t size;
};
typedef struct inspect_extent_util_stats_verbose_s
inspect_extent_util_stats_verbose_t;
struct inspect_extent_util_stats_verbose_s {
void *slabcur_addr;
size_t nfree;
size_t nregs;
size_t size;
size_t bin_nfree;
size_t bin_nregs;
};
void inspect_extent_util_stats_get(
tsdn_t *tsdn, const void *ptr, size_t *nfree, size_t *nregs, size_t *size);
void inspect_extent_util_stats_verbose_get(tsdn_t *tsdn, const void *ptr,
size_t *nfree, size_t *nregs, size_t *size, size_t *bin_nfree,
size_t *bin_nregs, void **slabcur_addr);
#endif /* JEMALLOC_INTERNAL_INSPECT_H */

View file

@ -46,6 +46,7 @@ extern bool opt_disable_large_size_classes;
extern const char *opt_malloc_conf_symlink;
extern const char *opt_malloc_conf_env_var;
extern const char *je_malloc_conf_2_conf_harder;
/* Escape free-fastpath when ptr & mask == 0 (for sanitization purpose). */
extern uintptr_t san_cache_bin_nonfast_mask;

View file

@ -11,11 +11,6 @@ void safety_check_fail_sized_dealloc(
bool current_dealloc, const void *ptr, size_t true_size, size_t input_size);
void safety_check_fail(const char *format, ...);
typedef void (*safety_check_abort_hook_t)(const char *message);
/* Can set to NULL for a default. */
void safety_check_set_abort(safety_check_abort_hook_t abort_fn);
#define REDZONE_SIZE ((size_t)32)
#define REDZONE_FILL_VALUE 0xBC

View file

@ -5,6 +5,7 @@
extern JEMALLOC_EXPORT void (*test_hooks_arena_new_hook)(void);
extern JEMALLOC_EXPORT void (*test_hooks_libc_hook)(void);
extern JEMALLOC_EXPORT void (*test_hooks_safety_check_abort)(const char *);
#if defined(JEMALLOC_JET) || defined(JEMALLOC_UNIT_TEST)
# define JEMALLOC_TEST_HOOK(fn, hook) \

View file

@ -48,6 +48,15 @@
<ClCompile Include="..\..\..\..\src\conf.c" />
<ClCompile Include="..\..\..\..\src\counter.c" />
<ClCompile Include="..\..\..\..\src\ctl.c" />
<ClCompile Include="..\..\..\..\src\ctl_arena.c" />
<ClCompile Include="..\..\..\..\src\ctl_background_thread.c" />
<ClCompile Include="..\..\..\..\src\ctl_config.c" />
<ClCompile Include="..\..\..\..\src\ctl_opt.c" />
<ClCompile Include="..\..\..\..\src\ctl_prof.c" />
<ClCompile Include="..\..\..\..\src\ctl_stats.c" />
<ClCompile Include="..\..\..\..\src\ctl_thread.c" />
<ClCompile Include="..\..\..\..\src\ctl_tcache.c" />
<ClCompile Include="..\..\..\..\src\ctl_utilization.c" />
<ClCompile Include="..\..\..\..\src\decay.c" />
<ClCompile Include="..\..\..\..\src\div.c" />
<ClCompile Include="..\..\..\..\src\ecache.c" />

View file

@ -40,6 +40,33 @@
<ClCompile Include="..\..\..\..\src\ctl.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_arena.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_background_thread.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_config.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_opt.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_prof.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_stats.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_thread.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_tcache.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_utilization.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\decay.c">
<Filter>Source Files</Filter>
</ClCompile>

View file

@ -48,6 +48,15 @@
<ClCompile Include="..\..\..\..\src\conf.c" />
<ClCompile Include="..\..\..\..\src\counter.c" />
<ClCompile Include="..\..\..\..\src\ctl.c" />
<ClCompile Include="..\..\..\..\src\ctl_arena.c" />
<ClCompile Include="..\..\..\..\src\ctl_background_thread.c" />
<ClCompile Include="..\..\..\..\src\ctl_config.c" />
<ClCompile Include="..\..\..\..\src\ctl_opt.c" />
<ClCompile Include="..\..\..\..\src\ctl_prof.c" />
<ClCompile Include="..\..\..\..\src\ctl_stats.c" />
<ClCompile Include="..\..\..\..\src\ctl_thread.c" />
<ClCompile Include="..\..\..\..\src\ctl_tcache.c" />
<ClCompile Include="..\..\..\..\src\ctl_utilization.c" />
<ClCompile Include="..\..\..\..\src\decay.c" />
<ClCompile Include="..\..\..\..\src\div.c" />
<ClCompile Include="..\..\..\..\src\ecache.c" />

View file

@ -40,6 +40,33 @@
<ClCompile Include="..\..\..\..\src\ctl.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_arena.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_background_thread.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_config.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_opt.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_prof.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_stats.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_thread.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_tcache.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_utilization.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\decay.c">
<Filter>Source Files</Filter>
</ClCompile>

View file

@ -48,6 +48,15 @@
<ClCompile Include="..\..\..\..\src\conf.c" />
<ClCompile Include="..\..\..\..\src\counter.c" />
<ClCompile Include="..\..\..\..\src\ctl.c" />
<ClCompile Include="..\..\..\..\src\ctl_arena.c" />
<ClCompile Include="..\..\..\..\src\ctl_background_thread.c" />
<ClCompile Include="..\..\..\..\src\ctl_config.c" />
<ClCompile Include="..\..\..\..\src\ctl_opt.c" />
<ClCompile Include="..\..\..\..\src\ctl_prof.c" />
<ClCompile Include="..\..\..\..\src\ctl_stats.c" />
<ClCompile Include="..\..\..\..\src\ctl_thread.c" />
<ClCompile Include="..\..\..\..\src\ctl_tcache.c" />
<ClCompile Include="..\..\..\..\src\ctl_utilization.c" />
<ClCompile Include="..\..\..\..\src\decay.c" />
<ClCompile Include="..\..\..\..\src\div.c" />
<ClCompile Include="..\..\..\..\src\ecache.c" />

View file

@ -40,6 +40,33 @@
<ClCompile Include="..\..\..\..\src\ctl.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_arena.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_background_thread.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_config.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_opt.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_prof.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_stats.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_thread.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_tcache.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_utilization.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\decay.c">
<Filter>Source Files</Filter>
</ClCompile>

View file

@ -48,6 +48,15 @@
<ClCompile Include="..\..\..\..\src\conf.c" />
<ClCompile Include="..\..\..\..\src\counter.c" />
<ClCompile Include="..\..\..\..\src\ctl.c" />
<ClCompile Include="..\..\..\..\src\ctl_arena.c" />
<ClCompile Include="..\..\..\..\src\ctl_background_thread.c" />
<ClCompile Include="..\..\..\..\src\ctl_config.c" />
<ClCompile Include="..\..\..\..\src\ctl_opt.c" />
<ClCompile Include="..\..\..\..\src\ctl_prof.c" />
<ClCompile Include="..\..\..\..\src\ctl_stats.c" />
<ClCompile Include="..\..\..\..\src\ctl_thread.c" />
<ClCompile Include="..\..\..\..\src\ctl_tcache.c" />
<ClCompile Include="..\..\..\..\src\ctl_utilization.c" />
<ClCompile Include="..\..\..\..\src\decay.c" />
<ClCompile Include="..\..\..\..\src\div.c" />
<ClCompile Include="..\..\..\..\src\ecache.c" />

View file

@ -40,6 +40,33 @@
<ClCompile Include="..\..\..\..\src\ctl.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_arena.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_background_thread.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_config.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_opt.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_prof.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_stats.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_thread.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_tcache.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\ctl_utilization.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\..\..\src\decay.c">
<Filter>Source Files</Filter>
</ClCompile>

4358
src/ctl.c

File diff suppressed because it is too large Load diff

1143
src/ctl_arena.c Normal file

File diff suppressed because it is too large Load diff

118
src/ctl_background_thread.c Normal file
View file

@ -0,0 +1,118 @@
#include "jemalloc/internal/jemalloc_preamble.h"
#include "jemalloc/internal/jemalloc_internal_includes.h"
#include "jemalloc/internal/background_thread_externs.h"
#include "jemalloc/internal/background_thread_inlines.h"
#include "jemalloc/internal/ctl_background_thread.h"
/******************************************************************************/
/* background_thread mallctl handlers. */
int
background_thread_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen) {
int ret;
bool oldval;
if (!have_background_thread) {
return ENOENT;
}
background_thread_ctl_init(tsd_tsdn(tsd));
ctl_mtx_lock(tsd_tsdn(tsd));
malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock);
if (newp == NULL) {
oldval = background_thread_enabled();
READ(oldval, bool);
} else {
if (newlen != sizeof(bool)) {
ret = EINVAL;
goto label_return;
}
oldval = background_thread_enabled();
READ(oldval, bool);
bool newval = *(bool *)newp;
if (newval == oldval) {
ret = 0;
goto label_return;
}
background_thread_enabled_set(tsd_tsdn(tsd), newval);
if (newval) {
if (background_threads_enable(tsd)) {
ret = EFAULT;
goto label_return;
}
} else {
if (background_threads_disable(tsd)) {
ret = EFAULT;
goto label_return;
}
}
}
ret = 0;
label_return:
malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock);
ctl_mtx_unlock(tsd_tsdn(tsd));
return ret;
}
int
max_background_threads_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
int ret;
size_t oldval;
if (!have_background_thread) {
return ENOENT;
}
background_thread_ctl_init(tsd_tsdn(tsd));
ctl_mtx_lock(tsd_tsdn(tsd));
malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock);
if (newp == NULL) {
oldval = max_background_threads;
READ(oldval, size_t);
} else {
if (newlen != sizeof(size_t)) {
ret = EINVAL;
goto label_return;
}
oldval = max_background_threads;
READ(oldval, size_t);
size_t newval = *(size_t *)newp;
if (newval == oldval) {
ret = 0;
goto label_return;
}
if (newval > opt_max_background_threads || newval == 0) {
ret = EINVAL;
goto label_return;
}
if (background_thread_enabled()) {
background_thread_enabled_set(tsd_tsdn(tsd), false);
if (background_threads_disable(tsd)) {
ret = EFAULT;
goto label_return;
}
max_background_threads = newval;
background_thread_enabled_set(tsd_tsdn(tsd), true);
if (background_threads_enable(tsd)) {
ret = EFAULT;
goto label_return;
}
} else {
max_background_threads = newval;
}
}
ret = 0;
label_return:
malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock);
ctl_mtx_unlock(tsd_tsdn(tsd));
return ret;
}

38
src/ctl_config.c Normal file
View file

@ -0,0 +1,38 @@
#include "jemalloc/internal/jemalloc_preamble.h"
#include "jemalloc/internal/jemalloc_internal_includes.h"
#include "jemalloc/internal/ctl_config.h"
/******************************************************************************/
/* config.* mallctl handlers. */
#define CTL_RO_CONFIG_GEN(n, t) \
int n##_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, \
void *oldp, size_t *oldlenp, void *newp, size_t newlen) { \
int ret; \
t oldval; \
\
READONLY(); \
oldval = n; \
READ(oldval, t); \
\
ret = 0; \
label_return: \
return ret; \
}
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_opt_safety_checks, 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_prof_frameptr, bool)
CTL_RO_CONFIG_GEN(config_stats, bool)
CTL_RO_CONFIG_GEN(config_utrace, bool)
CTL_RO_CONFIG_GEN(config_xmalloc, bool)
#undef CTL_RO_CONFIG_GEN

138
src/ctl_opt.c Normal file
View file

@ -0,0 +1,138 @@
#include "jemalloc/internal/jemalloc_preamble.h"
#include "jemalloc/internal/jemalloc_internal_includes.h"
#include "jemalloc/internal/ctl_opt.h"
/******************************************************************************/
/* opt.* mallctl handlers. */
CTL_RO_NL_GEN_PUBLIC(opt_abort, opt_abort, bool)
CTL_RO_NL_GEN_PUBLIC(opt_abort_conf, opt_abort_conf, bool)
CTL_RO_NL_GEN_PUBLIC(opt_cache_oblivious, opt_cache_oblivious, bool)
CTL_RO_NL_GEN_PUBLIC(
opt_debug_double_free_max_scan, opt_debug_double_free_max_scan, unsigned)
CTL_RO_NL_GEN_PUBLIC(opt_trust_madvise, opt_trust_madvise, bool)
CTL_RO_NL_GEN_PUBLIC(opt_experimental_hpa_start_huge_if_thp_always,
opt_experimental_hpa_start_huge_if_thp_always, bool)
CTL_RO_NL_GEN_PUBLIC(opt_experimental_hpa_enforce_hugify,
opt_experimental_hpa_enforce_hugify, bool)
CTL_RO_NL_GEN_PUBLIC(opt_confirm_conf, opt_confirm_conf, bool)
/* HPA options. */
CTL_RO_NL_GEN_PUBLIC(opt_hpa, opt_hpa, bool)
CTL_RO_NL_GEN_PUBLIC(
opt_hpa_hugification_threshold, opt_hpa_opts.hugification_threshold, size_t)
CTL_RO_NL_GEN_PUBLIC(
opt_hpa_hugify_delay_ms, opt_hpa_opts.hugify_delay_ms, uint64_t)
CTL_RO_NL_GEN_PUBLIC(opt_hpa_hugify_sync, opt_hpa_opts.hugify_sync, bool)
CTL_RO_NL_GEN_PUBLIC(
opt_hpa_min_purge_interval_ms, opt_hpa_opts.min_purge_interval_ms, uint64_t)
CTL_RO_NL_GEN_PUBLIC(opt_experimental_hpa_max_purge_nhp,
opt_hpa_opts.experimental_max_purge_nhp, ssize_t)
CTL_RO_NL_GEN_PUBLIC(
opt_hpa_purge_threshold, opt_hpa_opts.purge_threshold, size_t)
CTL_RO_NL_GEN_PUBLIC(
opt_hpa_min_purge_delay_ms, opt_hpa_opts.min_purge_delay_ms, uint64_t)
CTL_RO_NL_GEN_PUBLIC(opt_hpa_hugify_style,
hpa_hugify_style_names[opt_hpa_opts.hugify_style], const char *)
/*
* This will have to change before we publicly document this option; fxp_t and
* its representation are internal implementation details.
*/
CTL_RO_NL_GEN_PUBLIC(opt_hpa_dirty_mult, opt_hpa_opts.dirty_mult, fxp_t)
CTL_RO_NL_GEN_PUBLIC(
opt_hpa_slab_max_alloc, opt_hpa_opts.slab_max_alloc, size_t)
/* HPA SEC options */
CTL_RO_NL_GEN_PUBLIC(opt_hpa_sec_nshards, opt_hpa_sec_opts.nshards, size_t)
CTL_RO_NL_GEN_PUBLIC(opt_hpa_sec_max_alloc, opt_hpa_sec_opts.max_alloc, size_t)
CTL_RO_NL_GEN_PUBLIC(opt_hpa_sec_max_bytes, opt_hpa_sec_opts.max_bytes, size_t)
CTL_RO_NL_GEN_PUBLIC(opt_huge_arena_pac_thp, opt_huge_arena_pac_thp, bool)
CTL_RO_NL_GEN_PUBLIC(
opt_metadata_thp, metadata_thp_mode_names[opt_metadata_thp], const char *)
CTL_RO_NL_GEN_PUBLIC(opt_retain, opt_retain, bool)
CTL_RO_NL_GEN_PUBLIC(opt_dss, opt_dss, const char *)
CTL_RO_NL_GEN_PUBLIC(opt_narenas, opt_narenas, unsigned)
CTL_RO_NL_GEN_PUBLIC(
opt_percpu_arena, percpu_arena_mode_names[opt_percpu_arena], const char *)
CTL_RO_NL_GEN_PUBLIC(opt_mutex_max_spin, opt_mutex_max_spin, int64_t)
CTL_RO_NL_GEN_PUBLIC(opt_oversize_threshold, opt_oversize_threshold, size_t)
CTL_RO_NL_GEN_PUBLIC(opt_background_thread, opt_background_thread, bool)
CTL_RO_NL_GEN_PUBLIC(opt_max_background_threads, opt_max_background_threads,
size_t)
CTL_RO_NL_GEN_PUBLIC(opt_dirty_decay_ms, opt_dirty_decay_ms, ssize_t)
CTL_RO_NL_GEN_PUBLIC(opt_muzzy_decay_ms, opt_muzzy_decay_ms, ssize_t)
CTL_RO_NL_GEN_PUBLIC(opt_stats_print, opt_stats_print, bool)
CTL_RO_NL_GEN_PUBLIC(opt_stats_print_opts, opt_stats_print_opts, const char *)
CTL_RO_NL_GEN_PUBLIC(opt_stats_interval, opt_stats_interval, int64_t)
CTL_RO_NL_GEN_PUBLIC(
opt_stats_interval_opts, opt_stats_interval_opts, const char *)
CTL_RO_NL_CGEN_PUBLIC(config_fill, opt_junk, opt_junk, const char *)
CTL_RO_NL_CGEN_PUBLIC(config_fill, opt_zero, opt_zero, bool)
CTL_RO_NL_CGEN_PUBLIC(config_utrace, opt_utrace, opt_utrace, bool)
CTL_RO_NL_CGEN_PUBLIC(config_xmalloc, opt_xmalloc, opt_xmalloc, bool)
CTL_RO_NL_CGEN_PUBLIC(config_enable_cxx, opt_experimental_infallible_new,
opt_experimental_infallible_new, bool)
CTL_RO_NL_GEN_PUBLIC(
opt_experimental_tcache_gc, opt_experimental_tcache_gc, bool)
CTL_RO_NL_GEN_PUBLIC(opt_tcache, opt_tcache, bool)
CTL_RO_NL_GEN_PUBLIC(opt_tcache_max, opt_tcache_max, size_t)
CTL_RO_NL_GEN_PUBLIC(
opt_tcache_nslots_small_min, opt_tcache_nslots_small_min, unsigned)
CTL_RO_NL_GEN_PUBLIC(
opt_tcache_nslots_small_max, opt_tcache_nslots_small_max, unsigned)
CTL_RO_NL_GEN_PUBLIC(opt_tcache_nslots_large, opt_tcache_nslots_large, unsigned)
CTL_RO_NL_GEN_PUBLIC(
opt_lg_tcache_nslots_mul, opt_lg_tcache_nslots_mul, ssize_t)
CTL_RO_NL_GEN_PUBLIC(opt_tcache_gc_incr_bytes, opt_tcache_gc_incr_bytes, size_t)
CTL_RO_NL_GEN_PUBLIC(opt_tcache_gc_delay_bytes, opt_tcache_gc_delay_bytes,
size_t)
CTL_RO_NL_GEN_PUBLIC(
opt_lg_tcache_flush_small_div, opt_lg_tcache_flush_small_div, unsigned)
CTL_RO_NL_GEN_PUBLIC(
opt_lg_tcache_flush_large_div, opt_lg_tcache_flush_large_div, unsigned)
CTL_RO_NL_GEN_PUBLIC(opt_thp, thp_mode_names[opt_thp], const char *)
CTL_RO_NL_GEN_PUBLIC(
opt_lg_extent_max_active_fit, opt_lg_extent_max_active_fit, size_t)
CTL_RO_NL_GEN_PUBLIC(
opt_process_madvise_max_batch, opt_process_madvise_max_batch, size_t)
CTL_RO_NL_CGEN_PUBLIC(config_prof, opt_prof, opt_prof, bool)
CTL_RO_NL_CGEN_PUBLIC(config_prof, opt_prof_prefix, opt_prof_prefix,
const char *)
CTL_RO_NL_CGEN_PUBLIC(config_prof, opt_prof_active, opt_prof_active, bool)
CTL_RO_NL_CGEN_PUBLIC(
config_prof, opt_prof_thread_active_init, opt_prof_thread_active_init, bool)
CTL_RO_NL_CGEN_PUBLIC(config_prof, opt_prof_bt_max, opt_prof_bt_max, unsigned)
CTL_RO_NL_CGEN_PUBLIC(
config_prof, opt_lg_prof_sample, opt_lg_prof_sample, size_t)
CTL_RO_NL_CGEN_PUBLIC(config_prof, opt_prof_accum, opt_prof_accum, bool)
CTL_RO_NL_CGEN_PUBLIC(
config_prof, opt_prof_pid_namespace, opt_prof_pid_namespace, bool)
CTL_RO_NL_CGEN_PUBLIC(
config_prof, opt_lg_prof_interval, opt_lg_prof_interval, ssize_t)
CTL_RO_NL_CGEN_PUBLIC(config_prof, opt_prof_gdump, opt_prof_gdump, bool)
CTL_RO_NL_CGEN_PUBLIC(config_prof, opt_prof_final, opt_prof_final, bool)
CTL_RO_NL_CGEN_PUBLIC(config_prof, opt_prof_leak, opt_prof_leak, bool)
CTL_RO_NL_CGEN_PUBLIC(
config_prof, opt_prof_leak_error, opt_prof_leak_error, bool)
CTL_RO_NL_CGEN_PUBLIC(
config_prof, opt_prof_recent_alloc_max, opt_prof_recent_alloc_max, ssize_t)
CTL_RO_NL_CGEN_PUBLIC(config_prof, opt_prof_stats, opt_prof_stats, bool)
CTL_RO_NL_CGEN_PUBLIC(
config_prof, opt_prof_sys_thread_name, opt_prof_sys_thread_name, bool)
CTL_RO_NL_CGEN_PUBLIC(config_prof, opt_prof_time_res,
prof_time_res_mode_names[opt_prof_time_res], const char *)
CTL_RO_NL_CGEN_PUBLIC(
config_uaf_detection, opt_lg_san_uaf_align, opt_lg_san_uaf_align, ssize_t)
CTL_RO_NL_GEN_PUBLIC(opt_zero_realloc,
zero_realloc_mode_names[opt_zero_realloc_action], const char *)
CTL_RO_NL_GEN_PUBLIC(
opt_disable_large_size_classes, opt_disable_large_size_classes, bool)
/* malloc_conf options */
CTL_RO_NL_CGEN_PUBLIC(opt_malloc_conf_symlink, opt_malloc_conf_symlink,
opt_malloc_conf_symlink, const char *)
CTL_RO_NL_CGEN_PUBLIC(opt_malloc_conf_env_var, opt_malloc_conf_env_var,
opt_malloc_conf_env_var, const char *)
CTL_RO_NL_CGEN_PUBLIC(
je_malloc_conf, opt_malloc_conf_global_var, je_malloc_conf, const char *)

450
src/ctl_prof.c Normal file
View file

@ -0,0 +1,450 @@
#include "jemalloc/internal/jemalloc_preamble.h"
#include "jemalloc/internal/jemalloc_internal_includes.h"
#include "jemalloc/internal/ctl_prof.h"
#include "jemalloc/internal/prof_data.h"
#include "jemalloc/internal/prof_log.h"
#include "jemalloc/internal/prof_recent.h"
#include "jemalloc/internal/prof_stats.h"
#include "jemalloc/internal/prof_sys.h"
#include "jemalloc/internal/sc.h"
/******************************************************************************/
/* prof.* mallctl handlers. */
int
prof_thread_active_init_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
int ret;
bool oldval;
if (!config_prof) {
return ENOENT;
}
if (newp != NULL) {
if (!opt_prof) {
ret = ENOENT;
goto label_return;
}
if (newlen != sizeof(bool)) {
ret = EINVAL;
goto label_return;
}
oldval = prof_thread_active_init_set(
tsd_tsdn(tsd), *(bool *)newp);
} else {
oldval = opt_prof ? prof_thread_active_init_get(tsd_tsdn(tsd))
: false;
}
READ(oldval, bool);
ret = 0;
label_return:
return ret;
}
int
prof_active_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen) {
int ret;
bool oldval;
if (!config_prof) {
ret = ENOENT;
goto label_return;
}
if (newp != NULL) {
if (newlen != sizeof(bool)) {
ret = EINVAL;
goto label_return;
}
bool val = *(bool *)newp;
if (!opt_prof) {
if (val) {
ret = ENOENT;
goto label_return;
} else {
/* No change needed (already off). */
oldval = false;
}
} else {
oldval = prof_active_set(tsd_tsdn(tsd), val);
}
} else {
oldval = opt_prof ? prof_active_get(tsd_tsdn(tsd)) : false;
}
READ(oldval, bool);
ret = 0;
label_return:
return ret;
}
int
prof_dump_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen) {
int ret;
const char *filename = NULL;
if (!config_prof || !opt_prof) {
return ENOENT;
}
WRITEONLY();
WRITE(filename, const char *);
if (prof_mdump(tsd, filename)) {
ret = EFAULT;
goto label_return;
}
ret = 0;
label_return:
return ret;
}
int
prof_gdump_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen) {
int ret;
bool oldval;
if (!config_prof) {
return ENOENT;
}
if (newp != NULL) {
if (!opt_prof) {
ret = ENOENT;
goto label_return;
}
if (newlen != sizeof(bool)) {
ret = EINVAL;
goto label_return;
}
oldval = prof_gdump_set(tsd_tsdn(tsd), *(bool *)newp);
} else {
oldval = opt_prof ? prof_gdump_get(tsd_tsdn(tsd)) : false;
}
READ(oldval, bool);
ret = 0;
label_return:
return ret;
}
int
prof_prefix_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen) {
int ret;
const char *prefix = NULL;
if (!config_prof || !opt_prof) {
return ENOENT;
}
ctl_mtx_lock(tsd_tsdn(tsd));
WRITEONLY();
WRITE(prefix, const char *);
ret = prof_prefix_set(tsd_tsdn(tsd), prefix) ? EFAULT : 0;
label_return:
ctl_mtx_unlock(tsd_tsdn(tsd));
return ret;
}
int
prof_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen) {
int ret;
size_t lg_sample = lg_prof_sample;
if (!config_prof || !opt_prof) {
return ENOENT;
}
WRITEONLY();
WRITE(lg_sample, size_t);
if (lg_sample >= (sizeof(uint64_t) << 3)) {
lg_sample = (sizeof(uint64_t) << 3) - 1;
}
prof_reset(tsd, lg_sample);
ret = 0;
label_return:
return ret;
}
CTL_RO_NL_CGEN_PUBLIC(config_prof, prof_interval, prof_interval, uint64_t)
CTL_RO_NL_CGEN_PUBLIC(config_prof, lg_prof_sample, lg_prof_sample, size_t)
int
prof_log_start_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen) {
int ret;
const char *filename = NULL;
if (!config_prof || !opt_prof) {
return ENOENT;
}
WRITEONLY();
WRITE(filename, const char *);
if (prof_log_start(tsd_tsdn(tsd), filename)) {
ret = EFAULT;
goto label_return;
}
ret = 0;
label_return:
return ret;
}
int
prof_log_stop_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen) {
if (!config_prof || !opt_prof) {
return ENOENT;
}
if (prof_log_stop(tsd_tsdn(tsd))) {
return EFAULT;
}
return 0;
}
int
prof_stats_bins_i_live_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
int ret;
unsigned binind;
prof_stats_t stats;
if (!(config_prof && opt_prof && opt_prof_stats)) {
ret = ENOENT;
goto label_return;
}
READONLY();
MIB_UNSIGNED(binind, 3);
if (binind >= SC_NBINS) {
ret = EINVAL;
goto label_return;
}
prof_stats_get_live(tsd, (szind_t)binind, &stats);
READ(stats, prof_stats_t);
ret = 0;
label_return:
return ret;
}
int
prof_stats_bins_i_accum_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
int ret;
unsigned binind;
prof_stats_t stats;
if (!(config_prof && opt_prof && opt_prof_stats)) {
ret = ENOENT;
goto label_return;
}
READONLY();
MIB_UNSIGNED(binind, 3);
if (binind >= SC_NBINS) {
ret = EINVAL;
goto label_return;
}
prof_stats_get_accum(tsd, (szind_t)binind, &stats);
READ(stats, prof_stats_t);
ret = 0;
label_return:
return ret;
}
int
prof_stats_lextents_i_live_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
int ret;
unsigned lextent_ind;
prof_stats_t stats;
if (!(config_prof && opt_prof && opt_prof_stats)) {
ret = ENOENT;
goto label_return;
}
READONLY();
MIB_UNSIGNED(lextent_ind, 3);
if (lextent_ind >= SC_NSIZES - SC_NBINS) {
ret = EINVAL;
goto label_return;
}
prof_stats_get_live(tsd, (szind_t)(lextent_ind + SC_NBINS), &stats);
READ(stats, prof_stats_t);
ret = 0;
label_return:
return ret;
}
int
prof_stats_lextents_i_accum_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
int ret;
unsigned lextent_ind;
prof_stats_t stats;
if (!(config_prof && opt_prof && opt_prof_stats)) {
ret = ENOENT;
goto label_return;
}
READONLY();
MIB_UNSIGNED(lextent_ind, 3);
if (lextent_ind >= SC_NSIZES - SC_NBINS) {
ret = EINVAL;
goto label_return;
}
prof_stats_get_accum(tsd, (szind_t)(lextent_ind + SC_NBINS), &stats);
READ(stats, prof_stats_t);
ret = 0;
label_return:
return ret;
}
/******************************************************************************/
/* experimental.prof_recent.* and experimental.hooks.prof_* mallctl handlers. */
#define PROF_HOOK_CTL_BODY(hook_type, hook_get, hook_set, allow_null) \
do { \
int ret; \
if (oldp == NULL && newp == NULL) { \
ret = EINVAL; \
goto label_return; \
} \
if (oldp != NULL) { \
hook_type old_hook = hook_get(); \
READ(old_hook, hook_type); \
} \
if (newp != NULL) { \
if (!opt_prof) { \
ret = ENOENT; \
goto label_return; \
} \
hook_type new_hook JEMALLOC_CC_SILENCE_INIT(NULL); \
WRITE(new_hook, hook_type); \
if (!(allow_null) && new_hook == NULL) { \
ret = EINVAL; \
goto label_return; \
} \
hook_set(new_hook); \
} \
ret = 0; \
label_return: \
return ret; \
} while (0)
int
experimental_hooks_prof_backtrace_ctl(tsd_t *tsd, const size_t *mib,
size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
PROF_HOOK_CTL_BODY(prof_backtrace_hook_t, prof_backtrace_hook_get,
prof_backtrace_hook_set, false);
}
int
experimental_hooks_prof_dump_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
PROF_HOOK_CTL_BODY(prof_dump_hook_t, prof_dump_hook_get,
prof_dump_hook_set, true);
}
int
experimental_hooks_prof_sample_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
PROF_HOOK_CTL_BODY(prof_sample_hook_t, prof_sample_hook_get,
prof_sample_hook_set, true);
}
int
experimental_hooks_prof_sample_free_ctl(tsd_t *tsd, const size_t *mib,
size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
PROF_HOOK_CTL_BODY(prof_sample_free_hook_t, prof_sample_free_hook_get,
prof_sample_free_hook_set, true);
}
#undef PROF_HOOK_CTL_BODY
int
experimental_prof_recent_alloc_max_ctl(tsd_t *tsd, const size_t *mib,
size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
int ret;
if (!(config_prof && opt_prof)) {
ret = ENOENT;
goto label_return;
}
ssize_t old_max;
if (newp != NULL) {
if (newlen != sizeof(ssize_t)) {
ret = EINVAL;
goto label_return;
}
ssize_t max = *(ssize_t *)newp;
if (max < -1) {
ret = EINVAL;
goto label_return;
}
old_max = prof_recent_alloc_max_ctl_write(tsd, max);
} else {
old_max = prof_recent_alloc_max_ctl_read();
}
READ(old_max, ssize_t);
ret = 0;
label_return:
return ret;
}
typedef struct write_cb_packet_s write_cb_packet_t;
struct write_cb_packet_s {
write_cb_t *write_cb;
void *cbopaque;
};
int
experimental_prof_recent_alloc_dump_ctl(tsd_t *tsd, const size_t *mib,
size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
int ret;
if (!(config_prof && opt_prof)) {
ret = ENOENT;
goto label_return;
}
assert(sizeof(write_cb_packet_t) == sizeof(void *) * 2);
WRITEONLY();
write_cb_packet_t write_cb_packet;
ASSURED_WRITE(write_cb_packet, write_cb_packet_t);
prof_recent_alloc_dump(
tsd, write_cb_packet.write_cb, write_cb_packet.cbopaque);
ret = 0;
label_return:
return ret;
}

577
src/ctl_stats.c Normal file
View file

@ -0,0 +1,577 @@
#include "jemalloc/internal/jemalloc_preamble.h"
#include "jemalloc/internal/jemalloc_internal_includes.h"
#include "jemalloc/internal/assert.h"
#include "jemalloc/internal/ctl_arena.h"
#include "jemalloc/internal/ctl_mallctl.h"
#include "jemalloc/internal/ctl_stats.h"
#include "jemalloc/internal/mutex.h"
#include "jemalloc/internal/nstime.h"
#include "jemalloc/internal/prof_data.h"
#include "jemalloc/internal/prof_recent.h"
#include "jemalloc/internal/prof_stats.h"
#include "jemalloc/internal/sc.h"
/******************************************************************************/
/* stats.* ctl state. */
static ctl_stats_t *ctl_stats;
bool
ctl_stats_init(tsdn_t *tsdn) {
if (!config_stats || ctl_stats != NULL) {
return false;
}
ctl_stats = (ctl_stats_t *)base_alloc(
tsdn, b0get(), sizeof(ctl_stats_t), QUANTUM);
return ctl_stats == NULL;
}
static void
ctl_background_thread_stats_read(tsdn_t *tsdn) {
background_thread_stats_t *stats = &ctl_stats->background_thread;
if (!have_background_thread
|| background_thread_stats_read(tsdn, stats)) {
memset(stats, 0, sizeof(background_thread_stats_t));
nstime_init_zero(&stats->run_interval);
}
malloc_mutex_prof_copy(
&ctl_stats->mutex_prof_data[global_prof_mutex_max_per_bg_thd],
&stats->max_counter_per_bg_thd);
}
void
ctl_stats_refresh(tsdn_t *tsdn, ctl_arena_t *ctl_sarena) {
if (!config_stats) {
return;
}
ctl_stats->allocated = ctl_sarena->astats->allocated_small
+ ctl_sarena->astats->astats.allocated_large;
ctl_stats->active = (ctl_sarena->pactive << LG_PAGE);
ctl_stats->metadata = ctl_sarena->astats->astats.base
+ atomic_load_zu(
&ctl_sarena->astats->astats.internal, ATOMIC_RELAXED);
ctl_stats->metadata_edata = ctl_sarena->astats->astats.metadata_edata;
ctl_stats->metadata_rtree = ctl_sarena->astats->astats.metadata_rtree;
ctl_stats->resident = ctl_sarena->astats->astats.resident;
ctl_stats->metadata_thp = ctl_sarena->astats->astats.metadata_thp;
ctl_stats->mapped = ctl_sarena->astats->astats.mapped;
ctl_stats->retained = ctl_sarena->astats->astats.pa_shard_stats
.pac_stats.retained;
ctl_stats->pinned = ctl_sarena->astats->astats.pa_shard_stats
.pac_stats.pinned;
ctl_background_thread_stats_read(tsdn);
#define READ_GLOBAL_MUTEX_PROF_DATA(i, mtx) \
malloc_mutex_lock(tsdn, &mtx); \
malloc_mutex_prof_read(tsdn, &ctl_stats->mutex_prof_data[i], &mtx); \
malloc_mutex_unlock(tsdn, &mtx);
if (config_prof && opt_prof) {
READ_GLOBAL_MUTEX_PROF_DATA(
global_prof_mutex_prof, bt2gctx_mtx);
READ_GLOBAL_MUTEX_PROF_DATA(
global_prof_mutex_prof_thds_data, tdatas_mtx);
READ_GLOBAL_MUTEX_PROF_DATA(
global_prof_mutex_prof_dump, prof_dump_mtx);
READ_GLOBAL_MUTEX_PROF_DATA(
global_prof_mutex_prof_recent_alloc,
prof_recent_alloc_mtx);
READ_GLOBAL_MUTEX_PROF_DATA(
global_prof_mutex_prof_recent_dump,
prof_recent_dump_mtx);
READ_GLOBAL_MUTEX_PROF_DATA(
global_prof_mutex_prof_stats, prof_stats_mtx);
}
if (have_background_thread) {
READ_GLOBAL_MUTEX_PROF_DATA(
global_prof_mutex_background_thread, background_thread_lock);
} else {
memset(&ctl_stats->mutex_prof_data
[global_prof_mutex_background_thread],
0, sizeof(mutex_prof_data_t));
}
ctl_mtx_prof_read(
tsdn, &ctl_stats->mutex_prof_data[global_prof_mutex_ctl]);
#undef READ_GLOBAL_MUTEX_PROF_DATA
}
/******************************************************************************/
/* stats.* mallctl handlers. */
CTL_RO_CGEN_PUBLIC(config_stats, stats_allocated, ctl_stats->allocated, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_active, ctl_stats->active, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_metadata, ctl_stats->metadata, size_t)
CTL_RO_CGEN_PUBLIC(
config_stats, stats_metadata_edata, ctl_stats->metadata_edata, size_t)
CTL_RO_CGEN_PUBLIC(
config_stats, stats_metadata_rtree, ctl_stats->metadata_rtree, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_metadata_thp, ctl_stats->metadata_thp, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_resident, ctl_stats->resident, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_mapped, ctl_stats->mapped, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_retained, ctl_stats->retained, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_pinned, ctl_stats->pinned, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_background_thread_num_threads,
ctl_stats->background_thread.num_threads, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_background_thread_num_runs,
ctl_stats->background_thread.num_runs, uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_background_thread_run_interval,
nstime_ns(&ctl_stats->background_thread.run_interval), uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_zero_reallocs,
atomic_load_zu(&zero_realloc_count, ATOMIC_RELAXED), size_t)
/*
* approximate_stats.active returns a result that is informative itself,
* but the returned value SHOULD NOT be compared against other stats retrieved.
* For instance, approximate_stats.active should not be compared against
* any stats, e.g., stats.active or stats.resident, because there is no
* guarantee in the comparison results. Results returned by stats.*, on the
* other hand, provides such guarantees, i.e., stats.active <= stats.resident,
* as long as epoch is called right before the queries.
*/
int
approximate_stats_active_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
int ret;
size_t approximate_nactive = 0;
size_t approximate_active_bytes = 0;
READONLY();
tsdn_t *tsdn = tsd_tsdn(tsd);
unsigned n = narenas_total_get();
for (unsigned i = 0; i < n; i++) {
arena_t *arena = arena_get(tsdn, i, false);
if (!arena) {
continue;
}
/* Accumulate nactive pages from each arena's pa_shard */
approximate_nactive += pa_shard_nactive(&arena->pa_shard);
}
approximate_active_bytes = approximate_nactive << LG_PAGE;
READ(approximate_active_bytes, size_t);
ret = 0;
label_return:
return ret;
}
CTL_RO_GEN_PUBLIC(stats_arenas_i_dss, ctl_arenas_i(mib[2])->dss, const char *)
CTL_RO_GEN_PUBLIC(
stats_arenas_i_dirty_decay_ms, ctl_arenas_i(mib[2])->dirty_decay_ms, ssize_t)
CTL_RO_GEN_PUBLIC(
stats_arenas_i_muzzy_decay_ms, ctl_arenas_i(mib[2])->muzzy_decay_ms, ssize_t)
CTL_RO_GEN_PUBLIC(stats_arenas_i_nthreads, ctl_arenas_i(mib[2])->nthreads, unsigned)
CTL_RO_GEN_PUBLIC(stats_arenas_i_uptime,
nstime_ns(&ctl_arenas_i(mib[2])->astats->astats.uptime), uint64_t)
CTL_RO_GEN_PUBLIC(stats_arenas_i_pactive, ctl_arenas_i(mib[2])->pactive, size_t)
CTL_RO_GEN_PUBLIC(stats_arenas_i_pdirty, ctl_arenas_i(mib[2])->pdirty, size_t)
CTL_RO_GEN_PUBLIC(stats_arenas_i_pmuzzy, ctl_arenas_i(mib[2])->pmuzzy, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_mapped,
ctl_arenas_i(mib[2])->astats->astats.mapped, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_retained,
ctl_arenas_i(mib[2])->astats->astats.pa_shard_stats.pac_stats.retained, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_pinned,
ctl_arenas_i(mib[2])->astats->astats.pa_shard_stats.pac_stats.pinned, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_extent_avail,
ctl_arenas_i(mib[2])->astats->astats.pa_shard_stats.edata_avail, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_dirty_npurge,
locked_read_u64_unsynchronized(&ctl_arenas_i(mib[2])
->astats->astats.pa_shard_stats.pac_stats.decay_dirty.npurge),
uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_dirty_nmadvise,
locked_read_u64_unsynchronized(&ctl_arenas_i(mib[2])
->astats->astats.pa_shard_stats.pac_stats.decay_dirty.nmadvise),
uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_dirty_purged,
locked_read_u64_unsynchronized(&ctl_arenas_i(mib[2])
->astats->astats.pa_shard_stats.pac_stats.decay_dirty.purged),
uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_muzzy_npurge,
locked_read_u64_unsynchronized(&ctl_arenas_i(mib[2])
->astats->astats.pa_shard_stats.pac_stats.decay_muzzy.npurge),
uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_muzzy_nmadvise,
locked_read_u64_unsynchronized(&ctl_arenas_i(mib[2])
->astats->astats.pa_shard_stats.pac_stats.decay_muzzy.nmadvise),
uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_muzzy_purged,
locked_read_u64_unsynchronized(&ctl_arenas_i(mib[2])
->astats->astats.pa_shard_stats.pac_stats.decay_muzzy.purged),
uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_base,
ctl_arenas_i(mib[2])->astats->astats.base, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_internal,
atomic_load_zu(&ctl_arenas_i(mib[2])->astats->astats.internal, ATOMIC_RELAXED),
size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_metadata_edata,
ctl_arenas_i(mib[2])->astats->astats.metadata_edata, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_metadata_rtree,
ctl_arenas_i(mib[2])->astats->astats.metadata_rtree, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_metadata_thp,
ctl_arenas_i(mib[2])->astats->astats.metadata_thp, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_tcache_bytes,
ctl_arenas_i(mib[2])->astats->astats.tcache_bytes, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_tcache_stashed_bytes,
ctl_arenas_i(mib[2])->astats->astats.tcache_stashed_bytes, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_resident,
ctl_arenas_i(mib[2])->astats->astats.resident, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_abandoned_vm,
atomic_load_zu(
&ctl_arenas_i(mib[2])->astats->astats.pa_shard_stats.pac_stats.abandoned_vm,
ATOMIC_RELAXED),
size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_sec_bytes,
ctl_arenas_i(mib[2])->astats->hpastats.secstats.bytes, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_sec_hits,
ctl_arenas_i(mib[2])->astats->hpastats.secstats.total.nhits, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_sec_misses,
ctl_arenas_i(mib[2])->astats->hpastats.secstats.total.nmisses, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_sec_dalloc_flush,
ctl_arenas_i(mib[2])->astats->hpastats.secstats.total.ndalloc_flush, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_sec_dalloc_noflush,
ctl_arenas_i(mib[2])->astats->hpastats.secstats.total.ndalloc_noflush, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_sec_overfills,
ctl_arenas_i(mib[2])->astats->hpastats.secstats.total.noverfills, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_small_allocated,
ctl_arenas_i(mib[2])->astats->allocated_small, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_small_nmalloc,
ctl_arenas_i(mib[2])->astats->nmalloc_small, uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_small_ndalloc,
ctl_arenas_i(mib[2])->astats->ndalloc_small, uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_small_nrequests,
ctl_arenas_i(mib[2])->astats->nrequests_small, uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_small_nfills,
ctl_arenas_i(mib[2])->astats->nfills_small, uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_small_nflushes,
ctl_arenas_i(mib[2])->astats->nflushes_small, uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_large_allocated,
ctl_arenas_i(mib[2])->astats->astats.allocated_large, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_large_nmalloc,
ctl_arenas_i(mib[2])->astats->astats.nmalloc_large, uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_large_ndalloc,
ctl_arenas_i(mib[2])->astats->astats.ndalloc_large, uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_large_nrequests,
ctl_arenas_i(mib[2])->astats->astats.nrequests_large, uint64_t)
/*
* Note: "nmalloc_large" here instead of "nfills" in the read. This is
* intentional (large has no batch fill).
*/
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_large_nfills,
ctl_arenas_i(mib[2])->astats->astats.nmalloc_large, uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_large_nflushes,
ctl_arenas_i(mib[2])->astats->astats.nflushes_large, uint64_t)
/* Lock profiling related APIs below. */
#define RO_MUTEX_CTL_GEN(n, l) \
CTL_RO_CGEN_PUBLIC(config_stats, stats_##n##_num_ops, l.n_lock_ops, uint64_t) \
CTL_RO_CGEN_PUBLIC( \
config_stats, stats_##n##_num_wait, l.n_wait_times, uint64_t) \
CTL_RO_CGEN_PUBLIC(config_stats, stats_##n##_num_spin_acq, l.n_spin_acquired, \
uint64_t) \
CTL_RO_CGEN_PUBLIC(config_stats, stats_##n##_num_owner_switch, \
l.n_owner_switches, uint64_t) \
CTL_RO_CGEN_PUBLIC(config_stats, stats_##n##_total_wait_time, \
nstime_ns(&l.tot_wait_time), uint64_t) \
CTL_RO_CGEN_PUBLIC(config_stats, stats_##n##_max_wait_time, \
nstime_ns(&l.max_wait_time), uint64_t) \
CTL_RO_CGEN_PUBLIC( \
config_stats, stats_##n##_max_num_thds, l.max_n_thds, uint32_t)
/* Global mutexes. */
#define OP(mtx) \
RO_MUTEX_CTL_GEN(mutexes_##mtx, \
ctl_stats->mutex_prof_data[global_prof_mutex_##mtx])
MUTEX_PROF_GLOBAL_MUTEXES
#undef OP
/* Per arena mutexes */
#define OP(mtx) \
RO_MUTEX_CTL_GEN(arenas_i_mutexes_##mtx, \
ctl_arenas_i(mib[2]) \
->astats->astats.mutex_prof_data[arena_prof_mutex_##mtx])
MUTEX_PROF_ARENA_MUTEXES
#undef OP
/* tcache bin mutex */
RO_MUTEX_CTL_GEN(
arenas_i_bins_j_mutex, ctl_arenas_i(mib[2])->astats->bstats[mib[4]].mutex_data)
#undef RO_MUTEX_CTL_GEN
/* Resets all mutex stats, including global, arena and bin mutexes. */
int
stats_mutexes_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
if (!config_stats) {
return ENOENT;
}
tsdn_t *tsdn = tsd_tsdn(tsd);
#define MUTEX_PROF_RESET(mtx) \
malloc_mutex_lock(tsdn, &mtx); \
malloc_mutex_prof_data_reset(tsdn, &mtx); \
malloc_mutex_unlock(tsdn, &mtx);
/* Global mutexes: ctl and prof. */
ctl_mtx_prof_data_reset(tsdn);
if (have_background_thread) {
MUTEX_PROF_RESET(background_thread_lock);
}
if (config_prof && opt_prof) {
MUTEX_PROF_RESET(bt2gctx_mtx);
MUTEX_PROF_RESET(tdatas_mtx);
MUTEX_PROF_RESET(prof_dump_mtx);
MUTEX_PROF_RESET(prof_recent_alloc_mtx);
MUTEX_PROF_RESET(prof_recent_dump_mtx);
MUTEX_PROF_RESET(prof_stats_mtx);
}
/* Per arena mutexes. */
unsigned n = narenas_total_get();
for (unsigned i = 0; i < n; i++) {
arena_t *arena = arena_get(tsdn, i, false);
if (!arena) {
continue;
}
MUTEX_PROF_RESET(arena->large_mtx);
MUTEX_PROF_RESET(arena->pa_shard.edata_cache.mtx);
MUTEX_PROF_RESET(arena->pa_shard.pac.ecache_dirty.mtx);
MUTEX_PROF_RESET(arena->pa_shard.pac.ecache_muzzy.mtx);
MUTEX_PROF_RESET(arena->pa_shard.pac.ecache_retained.mtx);
MUTEX_PROF_RESET(arena->pa_shard.pac.ecache_pinned.mtx);
MUTEX_PROF_RESET(arena->pa_shard.pac.decay_dirty.mtx);
MUTEX_PROF_RESET(arena->pa_shard.pac.decay_muzzy.mtx);
MUTEX_PROF_RESET(arena->cache_bin_array_descriptor_ql_mtx);
MUTEX_PROF_RESET(arena->base->mtx);
for (szind_t j = 0; j < SC_NBINS; j++) {
for (unsigned k = 0; k < bin_infos[j].n_shards; k++) {
bin_t *bin = arena_get_bin(arena, j, k);
MUTEX_PROF_RESET(bin->lock);
}
}
}
#undef MUTEX_PROF_RESET
return 0;
}
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_bins_j_nmalloc,
ctl_arenas_i(mib[2])->astats->bstats[mib[4]].stats_data.nmalloc, uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_bins_j_ndalloc,
ctl_arenas_i(mib[2])->astats->bstats[mib[4]].stats_data.ndalloc, uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_bins_j_nrequests,
ctl_arenas_i(mib[2])->astats->bstats[mib[4]].stats_data.nrequests, uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_bins_j_curregs,
ctl_arenas_i(mib[2])->astats->bstats[mib[4]].stats_data.curregs, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_bins_j_nfills,
ctl_arenas_i(mib[2])->astats->bstats[mib[4]].stats_data.nfills, uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_bins_j_nflushes,
ctl_arenas_i(mib[2])->astats->bstats[mib[4]].stats_data.nflushes, uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_bins_j_nslabs,
ctl_arenas_i(mib[2])->astats->bstats[mib[4]].stats_data.nslabs, uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_bins_j_nreslabs,
ctl_arenas_i(mib[2])->astats->bstats[mib[4]].stats_data.reslabs, uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_bins_j_curslabs,
ctl_arenas_i(mib[2])->astats->bstats[mib[4]].stats_data.curslabs, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_bins_j_nonfull_slabs,
ctl_arenas_i(mib[2])->astats->bstats[mib[4]].stats_data.nonfull_slabs, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_lextents_j_nmalloc,
locked_read_u64_unsynchronized(
&ctl_arenas_i(mib[2])->astats->lstats[mib[4]].nmalloc),
uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_lextents_j_ndalloc,
locked_read_u64_unsynchronized(
&ctl_arenas_i(mib[2])->astats->lstats[mib[4]].ndalloc),
uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_lextents_j_nrequests,
locked_read_u64_unsynchronized(
&ctl_arenas_i(mib[2])->astats->lstats[mib[4]].nrequests),
uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_lextents_j_curlextents,
ctl_arenas_i(mib[2])->astats->lstats[mib[4]].curlextents, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_extents_j_ndirty,
ctl_arenas_i(mib[2])->astats->estats[mib[4]].ndirty, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_extents_j_nmuzzy,
ctl_arenas_i(mib[2])->astats->estats[mib[4]].nmuzzy, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_extents_j_nretained,
ctl_arenas_i(mib[2])->astats->estats[mib[4]].nretained, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_extents_j_npinned,
ctl_arenas_i(mib[2])->astats->estats[mib[4]].npinned, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_extents_j_dirty_bytes,
ctl_arenas_i(mib[2])->astats->estats[mib[4]].dirty_bytes, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_extents_j_muzzy_bytes,
ctl_arenas_i(mib[2])->astats->estats[mib[4]].muzzy_bytes, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_extents_j_retained_bytes,
ctl_arenas_i(mib[2])->astats->estats[mib[4]].retained_bytes, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_extents_j_pinned_bytes,
ctl_arenas_i(mib[2])->astats->estats[mib[4]].pinned_bytes, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_npageslabs,
ctl_arenas_i(mib[2])->astats->hpastats.psset_stats.merged.npageslabs, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_nactive,
ctl_arenas_i(mib[2])->astats->hpastats.psset_stats.merged.nactive, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_ndirty,
ctl_arenas_i(mib[2])->astats->hpastats.psset_stats.merged.ndirty, size_t)
/* Nonhuge slabs */
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_slabs_npageslabs_nonhuge,
ctl_arenas_i(mib[2])->astats->hpastats.psset_stats.slabs[0].npageslabs, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_slabs_nactive_nonhuge,
ctl_arenas_i(mib[2])->astats->hpastats.psset_stats.slabs[0].nactive, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_slabs_ndirty_nonhuge,
ctl_arenas_i(mib[2])->astats->hpastats.psset_stats.slabs[0].ndirty, size_t)
/* Huge slabs */
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_slabs_npageslabs_huge,
ctl_arenas_i(mib[2])->astats->hpastats.psset_stats.slabs[1].npageslabs, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_slabs_nactive_huge,
ctl_arenas_i(mib[2])->astats->hpastats.psset_stats.slabs[1].nactive, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_slabs_ndirty_huge,
ctl_arenas_i(mib[2])->astats->hpastats.psset_stats.slabs[1].ndirty, size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_npurge_passes,
ctl_arenas_i(mib[2])->astats->hpastats.nonderived_stats.npurge_passes,
uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_npurges,
ctl_arenas_i(mib[2])->astats->hpastats.nonderived_stats.npurges, uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_nhugifies,
ctl_arenas_i(mib[2])->astats->hpastats.nonderived_stats.nhugifies, uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_nhugify_failures,
ctl_arenas_i(mib[2])->astats->hpastats.nonderived_stats.nhugify_failures,
uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_ndehugifies,
ctl_arenas_i(mib[2])->astats->hpastats.nonderived_stats.ndehugifies, uint64_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_alloc_j_min_extents,
ctl_arenas_i(mib[2])
->astats->hpastats.nonderived_stats.hpa_alloc_min_extents[mib[5]],
uint64_t);
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_alloc_j_max_extents,
ctl_arenas_i(mib[2])
->astats->hpastats.nonderived_stats.hpa_alloc_max_extents[mib[5]],
uint64_t);
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_alloc_j_extents,
ctl_arenas_i(mib[2])
->astats->hpastats.nonderived_stats.hpa_alloc_extents[mib[5]],
uint64_t);
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_alloc_j_ps,
ctl_arenas_i(mib[2])->astats->hpastats.nonderived_stats.hpa_alloc_ps[mib[5]],
uint64_t);
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_alloc_j_pages_per_ps,
ctl_arenas_i(mib[2])
->astats->hpastats.nonderived_stats.hpa_alloc_pages_per_ps[mib[5]],
uint64_t);
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_alloc_j_extents_per_ps,
ctl_arenas_i(mib[2])
->astats->hpastats.nonderived_stats.hpa_alloc_extents_per_ps[mib[5]],
uint64_t);
CTL_RO_CGEN_PUBLIC(config_stats,
stats_arenas_i_hpa_shard_alloc_j_total_elapsed_ns_per_ps,
ctl_arenas_i(mib[2])
->astats->hpastats.nonderived_stats
.hpa_alloc_total_elapsed_ns_per_ps[mib[5]],
uint64_t);
/* Full, nonhuge */
CTL_RO_CGEN_PUBLIC(config_stats,
stats_arenas_i_hpa_shard_full_slabs_npageslabs_nonhuge,
ctl_arenas_i(mib[2])->astats->hpastats.psset_stats.full_slabs[0].npageslabs,
size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_full_slabs_nactive_nonhuge,
ctl_arenas_i(mib[2])->astats->hpastats.psset_stats.full_slabs[0].nactive,
size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_full_slabs_ndirty_nonhuge,
ctl_arenas_i(mib[2])->astats->hpastats.psset_stats.full_slabs[0].ndirty,
size_t)
/* Full, huge */
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_full_slabs_npageslabs_huge,
ctl_arenas_i(mib[2])->astats->hpastats.psset_stats.full_slabs[1].npageslabs,
size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_full_slabs_nactive_huge,
ctl_arenas_i(mib[2])->astats->hpastats.psset_stats.full_slabs[1].nactive,
size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_full_slabs_ndirty_huge,
ctl_arenas_i(mib[2])->astats->hpastats.psset_stats.full_slabs[1].ndirty,
size_t)
/* Empty, nonhuge */
CTL_RO_CGEN_PUBLIC(config_stats,
stats_arenas_i_hpa_shard_empty_slabs_npageslabs_nonhuge,
ctl_arenas_i(mib[2])->astats->hpastats.psset_stats.empty_slabs[0].npageslabs,
size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_empty_slabs_nactive_nonhuge,
ctl_arenas_i(mib[2])->astats->hpastats.psset_stats.empty_slabs[0].nactive,
size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_empty_slabs_ndirty_nonhuge,
ctl_arenas_i(mib[2])->astats->hpastats.psset_stats.empty_slabs[0].ndirty,
size_t)
/* Empty, huge */
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_empty_slabs_npageslabs_huge,
ctl_arenas_i(mib[2])->astats->hpastats.psset_stats.empty_slabs[1].npageslabs,
size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_empty_slabs_nactive_huge,
ctl_arenas_i(mib[2])->astats->hpastats.psset_stats.empty_slabs[1].nactive,
size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_empty_slabs_ndirty_huge,
ctl_arenas_i(mib[2])->astats->hpastats.psset_stats.empty_slabs[1].ndirty,
size_t)
/* Nonfull, nonhuge */
CTL_RO_CGEN_PUBLIC(config_stats,
stats_arenas_i_hpa_shard_nonfull_slabs_j_npageslabs_nonhuge,
ctl_arenas_i(mib[2])
->astats->hpastats.psset_stats.nonfull_slabs[mib[5]][0]
.npageslabs,
size_t)
CTL_RO_CGEN_PUBLIC(config_stats,
stats_arenas_i_hpa_shard_nonfull_slabs_j_nactive_nonhuge,
ctl_arenas_i(mib[2])
->astats->hpastats.psset_stats.nonfull_slabs[mib[5]][0]
.nactive,
size_t)
CTL_RO_CGEN_PUBLIC(config_stats,
stats_arenas_i_hpa_shard_nonfull_slabs_j_ndirty_nonhuge,
ctl_arenas_i(mib[2])
->astats->hpastats.psset_stats.nonfull_slabs[mib[5]][0]
.ndirty,
size_t)
/* Nonfull, huge */
CTL_RO_CGEN_PUBLIC(config_stats,
stats_arenas_i_hpa_shard_nonfull_slabs_j_npageslabs_huge,
ctl_arenas_i(mib[2])
->astats->hpastats.psset_stats.nonfull_slabs[mib[5]][1]
.npageslabs,
size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_nonfull_slabs_j_nactive_huge,
ctl_arenas_i(mib[2])
->astats->hpastats.psset_stats.nonfull_slabs[mib[5]][1]
.nactive,
size_t)
CTL_RO_CGEN_PUBLIC(config_stats, stats_arenas_i_hpa_shard_nonfull_slabs_j_ndirty_huge,
ctl_arenas_i(mib[2])
->astats->hpastats.psset_stats.nonfull_slabs[mib[5]][1]
.ndirty,
size_t)

56
src/ctl_tcache.c Normal file
View file

@ -0,0 +1,56 @@
#include "jemalloc/internal/jemalloc_preamble.h"
#include "jemalloc/internal/jemalloc_internal_includes.h"
#include "jemalloc/internal/ctl_tcache.h"
/******************************************************************************/
/* tcache.* mallctl handlers. */
int
tcache_create_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen) {
int ret;
unsigned tcache_ind;
READONLY();
VERIFY_READ(unsigned);
if (tcaches_create(tsd, b0get(), &tcache_ind)) {
ret = EFAULT;
goto label_return;
}
READ(tcache_ind, unsigned);
ret = 0;
label_return:
return ret;
}
int
tcache_flush_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen) {
int ret;
unsigned tcache_ind;
WRITEONLY();
ASSURED_WRITE(tcache_ind, unsigned);
tcaches_flush(tsd, tcache_ind);
ret = 0;
label_return:
return ret;
}
int
tcache_destroy_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen) {
int ret;
unsigned tcache_ind;
WRITEONLY();
ASSURED_WRITE(tcache_ind, unsigned);
tcaches_destroy(tsd, tcache_ind);
ret = 0;
label_return:
return ret;
}

353
src/ctl_thread.c Normal file
View file

@ -0,0 +1,353 @@
#include "jemalloc/internal/jemalloc_preamble.h"
#include "jemalloc/internal/jemalloc_internal_includes.h"
#include "jemalloc/internal/assert.h"
#include "jemalloc/internal/ctl_thread.h"
#include "jemalloc/internal/peak_event.h"
#include "jemalloc/internal/prof_data.h"
#include "jemalloc/internal/sc.h"
#include "jemalloc/internal/thread_event_registry.h"
/*******************************************************************************/
/* thread.* mallctl handlers. */
int
thread_arena_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen) {
int ret;
arena_t *oldarena;
unsigned newind, oldind;
oldarena = arena_choose(tsd, NULL);
if (oldarena == NULL) {
return EAGAIN;
}
newind = oldind = arena_ind_get(oldarena);
WRITE(newind, unsigned);
READ(oldind, unsigned);
if (newind != oldind) {
arena_t *newarena;
if (newind >= narenas_total_get()) {
/* New arena index is out of range. */
ret = EFAULT;
goto label_return;
}
if (have_percpu_arena
&& PERCPU_ARENA_ENABLED(opt_percpu_arena)) {
if (newind < percpu_arena_ind_limit(opt_percpu_arena)) {
/*
* If perCPU arena is enabled, thread_arena
* control is not allowed for the auto arena
* range.
*/
ret = EPERM;
goto label_return;
}
}
/* Initialize arena if necessary. */
newarena = arena_get(tsd_tsdn(tsd), newind, true);
if (newarena == NULL) {
ret = EAGAIN;
goto label_return;
}
thread_migrate_arena(tsd, oldarena, newarena);
}
ret = 0;
label_return:
return ret;
}
CTL_RO_NL_GEN_PUBLIC(thread_allocated, tsd_thread_allocated_get(tsd), uint64_t)
CTL_RO_NL_GEN_PUBLIC(thread_allocatedp, tsd_thread_allocatedp_get(tsd), uint64_t *)
int
thread_tcache_ncached_max_read_sizeclass_ctl(tsd_t *tsd, const size_t *mib,
size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
int ret;
size_t bin_size = 0;
/* Read the bin size from newp. */
if (newp == NULL) {
ret = EINVAL;
goto label_return;
}
WRITE(bin_size, size_t);
cache_bin_sz_t ncached_max = 0;
if (tcache_bin_ncached_max_read(tsd, bin_size, &ncached_max)) {
ret = EINVAL;
goto label_return;
}
size_t result = (size_t)ncached_max;
READ(result, size_t);
ret = 0;
label_return:
return ret;
}
int
thread_tcache_ncached_max_write_ctl(tsd_t *tsd, const size_t *mib,
size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
int ret;
WRITEONLY();
if (newp != NULL) {
if (!tcache_available(tsd)) {
ret = ENOENT;
goto label_return;
}
char *settings = NULL;
WRITE(settings, char *);
if (settings == NULL) {
ret = EINVAL;
goto label_return;
}
/* Get the length of the setting string safely. */
char *end = (char *)memchr(
settings, '\0', CTL_MULTI_SETTING_MAX_LEN);
if (end == NULL) {
ret = EINVAL;
goto label_return;
}
/*
* Exclude the last '\0' for len since it is not handled by
* multi_setting_parse_next.
*/
size_t len = (uintptr_t)end - (uintptr_t)settings;
if (len == 0) {
ret = 0;
goto label_return;
}
if (tcache_bins_ncached_max_write(tsd, settings, len)) {
ret = EINVAL;
goto label_return;
}
}
ret = 0;
label_return:
return ret;
}
CTL_RO_NL_GEN_PUBLIC(thread_deallocated, tsd_thread_deallocated_get(tsd), uint64_t)
CTL_RO_NL_GEN_PUBLIC(thread_deallocatedp, tsd_thread_deallocatedp_get(tsd), uint64_t *)
int
thread_tcache_enabled_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
int ret;
bool oldval;
oldval = tcache_enabled_get(tsd);
if (newp != NULL) {
if (newlen != sizeof(bool)) {
ret = EINVAL;
goto label_return;
}
tcache_enabled_set(tsd, *(bool *)newp);
}
READ(oldval, bool);
ret = 0;
label_return:
return ret;
}
int
thread_tcache_max_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen) {
int ret;
size_t oldval;
/* pointer to tcache_t always exists even with tcache disabled. */
tcache_t *tcache = tsd_tcachep_get(tsd);
assert(tcache != NULL);
oldval = tcache_max_get(tcache->tcache_slow);
READ(oldval, size_t);
if (newp != NULL) {
if (newlen != sizeof(size_t)) {
ret = EINVAL;
goto label_return;
}
size_t new_tcache_max = oldval;
WRITE(new_tcache_max, size_t);
if (new_tcache_max > TCACHE_MAXCLASS_LIMIT) {
new_tcache_max = TCACHE_MAXCLASS_LIMIT;
}
new_tcache_max = sz_s2u(new_tcache_max);
if (new_tcache_max != oldval) {
thread_tcache_max_set(tsd, new_tcache_max);
}
}
ret = 0;
label_return:
return ret;
}
int
thread_tcache_flush_ctl(tsd_t *tsd, const size_t *mib, size_t miblen,
void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
int ret;
if (!tcache_available(tsd)) {
ret = EFAULT;
goto label_return;
}
NEITHER_READ_NOR_WRITE();
tcache_flush(tsd);
ret = 0;
label_return:
return ret;
}
int
thread_peak_read_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen) {
int ret;
if (!config_stats) {
return ENOENT;
}
READONLY();
peak_event_update(tsd);
uint64_t result = peak_event_max(tsd);
READ(result, uint64_t);
ret = 0;
label_return:
return ret;
}
int
thread_peak_reset_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen) {
int ret;
if (!config_stats) {
return ENOENT;
}
NEITHER_READ_NOR_WRITE();
peak_event_zero(tsd);
ret = 0;
label_return:
return ret;
}
int
thread_prof_name_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen) {
int ret;
if (!config_prof || !opt_prof) {
return ENOENT;
}
READ_XOR_WRITE();
if (newp != NULL) {
const char *newval = *(const char **)newp;
if (newlen != sizeof(const char *) || newval == NULL) {
ret = EINVAL;
goto label_return;
}
if ((ret = prof_thread_name_set(tsd, newval)) != 0) {
goto label_return;
}
} else {
const char *oldname = prof_thread_name_get(tsd);
READ(oldname, const char *);
}
ret = 0;
label_return:
return ret;
}
int
thread_prof_active_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen) {
int ret;
bool oldval;
if (!config_prof) {
return ENOENT;
}
oldval = opt_prof ? prof_thread_active_get(tsd) : false;
if (newp != NULL) {
if (!opt_prof) {
ret = ENOENT;
goto label_return;
}
if (newlen != sizeof(bool)) {
ret = EINVAL;
goto label_return;
}
if (prof_thread_active_set(tsd, *(bool *)newp)) {
ret = EAGAIN;
goto label_return;
}
}
READ(oldval, bool);
ret = 0;
label_return:
return ret;
}
int
thread_idle_ctl(tsd_t *tsd, const size_t *mib, size_t miblen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen) {
int ret;
NEITHER_READ_NOR_WRITE();
if (tcache_available(tsd)) {
tcache_flush(tsd);
}
/*
* This heuristic is perhaps not the most well-considered. But it
* matches the only idling policy we have experience with in the status
* quo. Over time we should investigate more principled approaches.
*/
if (opt_narenas > ncpus * 2) {
arena_t *arena = arena_choose(tsd, NULL);
if (arena != NULL) {
arena_decay(tsd_tsdn(tsd), arena, false, true);
}
/*
* The missing arena case is not actually an error; a thread
* might be idle before it associates itself to one. This is
* unusual, but not wrong.
*/
}
ret = 0;
label_return:
return ret;
}
int
experimental_hooks_thread_event_ctl(tsd_t *tsd, const size_t *mib,
size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
int ret;
if (newp == NULL) {
ret = EINVAL;
goto label_return;
}
user_hook_object_t t_new = {NULL, 0, false};
WRITE(t_new, user_hook_object_t);
ret = te_register_user_handler(tsd_tsdn(tsd), &t_new);
label_return:
return ret;
}

51
src/ctl_utilization.c Normal file
View file

@ -0,0 +1,51 @@
#include "jemalloc/internal/jemalloc_preamble.h"
#include "jemalloc/internal/jemalloc_internal_includes.h"
#include "jemalloc/internal/assert.h"
#include "jemalloc/internal/ctl_utilization.h"
#include "jemalloc/internal/inspect.h"
/******************************************************************************/
/* experimental.utilization.* mallctl handlers. */
/*
* Given an input array of pointers, output three memory utilization entries of
* type size_t for each input pointer about the extent it resides in:
*
* (a) number of free regions in the extent,
* (b) number of regions in the extent, and
* (c) size of the extent in terms of bytes.
*
* This API is mainly intended for small class allocations, where extents are
* used as slab. In case of large class allocations, the outputs are trivial:
* "(a)" will be 0, "(b)" will be 1, and "(c)" will be the usable size.
*/
int
experimental_utilization_batch_query_ctl(tsd_t *tsd, const size_t *mib,
size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) {
int ret;
assert(sizeof(inspect_extent_util_stats_t) == sizeof(size_t) * 3);
const size_t len = newlen / sizeof(const void *);
if (oldp == NULL || oldlenp == NULL || newp == NULL || newlen == 0
|| newlen != len * sizeof(const void *)
|| *oldlenp != len * sizeof(inspect_extent_util_stats_t)) {
ret = EINVAL;
goto label_return;
}
void **ptrs = (void **)newp;
inspect_extent_util_stats_t *util_stats =
(inspect_extent_util_stats_t *)oldp;
size_t i;
for (i = 0; i < len; ++i) {
inspect_extent_util_stats_get(tsd_tsdn(tsd), ptrs[i],
&util_stats[i].nfree, &util_stats[i].nregs,
&util_stats[i].size);
}
ret = 0;
label_return:
return ret;
}

View file

@ -24,54 +24,3 @@ inspect_extent_util_stats_get(
assert(*nfree * edata_usize_get(edata) <= *size);
}
}
void
inspect_extent_util_stats_verbose_get(tsdn_t *tsdn, const void *ptr,
size_t *nfree, size_t *nregs, size_t *size, size_t *bin_nfree,
size_t *bin_nregs, void **slabcur_addr) {
assert(ptr != NULL && nfree != NULL && nregs != NULL && size != NULL
&& bin_nfree != NULL && bin_nregs != NULL && slabcur_addr != NULL);
const edata_t *edata = emap_edata_lookup(tsdn, &arena_emap_global, ptr);
if (unlikely(edata == NULL)) {
*nfree = *nregs = *size = *bin_nfree = *bin_nregs = 0;
*slabcur_addr = NULL;
return;
}
*size = edata_size_get(edata);
if (!edata_slab_get(edata)) {
*nfree = *bin_nfree = *bin_nregs = 0;
*nregs = 1;
*slabcur_addr = NULL;
return;
}
*nfree = edata_nfree_get(edata);
const szind_t szind = edata_szind_get(edata);
*nregs = bin_infos[szind].nregs;
assert(*nfree <= *nregs);
assert(*nfree * edata_usize_get(edata) <= *size);
arena_t *arena = arena_get_from_edata(edata);
assert(arena != NULL);
const unsigned binshard = edata_binshard_get(edata);
bin_t *bin = arena_get_bin(arena, szind, binshard);
malloc_mutex_lock(tsdn, &bin->lock);
if (config_stats) {
*bin_nregs = *nregs * bin->stats.curslabs;
assert(*bin_nregs >= bin->stats.curregs);
*bin_nfree = *bin_nregs - bin->stats.curregs;
} else {
*bin_nfree = *bin_nregs = 0;
}
edata_t *slab;
if (bin->slabcur != NULL) {
slab = bin->slabcur;
} else {
slab = edata_heap_first(&bin->slabs_nonfull);
}
*slabcur_addr = slab != NULL ? edata_addr_get(slab) : NULL;
malloc_mutex_unlock(tsdn, &bin->lock);
}

View file

@ -1,8 +1,6 @@
#include "jemalloc/internal/jemalloc_preamble.h"
#include "jemalloc/internal/jemalloc_internal_includes.h"
static safety_check_abort_hook_t safety_check_abort;
void
safety_check_fail_sized_dealloc(bool current_dealloc, const void *ptr,
size_t true_size, size_t input_size) {
@ -19,23 +17,18 @@ safety_check_fail_sized_dealloc(bool current_dealloc, const void *ptr,
true_size, input_size, ptr, src, suggest_debug_build);
}
void
safety_check_set_abort(safety_check_abort_hook_t abort_fn) {
safety_check_abort = abort_fn;
}
/*
* In addition to malloc_write, also embed hint msg in the abort function name
* because there are cases only logging crash stack traces.
*/
static void
safety_check_detected_heap_corruption___run_address_sanitizer_build_to_debug(
const char *buf) {
if (safety_check_abort == NULL) {
const char *buf) {
if (test_hooks_safety_check_abort == NULL) {
malloc_write(buf);
abort();
} else {
safety_check_abort(buf);
test_hooks_safety_check_abort(buf);
}
}

View file

@ -1708,10 +1708,9 @@ stats_general_print(emitter_t *emitter) {
MALLOC_CONF_WRITE("global_var", "Global variable malloc_conf");
MALLOC_CONF_WRITE("symlink", "Symbolic link malloc.conf");
MALLOC_CONF_WRITE("env_var", "Environment variable MALLOC_CONF");
/* As this config is unofficial, skip the output if it's NULL */
if (je_mallctl("opt.malloc_conf.global_var_2_conf_harder", (void *)&cpv,
&cpsz, NULL, 0)
== 0) {
/* As this config is unofficial, skip the output if it's NULL. */
if (je_malloc_conf_2_conf_harder != NULL) {
cpv = je_malloc_conf_2_conf_harder;
emitter_kv(emitter, "global_var_2_conf_harder",
"Global "
"variable malloc_conf_2_conf_harder",

View file

@ -10,3 +10,6 @@ void (*test_hooks_arena_new_hook)(void) = NULL;
JEMALLOC_EXPORT
void (*test_hooks_libc_hook)(void) = NULL;
JEMALLOC_EXPORT
void (*test_hooks_safety_check_abort)(const char *) = NULL;

View file

@ -3,10 +3,9 @@
#include "test/jemalloc_test.h"
/*
* We can't test C++ in unit tests. In order to intercept abort, use a secret
* safety check abort hook in integration tests.
* We can't test C++ in unit tests. In order to intercept abort, use the
* internal test hook in integration tests.
*/
typedef void (*abort_hook_t)(const char *message);
bool fake_abort_called;
void
fake_abort(const char *message) {
@ -34,10 +33,7 @@ own_operator_new(void) {
}
TEST_BEGIN(test_failing_alloc) {
abort_hook_t abort_hook = &fake_abort;
expect_d_eq(mallctl("experimental.hooks.safety_check_abort", NULL, NULL,
(void *)&abort_hook, sizeof(abort_hook)),
0, "Unexpected mallctl failure setting abort hook");
test_hooks_safety_check_abort = &fake_abort;
/*
* Not owning operator new is only expected to happen on MinGW which
@ -57,6 +53,7 @@ TEST_BEGIN(test_failing_alloc) {
}
expect_ptr_null(ptr, "Allocation should have failed");
expect_b_eq(fake_abort_called, true, "Abort hook not invoked");
test_hooks_safety_check_abort = NULL;
}
TEST_END

View file

@ -150,6 +150,7 @@ p_test_impl(bool do_malloc_init, bool do_reentrant, test_t *t, va_list ap) {
/* Non-reentrant run. */
reentrancy = non_reentrant;
test_hooks_arena_new_hook = test_hooks_libc_hook = NULL;
test_hooks_safety_check_abort = NULL;
t();
if (test_status > ret) {
ret = test_status;
@ -158,6 +159,7 @@ p_test_impl(bool do_malloc_init, bool do_reentrant, test_t *t, va_list ap) {
if (do_reentrant) {
reentrancy = libc_reentrant;
test_hooks_arena_new_hook = NULL;
test_hooks_safety_check_abort = NULL;
test_hooks_libc_hook = &libc_reentrancy_hook;
t();
if (test_status > ret) {
@ -166,6 +168,7 @@ p_test_impl(bool do_malloc_init, bool do_reentrant, test_t *t, va_list ap) {
reentrancy = arena_new_reentrant;
test_hooks_libc_hook = NULL;
test_hooks_safety_check_abort = NULL;
test_hooks_arena_new_hook = &arena_new_reentrancy_hook;
t();
if (test_status > ret) {

View file

@ -2,15 +2,30 @@
case @abi@ in
macho)
export DYLD_FALLBACK_LIBRARY_PATH="@objroot@lib"
export DYLD_FALLBACK_LIBRARY_PATH="@abs_objroot@lib"
;;
pecoff)
export PATH="${PATH}:@objroot@lib"
export PATH="@abs_objroot@lib:${PATH}"
;;
*)
;;
esac
prepare_test_exec() {
case @abi@ in
pecoff)
test_dir=`dirname "$1"`
for dll in @abs_objroot@lib/*.dll ; do
if [ -f "${dll}" ] ; then
cp -f "${dll}" "${test_dir}/"
fi
done
;;
*)
;;
esac
}
# Make a copy of the @JEMALLOC_CPREFIX@MALLOC_CONF passed in to this script, so
# it can be repeatedly concatenated with per test settings.
export MALLOC_CONF_ALL=${@JEMALLOC_CPREFIX@MALLOC_CONF}
@ -45,10 +60,12 @@ for t in $@; do
enable_prof=@enable_prof@ \
disable_large_size_classes=@disable_large_size_classes@ \
. @srcroot@${t}.sh && \
prepare_test_exec ${t}@exe@ && \
export_malloc_conf && \
$JEMALLOC_TEST_PREFIX ${t}@exe@ @abs_srcroot@ @abs_objroot@
else
export MALLOC_CONF= && \
prepare_test_exec ${t}@exe@ && \
export_malloc_conf && \
$JEMALLOC_TEST_PREFIX ${t}@exe@ @abs_srcroot@ @abs_objroot@
fi

View file

@ -12,14 +12,14 @@ fake_abort(const char *message) {
static void
test_double_free_pre(void) {
safety_check_set_abort(&fake_abort);
test_hooks_safety_check_abort = &fake_abort;
fake_abort_called = false;
}
static void
test_double_free_post(void) {
expect_b_eq(fake_abort_called, true, "Double-free check didn't fire.");
safety_check_set_abort(NULL);
test_hooks_safety_check_abort = NULL;
}
static bool

View file

@ -11,8 +11,6 @@
"Output content touched when given invalid arguments"); \
} while (0)
#define TEST_UTIL_QUERY_EINVAL(a, b, c, d, why_inval) \
TEST_UTIL_EINVAL("query", a, b, c, d, why_inval)
#define TEST_UTIL_BATCH_EINVAL(a, b, c, d, why_inval) \
TEST_UTIL_EINVAL("batch_query", a, b, c, d, why_inval)
@ -30,139 +28,6 @@
#define TEST_MAX_SIZE (1 << 20)
TEST_BEGIN(test_query) {
size_t sz;
/*
* Select some sizes that can span both small and large sizes, and are
* numerically unrelated to any size boundaries.
*/
for (sz = 7; sz <= TEST_MAX_SIZE && sz <= SC_LARGE_MAXCLASS;
sz += (sz <= SC_SMALL_MAXCLASS ? 1009 : 99989)) {
void *p = mallocx(sz, 0);
void **in = &p;
size_t in_sz = sizeof(const void *);
size_t out_sz = sizeof(void *) + sizeof(size_t) * 5;
void *out = mallocx(out_sz, 0);
void *out_ref = mallocx(out_sz, 0);
size_t out_sz_ref = out_sz;
assert_ptr_not_null(p, "test pointer allocation failed");
assert_ptr_not_null(out, "test output allocation failed");
assert_ptr_not_null(
out_ref, "test reference output allocation failed");
#define SLABCUR_READ(out) (*(void **)out)
#define COUNTS(out) ((size_t *)((void **)out + 1))
#define NFREE_READ(out) COUNTS(out)[0]
#define NREGS_READ(out) COUNTS(out)[1]
#define SIZE_READ(out) COUNTS(out)[2]
#define BIN_NFREE_READ(out) COUNTS(out)[3]
#define BIN_NREGS_READ(out) COUNTS(out)[4]
SLABCUR_READ(out) = NULL;
NFREE_READ(out) = NREGS_READ(out) = SIZE_READ(out) = -1;
BIN_NFREE_READ(out) = BIN_NREGS_READ(out) = -1;
memcpy(out_ref, out, out_sz);
/* Test invalid argument(s) errors */
TEST_UTIL_QUERY_EINVAL(NULL, &out_sz, in, in_sz, "old is NULL");
TEST_UTIL_QUERY_EINVAL(out, NULL, in, in_sz, "oldlenp is NULL");
TEST_UTIL_QUERY_EINVAL(
out, &out_sz, NULL, in_sz, "newp is NULL");
TEST_UTIL_QUERY_EINVAL(out, &out_sz, in, 0, "newlen is zero");
in_sz -= 1;
TEST_UTIL_QUERY_EINVAL(
out, &out_sz, in, in_sz, "invalid newlen");
in_sz += 1;
out_sz_ref = out_sz -= 2 * sizeof(size_t);
TEST_UTIL_QUERY_EINVAL(
out, &out_sz, in, in_sz, "invalid *oldlenp");
out_sz_ref = out_sz += 2 * sizeof(size_t);
/* Examine output for valid call */
TEST_UTIL_VALID("query");
expect_zu_le(sz, SIZE_READ(out),
"Extent size should be at least allocation size");
expect_zu_eq(SIZE_READ(out) & (PAGE - 1), 0,
"Extent size should be a multiple of page size");
/*
* We don't do much bin checking if prof is on, since profiling
* can produce extents that are for small size classes but not
* slabs, which interferes with things like region counts.
*/
if (!opt_prof && sz <= SC_SMALL_MAXCLASS) {
expect_zu_le(NFREE_READ(out), NREGS_READ(out),
"Extent free count exceeded region count");
expect_zu_le(NREGS_READ(out), SIZE_READ(out),
"Extent region count exceeded size");
expect_zu_ne(NREGS_READ(out), 0,
"Extent region count must be positive");
expect_true(NFREE_READ(out) == 0
|| (SLABCUR_READ(out) != NULL
&& SLABCUR_READ(out) <= p),
"Allocation should follow first fit principle");
if (config_stats) {
expect_zu_le(BIN_NFREE_READ(out),
BIN_NREGS_READ(out),
"Bin free count exceeded region count");
expect_zu_ne(BIN_NREGS_READ(out), 0,
"Bin region count must be positive");
expect_zu_le(NFREE_READ(out),
BIN_NFREE_READ(out),
"Extent free count exceeded bin free count");
expect_zu_le(NREGS_READ(out),
BIN_NREGS_READ(out),
"Extent region count exceeded "
"bin region count");
expect_zu_eq(
BIN_NREGS_READ(out) % NREGS_READ(out), 0,
"Bin region count isn't a multiple of "
"extent region count");
expect_zu_le(
BIN_NFREE_READ(out) - NFREE_READ(out),
BIN_NREGS_READ(out) - NREGS_READ(out),
"Free count in other extents in the bin "
"exceeded region count in other extents "
"in the bin");
expect_zu_le(NREGS_READ(out) - NFREE_READ(out),
BIN_NREGS_READ(out) - BIN_NFREE_READ(out),
"Extent utilized count exceeded "
"bin utilized count");
}
} else if (sz > SC_SMALL_MAXCLASS) {
expect_zu_eq(NFREE_READ(out), 0,
"Extent free count should be zero");
expect_zu_eq(NREGS_READ(out), 1,
"Extent region count should be one");
expect_ptr_null(SLABCUR_READ(out),
"Current slab must be null for large size classes");
if (config_stats) {
expect_zu_eq(BIN_NFREE_READ(out), 0,
"Bin free count must be zero for "
"large sizes");
expect_zu_eq(BIN_NREGS_READ(out), 0,
"Bin region count must be zero for "
"large sizes");
}
}
#undef BIN_NREGS_READ
#undef BIN_NFREE_READ
#undef SIZE_READ
#undef NREGS_READ
#undef NFREE_READ
#undef COUNTS
#undef SLABCUR_READ
free(out_ref);
free(out);
free(p);
}
}
TEST_END
TEST_BEGIN(test_batch) {
size_t sz;
/*
@ -217,10 +82,7 @@ TEST_BEGIN(test_batch) {
"Extent size should be at least allocation size");
expect_zu_eq(SIZE_READ(out, 0) & (PAGE - 1), 0,
"Extent size should be a multiple of page size");
/*
* See the corresponding comment in test_query; profiling breaks
* our slab count expectations.
*/
/* Profiling breaks our slab count expectations. */
if (sz <= SC_SMALL_MAXCLASS && !opt_prof) {
expect_zu_le(NFREE_READ(out, 0), NREGS_READ(out, 0),
"Extent free count exceeded region count");
@ -270,5 +132,5 @@ int
main(void) {
assert_zu_lt(SC_SMALL_MAXCLASS + 100000, TEST_MAX_SIZE,
"Test case cannot cover large classes");
return test(test_query, test_batch);
return test(test_batch);
}

View file

@ -39,13 +39,6 @@ TEST_BEGIN(test_mallctl_global_var) {
expect_str_eq(mc, malloc_conf,
"Unexpected value for the global variable "
"malloc_conf");
expect_d_eq(mallctl("opt.malloc_conf.global_var_2_conf_harder",
(void *)&mc, &sz, NULL, 0),
0, "Unexpected mallctl() failure");
expect_str_eq(mc, malloc_conf_2_conf_harder,
"Unexpected value for the "
"global variable malloc_conf_2_conf_harder");
}
TEST_END

View file

@ -334,9 +334,23 @@ TEST_BEGIN(test_prof_sample_hooks) {
}
TEST_END
TEST_BEGIN(test_prof_hook_noop) {
test_skip_if(!config_prof);
const char *hooks[] = {"experimental.hooks.prof_backtrace",
"experimental.hooks.prof_dump", "experimental.hooks.prof_sample",
"experimental.hooks.prof_sample_free"};
for (unsigned i = 0; i < sizeof(hooks) / sizeof(hooks[0]); i++) {
expect_d_eq(mallctl(hooks[i], NULL, NULL, NULL, 0), EINVAL,
"Unexpected noop hook mallctl result");
}
}
TEST_END
int
main(void) {
return test(test_prof_backtrace_hook_replace,
test_prof_backtrace_hook_augment, test_prof_dump_hook,
test_prof_sample_hooks);
test_prof_sample_hooks, test_prof_hook_noop);
}

View file

@ -25,12 +25,12 @@ TEST_BEGIN(test_malloc_free_overflow) {
test_skip_if(!config_prof);
test_skip_if(!config_opt_safety_checks);
safety_check_set_abort(&fake_abort);
test_hooks_safety_check_abort = &fake_abort;
/* Buffer overflow! */
char *ptr = malloc(128);
buffer_overflow_write(ptr, 128);
free(ptr);
safety_check_set_abort(NULL);
test_hooks_safety_check_abort = NULL;
expect_b_eq(fake_abort_called, true, "Redzone check didn't fire.");
fake_abort_called = false;
@ -41,12 +41,12 @@ TEST_BEGIN(test_mallocx_dallocx_overflow) {
test_skip_if(!config_prof);
test_skip_if(!config_opt_safety_checks);
safety_check_set_abort(&fake_abort);
test_hooks_safety_check_abort = &fake_abort;
/* Buffer overflow! */
char *ptr = mallocx(128, 0);
buffer_overflow_write(ptr, 128);
dallocx(ptr, 0);
safety_check_set_abort(NULL);
test_hooks_safety_check_abort = NULL;
expect_b_eq(fake_abort_called, true, "Redzone check didn't fire.");
fake_abort_called = false;
@ -57,12 +57,12 @@ TEST_BEGIN(test_malloc_sdallocx_overflow) {
test_skip_if(!config_prof);
test_skip_if(!config_opt_safety_checks);
safety_check_set_abort(&fake_abort);
test_hooks_safety_check_abort = &fake_abort;
/* Buffer overflow! */
char *ptr = malloc(128);
buffer_overflow_write(ptr, 128);
sdallocx(ptr, 128, 0);
safety_check_set_abort(NULL);
test_hooks_safety_check_abort = NULL;
expect_b_eq(fake_abort_called, true, "Redzone check didn't fire.");
fake_abort_called = false;
@ -73,12 +73,12 @@ TEST_BEGIN(test_realloc_overflow) {
test_skip_if(!config_prof);
test_skip_if(!config_opt_safety_checks);
safety_check_set_abort(&fake_abort);
test_hooks_safety_check_abort = &fake_abort;
/* Buffer overflow! */
char *ptr = malloc(128);
buffer_overflow_write(ptr, 128);
ptr = realloc(ptr, 129);
safety_check_set_abort(NULL);
test_hooks_safety_check_abort = NULL;
free(ptr);
expect_b_eq(fake_abort_called, true, "Redzone check didn't fire.");
@ -90,12 +90,12 @@ TEST_BEGIN(test_rallocx_overflow) {
test_skip_if(!config_prof);
test_skip_if(!config_opt_safety_checks);
safety_check_set_abort(&fake_abort);
test_hooks_safety_check_abort = &fake_abort;
/* Buffer overflow! */
char *ptr = malloc(128);
buffer_overflow_write(ptr, 128);
ptr = rallocx(ptr, 129, 0);
safety_check_set_abort(NULL);
test_hooks_safety_check_abort = NULL;
free(ptr);
expect_b_eq(fake_abort_called, true, "Redzone check didn't fire.");
@ -107,7 +107,7 @@ TEST_BEGIN(test_xallocx_overflow) {
test_skip_if(!config_prof);
test_skip_if(!config_opt_safety_checks);
safety_check_set_abort(&fake_abort);
test_hooks_safety_check_abort = &fake_abort;
/* Buffer overflow! */
char *ptr = malloc(128);
buffer_overflow_write(ptr, 128);
@ -116,7 +116,7 @@ TEST_BEGIN(test_xallocx_overflow) {
free(ptr);
expect_b_eq(fake_abort_called, true, "Redzone check didn't fire.");
fake_abort_called = false;
safety_check_set_abort(NULL);
test_hooks_safety_check_abort = NULL;
}
TEST_END

View file

@ -17,7 +17,7 @@ fake_abort(const char *message) {
static void *
test_invalid_size_pre(size_t sz) {
safety_check_set_abort(&fake_abort);
test_hooks_safety_check_abort = &fake_abort;
fake_abort_called = false;
void *ptr = malloc(sz);
@ -29,7 +29,7 @@ test_invalid_size_pre(size_t sz) {
static void
test_invalid_size_post(void) {
expect_true(fake_abort_called, "Safety check didn't fire");
safety_check_set_abort(NULL);
test_hooks_safety_check_abort = NULL;
}
TEST_BEGIN(test_invalid_size_sdallocx) {

View file

@ -19,7 +19,7 @@ fake_abort(const char *message) {
static void
test_write_after_free_pre(void) {
safety_check_set_abort(&fake_abort);
test_hooks_safety_check_abort = &fake_abort;
fake_abort_called = false;
}
@ -28,7 +28,7 @@ test_write_after_free_post(void) {
assert_d_eq(mallctl("thread.tcache.flush", NULL, NULL, NULL, 0), 0,
"Unexpected tcache flush failure");
expect_true(fake_abort_called, "Use-after-free check didn't fire.");
safety_check_set_abort(NULL);
test_hooks_safety_check_abort = NULL;
}
static bool

View file

@ -12,7 +12,7 @@ set_abort_called(const char *message) {
TEST_BEGIN(test_realloc_abort) {
abort_called = false;
safety_check_set_abort(&set_abort_called);
test_hooks_safety_check_abort = &set_abort_called;
void *ptr = mallocx(42, 0);
expect_ptr_not_null(ptr, "Unexpected mallocx error");
ptr = realloc(ptr, 0);