Implement mallctl{nametomib,bymib}().
Replace chunk stats code that was missing locking; this fixes a race condition that could corrupt chunk statistics. Converting malloc_stats_print() to use mallctl*(). Add a missing semicolon in th DSS code. Convert malloc_tcache_flush() to a mallctl. Convert malloc_swap_enable() to a set of mallctl's.
This commit is contained in:
@@ -391,6 +391,8 @@ extern size_t medium_max;
|
||||
extern size_t lg_mspace;
|
||||
extern size_t mspace_mask;
|
||||
|
||||
#define nlclasses ((chunksize - PAGE_SIZE) >> PAGE_SHIFT)
|
||||
|
||||
#ifdef JEMALLOC_TCACHE
|
||||
void arena_tcache_fill(arena_t *arena, tcache_bin_t *tbin, size_t binind);
|
||||
#endif
|
||||
@@ -407,14 +409,6 @@ void arena_dalloc_large(arena_t *arena, arena_chunk_t *chunk, void *ptr);
|
||||
void arena_stats_merge(arena_t *arena, size_t *nactive, size_t *ndirty,
|
||||
arena_stats_t *astats, malloc_bin_stats_t *bstats,
|
||||
malloc_large_stats_t *lstats);
|
||||
void arena_stats_mprint(arena_t *arena, size_t nactive, size_t ndirty,
|
||||
const arena_stats_t *astats, const malloc_bin_stats_t *bstats,
|
||||
const malloc_large_stats_t *lstats, bool bins, bool large,
|
||||
void (*write4)(void *, const char *, const char *, const char *,
|
||||
const char *), void *w4opaque);
|
||||
void arena_stats_print(arena_t *arena, bool bins, bool large,
|
||||
void (*write4)(void *, const char *, const char *, const char *,
|
||||
const char *), void *w4opaque);
|
||||
#endif
|
||||
void *arena_ralloc(void *ptr, size_t size, size_t oldsize);
|
||||
bool arena_new(arena_t *arena, unsigned ind);
|
||||
|
||||
@@ -33,6 +33,8 @@ extern bool opt_overcommit;
|
||||
#endif
|
||||
|
||||
#ifdef JEMALLOC_STATS
|
||||
/* Protects stats_chunks; currently not used for any other purpose. */
|
||||
extern malloc_mutex_t chunks_mtx;
|
||||
/* Chunk statistics. */
|
||||
extern chunk_stats_t stats_chunks;
|
||||
#endif
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
|
||||
extern malloc_mutex_t swap_mtx;
|
||||
extern bool swap_enabled;
|
||||
extern bool swap_prezeroed;
|
||||
extern size_t swap_nfds;
|
||||
extern int *swap_fds;
|
||||
#ifdef JEMALLOC_STATS
|
||||
extern size_t swap_avail;
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_TYPES
|
||||
|
||||
typedef struct ctl_node_s ctl_node_t;
|
||||
typedef struct ctl_arena_stats_s ctl_arena_stats_t;
|
||||
typedef struct ctl_stats_s ctl_stats_t;
|
||||
|
||||
#endif /* JEMALLOC_H_TYPES */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_STRUCTS
|
||||
|
||||
struct ctl_node_s {
|
||||
bool named;
|
||||
union {
|
||||
struct {
|
||||
const char *name;
|
||||
/* If (nchildren == 0), this is a terminal node. */
|
||||
unsigned nchildren;
|
||||
const ctl_node_t *children;
|
||||
} named;
|
||||
struct {
|
||||
const ctl_node_t *(*index)(const size_t *, size_t,
|
||||
size_t);
|
||||
} indexed;
|
||||
} u;
|
||||
int (*ctl)(const size_t *, size_t, void *, size_t *, void *,
|
||||
size_t);
|
||||
};
|
||||
|
||||
struct ctl_arena_stats_s {
|
||||
bool initialized;
|
||||
size_t pactive;
|
||||
size_t pdirty;
|
||||
#ifdef JEMALLOC_STATS
|
||||
arena_stats_t astats;
|
||||
malloc_bin_stats_t *bstats; /* nbins elements. */
|
||||
malloc_large_stats_t *lstats; /* nlclasses elements. */
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ctl_stats_s {
|
||||
#ifdef JEMALLOC_STATS
|
||||
size_t allocated;
|
||||
size_t active;
|
||||
size_t mapped;
|
||||
struct {
|
||||
size_t current; /* stats_chunks.curchunks */
|
||||
uint64_t total; /* stats_chunks.nchunks */
|
||||
size_t high; /* stats_chunks.highchunks */
|
||||
} chunks;
|
||||
struct {
|
||||
size_t allocated; /* huge_allocated */
|
||||
uint64_t nmalloc; /* huge_nmalloc */
|
||||
uint64_t ndalloc; /* huge_ndalloc */
|
||||
} huge;
|
||||
#endif
|
||||
ctl_arena_stats_t *arenas; /* (narenas + 1) elements. */
|
||||
#ifdef JEMALLOC_SWAP
|
||||
size_t swap_avail;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* JEMALLOC_H_STRUCTS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_EXTERNS
|
||||
|
||||
int ctl_byname(const char *name, void *oldp, size_t *oldlenp, void *newp,
|
||||
size_t newlen);
|
||||
int ctl_nametomib(const char *name, size_t *mibp, size_t *miblenp);
|
||||
|
||||
int ctl_bymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
|
||||
void *newp, size_t newlen);
|
||||
bool ctl_boot(void);
|
||||
|
||||
#define xmallctl(name, oldp, oldlenp, newp, newlen) do { \
|
||||
if (mallctl(name, oldp, oldlenp, newp, newlen) != 0) { \
|
||||
malloc_write4("<jemalloc>: Invalid xmallctl(\"", name, \
|
||||
"\", ...) call\n", ""); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define xmallctlnametomib(name, mibp, miblenp) do { \
|
||||
if (mallctlnametomib(name, mibp, miblenp) != 0) { \
|
||||
malloc_write4( \
|
||||
"<jemalloc>: Invalid xmallctlnametomib(\"", name, \
|
||||
"\", ...) call\n", ""); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define xmallctlbymib(mib, miblen, oldp, oldlenp, newp, newlen) do { \
|
||||
if (mallctlbymib(mib, miblen, oldp, oldlenp, newp, newlen) \
|
||||
!= 0) { \
|
||||
malloc_write4( \
|
||||
"<jemalloc>: Invalid xmallctlbymib() call\n", "", \
|
||||
"", ""); \
|
||||
abort(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* JEMALLOC_H_EXTERNS */
|
||||
/******************************************************************************/
|
||||
#ifdef JEMALLOC_H_INLINES
|
||||
|
||||
#endif /* JEMALLOC_H_INLINES */
|
||||
/******************************************************************************/
|
||||
|
||||
@@ -170,6 +170,7 @@ extern void (*JEMALLOC_P(malloc_message))(void *w4opaque, const char *p1,
|
||||
(((s) + PAGE_MASK) & ~PAGE_MASK)
|
||||
|
||||
#include "internal/jemalloc_stats.h"
|
||||
#include "internal/jemalloc_ctl.h"
|
||||
#include "internal/jemalloc_mutex.h"
|
||||
#include "internal/jemalloc_extent.h"
|
||||
#include "internal/jemalloc_arena.h"
|
||||
@@ -184,6 +185,7 @@ extern void (*JEMALLOC_P(malloc_message))(void *w4opaque, const char *p1,
|
||||
#define JEMALLOC_H_STRUCTS
|
||||
|
||||
#include "internal/jemalloc_stats.h"
|
||||
#include "internal/jemalloc_ctl.h"
|
||||
#include "internal/jemalloc_mutex.h"
|
||||
#include "internal/jemalloc_extent.h"
|
||||
#include "internal/jemalloc_arena.h"
|
||||
@@ -220,6 +222,7 @@ extern size_t lg_pagesize;
|
||||
/* Number of CPUs. */
|
||||
extern unsigned ncpus;
|
||||
|
||||
extern malloc_mutex_t arenas_lock; /* Protects arenas initialization. */
|
||||
#ifndef NO_TLS
|
||||
/*
|
||||
* Map of pthread_self() --> arenas[???], used for selecting an arena to use
|
||||
@@ -240,6 +243,7 @@ arena_t *choose_arena_hard(void);
|
||||
#endif
|
||||
|
||||
#include "internal/jemalloc_stats.h"
|
||||
#include "internal/jemalloc_ctl.h"
|
||||
#include "internal/jemalloc_mutex.h"
|
||||
#include "internal/jemalloc_extent.h"
|
||||
#include "internal/jemalloc_arena.h"
|
||||
@@ -254,6 +258,7 @@ arena_t *choose_arena_hard(void);
|
||||
#define JEMALLOC_H_INLINES
|
||||
|
||||
#include "internal/jemalloc_stats.h"
|
||||
#include "internal/jemalloc_ctl.h"
|
||||
#include "internal/jemalloc_mutex.h"
|
||||
#include "internal/jemalloc_extent.h"
|
||||
#include "internal/jemalloc_base.h"
|
||||
|
||||
@@ -21,7 +21,7 @@ void trace_free(const void *ptr, size_t size);
|
||||
void trace_malloc_usable_size(size_t size, const void *ptr);
|
||||
void trace_thread_exit(void);
|
||||
|
||||
void trace_boot(void);
|
||||
bool trace_boot(void);
|
||||
|
||||
#endif /* JEMALLOC_H_EXTERNS */
|
||||
/******************************************************************************/
|
||||
|
||||
+43
-24
@@ -95,12 +95,12 @@
|
||||
/******************************************************************************/
|
||||
/* Data. */
|
||||
|
||||
malloc_mutex_t arenas_lock;
|
||||
arena_t **arenas;
|
||||
unsigned narenas;
|
||||
#ifndef NO_TLS
|
||||
static unsigned next_arena;
|
||||
#endif
|
||||
static malloc_mutex_t arenas_lock; /* Protects arenas initialization. */
|
||||
|
||||
#ifndef NO_TLS
|
||||
__thread arena_t *arenas_map JEMALLOC_ATTR(tls_model("initial-exec"));
|
||||
@@ -710,9 +710,18 @@ MALLOC_OUT:
|
||||
}
|
||||
}
|
||||
|
||||
if (ctl_boot()) {
|
||||
malloc_mutex_unlock(&init_lock);
|
||||
return (true);
|
||||
}
|
||||
|
||||
#ifdef JEMALLOC_TRACE
|
||||
if (opt_trace)
|
||||
trace_boot();
|
||||
if (opt_trace) {
|
||||
if (trace_boot()) {
|
||||
malloc_mutex_unlock(&init_lock);
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (opt_stats_print) {
|
||||
/* Print statistics at exit. */
|
||||
@@ -722,6 +731,11 @@ MALLOC_OUT:
|
||||
/* Register fork handlers. */
|
||||
pthread_atfork(jemalloc_prefork, jemalloc_postfork, jemalloc_postfork);
|
||||
|
||||
if (base_boot()) {
|
||||
malloc_mutex_unlock(&init_lock);
|
||||
return (true);
|
||||
}
|
||||
|
||||
if (arena_boot0()) {
|
||||
malloc_mutex_unlock(&init_lock);
|
||||
return (true);
|
||||
@@ -742,11 +756,6 @@ MALLOC_OUT:
|
||||
return (true);
|
||||
}
|
||||
|
||||
if (huge_boot()) {
|
||||
malloc_mutex_unlock(&init_lock);
|
||||
return (true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create enough scaffolding to allow recursive allocation in
|
||||
* malloc_ncpus().
|
||||
@@ -1222,22 +1231,6 @@ JEMALLOC_P(malloc_swap_enable)(const int *fds, unsigned nfds, int prezeroed)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef JEMALLOC_TCACHE
|
||||
JEMALLOC_ATTR(visibility("default"))
|
||||
void
|
||||
JEMALLOC_P(malloc_tcache_flush)(void)
|
||||
{
|
||||
tcache_t *tcache;
|
||||
|
||||
tcache = tcache_tls;
|
||||
if (tcache == NULL)
|
||||
return;
|
||||
|
||||
tcache_destroy(tcache);
|
||||
tcache_tls = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
JEMALLOC_ATTR(visibility("default"))
|
||||
void
|
||||
JEMALLOC_P(malloc_stats_print)(void (*write4)(void *, const char *,
|
||||
@@ -1247,6 +1240,32 @@ JEMALLOC_P(malloc_stats_print)(void (*write4)(void *, const char *,
|
||||
stats_print(write4, w4opaque, opts);
|
||||
}
|
||||
|
||||
JEMALLOC_ATTR(visibility("default"))
|
||||
int
|
||||
JEMALLOC_P(mallctl)(const char *name, void *oldp, size_t *oldlenp, void *newp,
|
||||
size_t newlen)
|
||||
{
|
||||
|
||||
return (ctl_byname(name, oldp, oldlenp, newp, newlen));
|
||||
}
|
||||
|
||||
JEMALLOC_ATTR(visibility("default"))
|
||||
int
|
||||
JEMALLOC_P(mallctlnametomib)(const char *name, size_t *mibp, size_t *miblenp)
|
||||
{
|
||||
|
||||
return (ctl_nametomib(name, mibp, miblenp));
|
||||
}
|
||||
|
||||
JEMALLOC_ATTR(visibility("default"))
|
||||
int
|
||||
JEMALLOC_P(mallctlbymib)(const size_t *mib, size_t miblen, void *oldp,
|
||||
size_t *oldlenp, void *newp, size_t newlen)
|
||||
{
|
||||
|
||||
return (ctl_bymib(mib, miblen, oldp, oldlenp, newp, newlen));
|
||||
}
|
||||
|
||||
/*
|
||||
* End non-standard functions.
|
||||
*/
|
||||
|
||||
@@ -21,16 +21,15 @@ void *JEMALLOC_P(realloc)(void *ptr, size_t size);
|
||||
void JEMALLOC_P(free)(void *ptr);
|
||||
|
||||
size_t JEMALLOC_P(malloc_usable_size)(const void *ptr);
|
||||
#ifdef JEMALLOC_SWAP
|
||||
int JEMALLOC_P(malloc_swap_enable)(const int *fds, unsigned nfds,
|
||||
int prezeroed);
|
||||
#endif
|
||||
#ifdef JEMALLOC_TCACHE
|
||||
void JEMALLOC_P(malloc_tcache_flush)(void);
|
||||
#endif
|
||||
void JEMALLOC_P(malloc_stats_print)(void (*write4)(void *, const char *,
|
||||
const char *, const char *, const char *), void *w4opaque,
|
||||
const char *opts);
|
||||
int JEMALLOC_P(mallctl)(const char *name, void *oldp, size_t *oldlenp,
|
||||
void *newp, size_t newlen);
|
||||
int JEMALLOC_P(mallctlnametomib)(const char *name, size_t *mibp,
|
||||
size_t *miblenp);
|
||||
int JEMALLOC_P(mallctlbymib)(const size_t *mib, size_t miblen, void *oldp,
|
||||
size_t *oldlenp, void *newp, size_t newlen);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
|
||||
@@ -172,19 +172,6 @@ static void *arena_malloc_large(arena_t *arena, size_t size, bool zero);
|
||||
static bool arena_is_large(const void *ptr);
|
||||
static void arena_dalloc_bin_run(arena_t *arena, arena_chunk_t *chunk,
|
||||
arena_run_t *run, arena_bin_t *bin);
|
||||
#ifdef JEMALLOC_STATS
|
||||
static void arena_stats_aprint(size_t nactive, size_t ndirty,
|
||||
const arena_stats_t *astats,
|
||||
void (*write4)(void *, const char *, const char *, const char *,
|
||||
const char *), void *w4opaque);
|
||||
static void arena_stats_bprint(arena_t *arena,
|
||||
const malloc_bin_stats_t *bstats,
|
||||
void (*write4)(void *, const char *, const char *, const char *,
|
||||
const char *), void *w4opaque);
|
||||
static void arena_stats_lprint(const malloc_large_stats_t *lstats,
|
||||
void (*write4)(void *, const char *, const char *, const char *,
|
||||
const char *), void *w4opaque);
|
||||
#endif
|
||||
static void arena_ralloc_large_shrink(arena_t *arena, arena_chunk_t *chunk,
|
||||
void *ptr, size_t size, size_t oldsize);
|
||||
static bool arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk,
|
||||
@@ -1570,7 +1557,7 @@ arena_stats_merge(arena_t *arena, size_t *nactive, size_t *ndirty,
|
||||
arena_stats_t *astats, malloc_bin_stats_t *bstats,
|
||||
malloc_large_stats_t *lstats)
|
||||
{
|
||||
unsigned i, nlclasses;
|
||||
unsigned i;
|
||||
|
||||
*nactive += arena->nactive;
|
||||
*ndirty += arena->ndirty;
|
||||
@@ -1601,193 +1588,12 @@ arena_stats_merge(arena_t *arena, size_t *nactive, size_t *ndirty,
|
||||
bstats[i].curruns += arena->bins[i].stats.curruns;
|
||||
}
|
||||
|
||||
for (i = 0, nlclasses = (chunksize - PAGE_SIZE) >> PAGE_SHIFT;
|
||||
i < nlclasses;
|
||||
i++) {
|
||||
for (i = 0; i < nlclasses; i++) {
|
||||
lstats[i].nrequests += arena->stats.lstats[i].nrequests;
|
||||
lstats[i].highruns += arena->stats.lstats[i].highruns;
|
||||
lstats[i].curruns += arena->stats.lstats[i].curruns;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
arena_stats_aprint(size_t nactive, size_t ndirty, const arena_stats_t *astats,
|
||||
void (*write4)(void *, const char *, const char *, const char *,
|
||||
const char *), void *w4opaque)
|
||||
{
|
||||
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"dirty pages: %zu:%zu active:dirty, %"PRIu64" sweep%s,"
|
||||
" %"PRIu64" madvise%s, %"PRIu64" purged\n",
|
||||
nactive, ndirty,
|
||||
astats->npurge, astats->npurge == 1 ? "" : "s",
|
||||
astats->nmadvise, astats->nmadvise == 1 ? "" : "s",
|
||||
astats->purged);
|
||||
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
" allocated nmalloc ndalloc\n");
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"small: %12zu %12"PRIu64" %12"PRIu64"\n",
|
||||
astats->allocated_small, astats->nmalloc_small,
|
||||
astats->ndalloc_small);
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"medium: %12zu %12"PRIu64" %12"PRIu64"\n",
|
||||
astats->allocated_medium, astats->nmalloc_medium,
|
||||
astats->ndalloc_medium);
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"large: %12zu %12"PRIu64" %12"PRIu64"\n",
|
||||
astats->allocated_large, astats->nmalloc_large,
|
||||
astats->ndalloc_large);
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"total: %12zu %12"PRIu64" %12"PRIu64"\n",
|
||||
astats->allocated_small + astats->allocated_medium +
|
||||
astats->allocated_large, astats->nmalloc_small +
|
||||
astats->nmalloc_medium + astats->nmalloc_large,
|
||||
astats->ndalloc_small + astats->ndalloc_medium +
|
||||
astats->ndalloc_large);
|
||||
malloc_cprintf(write4, w4opaque, "mapped: %12zu\n", astats->mapped);
|
||||
}
|
||||
|
||||
static void
|
||||
arena_stats_bprint(arena_t *arena, const malloc_bin_stats_t *bstats,
|
||||
void (*write4)(void *, const char *, const char *, const char *,
|
||||
const char *), void *w4opaque)
|
||||
{
|
||||
unsigned i, gap_start;
|
||||
|
||||
#ifdef JEMALLOC_TCACHE
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"bins: bin size regs pgs requests "
|
||||
"nfills nflushes newruns reruns maxruns curruns\n");
|
||||
#else
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"bins: bin size regs pgs requests "
|
||||
"newruns reruns maxruns curruns\n");
|
||||
#endif
|
||||
for (i = 0, gap_start = UINT_MAX; i < nbins; i++) {
|
||||
if (bstats[i].nruns == 0) {
|
||||
if (gap_start == UINT_MAX)
|
||||
gap_start = i;
|
||||
} else {
|
||||
if (gap_start != UINT_MAX) {
|
||||
if (i > gap_start + 1) {
|
||||
/* Gap of more than one size class. */
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"[%u..%u]\n", gap_start,
|
||||
i - 1);
|
||||
} else {
|
||||
/* Gap of one size class. */
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"[%u]\n", gap_start);
|
||||
}
|
||||
gap_start = UINT_MAX;
|
||||
}
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"%13u %1s %5u %4u %3u %9"PRIu64" %9"PRIu64
|
||||
#ifdef JEMALLOC_TCACHE
|
||||
" %9"PRIu64" %9"PRIu64""
|
||||
#endif
|
||||
" %9"PRIu64" %7zu %7zu\n",
|
||||
i,
|
||||
i < ntbins ? "T" : i < ntbins + nqbins ?
|
||||
"Q" : i < ntbins + nqbins + ncbins ? "C" :
|
||||
i < ntbins + nqbins + ncbins + nsbins ? "S"
|
||||
: "M",
|
||||
arena->bins[i].reg_size,
|
||||
arena->bins[i].nregs,
|
||||
arena->bins[i].run_size >> PAGE_SHIFT,
|
||||
bstats[i].nrequests,
|
||||
#ifdef JEMALLOC_TCACHE
|
||||
bstats[i].nfills,
|
||||
bstats[i].nflushes,
|
||||
#endif
|
||||
bstats[i].nruns,
|
||||
bstats[i].reruns,
|
||||
bstats[i].highruns,
|
||||
bstats[i].curruns);
|
||||
}
|
||||
}
|
||||
if (gap_start != UINT_MAX) {
|
||||
if (i > gap_start + 1) {
|
||||
/* Gap of more than one size class. */
|
||||
malloc_cprintf(write4, w4opaque, "[%u..%u]\n",
|
||||
gap_start, i - 1);
|
||||
} else {
|
||||
/* Gap of one size class. */
|
||||
malloc_cprintf(write4, w4opaque, "[%u]\n", gap_start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
arena_stats_lprint(const malloc_large_stats_t *lstats,
|
||||
void (*write4)(void *, const char *, const char *, const char *,
|
||||
const char *), void *w4opaque)
|
||||
{
|
||||
size_t i;
|
||||
ssize_t gap_start;
|
||||
size_t nlclasses = (chunksize - PAGE_SIZE) >> PAGE_SHIFT;
|
||||
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"large: size pages nrequests maxruns curruns\n");
|
||||
|
||||
for (i = 0, gap_start = -1; i < nlclasses; i++) {
|
||||
if (lstats[i].nrequests == 0) {
|
||||
if (gap_start == -1)
|
||||
gap_start = i;
|
||||
} else {
|
||||
if (gap_start != -1) {
|
||||
malloc_cprintf(write4, w4opaque, "[%zu]\n",
|
||||
i - gap_start);
|
||||
gap_start = -1;
|
||||
}
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"%13zu %5zu %9"PRIu64" %9zu %9zu\n",
|
||||
(i+1) << PAGE_SHIFT, i+1,
|
||||
lstats[i].nrequests,
|
||||
lstats[i].highruns,
|
||||
lstats[i].curruns);
|
||||
}
|
||||
}
|
||||
if (gap_start != -1)
|
||||
malloc_cprintf(write4, w4opaque, "[%zu]\n", i - gap_start);
|
||||
}
|
||||
|
||||
void
|
||||
arena_stats_mprint(arena_t *arena, size_t nactive, size_t ndirty,
|
||||
const arena_stats_t *astats, const malloc_bin_stats_t *bstats,
|
||||
const malloc_large_stats_t *lstats, bool bins, bool large,
|
||||
void (*write4)(void *, const char *, const char *, const char *,
|
||||
const char *), void *w4opaque)
|
||||
{
|
||||
|
||||
arena_stats_aprint(nactive, ndirty, astats, write4, w4opaque);
|
||||
if (bins && astats->nmalloc_small + astats->nmalloc_medium > 0)
|
||||
arena_stats_bprint(arena, bstats, write4, w4opaque);
|
||||
if (large && astats->nmalloc_large > 0)
|
||||
arena_stats_lprint(lstats, write4, w4opaque);
|
||||
}
|
||||
|
||||
void
|
||||
arena_stats_print(arena_t *arena, bool bins, bool large,
|
||||
void (*write4)(void *, const char *, const char *, const char *,
|
||||
const char *), void *w4opaque)
|
||||
{
|
||||
size_t nactive, ndirty;
|
||||
arena_stats_t astats;
|
||||
malloc_bin_stats_t bstats[nbins];
|
||||
malloc_large_stats_t lstats[((chunksize - PAGE_SIZE) >> PAGE_SHIFT)];
|
||||
|
||||
nactive = 0;
|
||||
ndirty = 0;
|
||||
memset(&astats, 0, sizeof(astats));
|
||||
memset(bstats, 0, sizeof(bstats));
|
||||
memset(lstats, 0, sizeof(lstats));
|
||||
|
||||
arena_stats_merge(arena, &nactive, &ndirty, &astats, bstats, lstats);
|
||||
arena_stats_mprint(arena, nactive, ndirty, &astats, bstats, lstats,
|
||||
bins, large, write4, w4opaque);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
|
||||
@@ -10,6 +10,7 @@ bool opt_overcommit = true;
|
||||
#endif
|
||||
|
||||
#ifdef JEMALLOC_STATS
|
||||
malloc_mutex_t chunks_mtx;
|
||||
chunk_stats_t stats_chunks;
|
||||
#endif
|
||||
|
||||
@@ -64,11 +65,13 @@ chunk_alloc(size_t size, bool *zero)
|
||||
RETURN:
|
||||
#ifdef JEMALLOC_STATS
|
||||
if (ret != NULL) {
|
||||
malloc_mutex_lock(&chunks_mtx);
|
||||
stats_chunks.nchunks += (size / chunksize);
|
||||
stats_chunks.curchunks += (size / chunksize);
|
||||
if (stats_chunks.curchunks > stats_chunks.highchunks)
|
||||
stats_chunks.highchunks = stats_chunks.curchunks;
|
||||
malloc_mutex_unlock(&chunks_mtx);
|
||||
}
|
||||
if (stats_chunks.curchunks > stats_chunks.highchunks)
|
||||
stats_chunks.highchunks = stats_chunks.curchunks;
|
||||
#endif
|
||||
|
||||
assert(CHUNK_ADDR2BASE(ret) == ret);
|
||||
@@ -85,7 +88,9 @@ chunk_dealloc(void *chunk, size_t size)
|
||||
assert((size & chunksize_mask) == 0);
|
||||
|
||||
#ifdef JEMALLOC_STATS
|
||||
malloc_mutex_lock(&chunks_mtx);
|
||||
stats_chunks.curchunks -= (size / chunksize);
|
||||
malloc_mutex_unlock(&chunks_mtx);
|
||||
#endif
|
||||
|
||||
#ifdef JEMALLOC_SWAP
|
||||
@@ -110,6 +115,8 @@ chunk_boot(void)
|
||||
chunk_npages = (chunksize >> PAGE_SHIFT);
|
||||
|
||||
#ifdef JEMALLOC_STATS
|
||||
if (malloc_mutex_init(&chunks_mtx))
|
||||
return (true);
|
||||
memset(&stats_chunks, 0, sizeof(chunk_stats_t));
|
||||
#endif
|
||||
|
||||
|
||||
@@ -243,7 +243,7 @@ chunk_dealloc_dss(void *chunk, size_t size)
|
||||
goto RETURN;
|
||||
}
|
||||
|
||||
ret = true
|
||||
ret = true;
|
||||
RETURN:
|
||||
malloc_mutex_unlock(&dss_mtx);
|
||||
return (ret);
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
|
||||
malloc_mutex_t swap_mtx;
|
||||
bool swap_enabled;
|
||||
bool swap_prezeroed;
|
||||
size_t swap_nfds;
|
||||
int *swap_fds;
|
||||
#ifdef JEMALLOC_STATS
|
||||
size_t swap_avail;
|
||||
#endif
|
||||
|
||||
static bool swap_prezeroed;
|
||||
|
||||
/* Base address of the mmap()ed file(s). */
|
||||
static void *swap_base;
|
||||
/* Current end of the space in use (<= swap_max). */
|
||||
@@ -318,12 +319,21 @@ chunk_swap_enable(const int *fds, unsigned nfds, bool prezeroed)
|
||||
swap_end = swap_base;
|
||||
swap_max = (void *)((uintptr_t)vaddr + cumsize);
|
||||
|
||||
swap_enabled = true;
|
||||
/* Copy the fds array for mallctl purposes. */
|
||||
swap_fds = (int *)base_alloc(nfds * sizeof(int));
|
||||
if (swap_fds == NULL) {
|
||||
ret = true;
|
||||
goto RETURN;
|
||||
}
|
||||
memcpy(swap_fds, fds, nfds * sizeof(int));
|
||||
swap_nfds = nfds;
|
||||
|
||||
#ifdef JEMALLOC_STATS
|
||||
swap_avail = cumsize;
|
||||
#endif
|
||||
|
||||
swap_enabled = true;
|
||||
|
||||
ret = false;
|
||||
RETURN:
|
||||
malloc_mutex_unlock(&swap_mtx);
|
||||
@@ -338,10 +348,12 @@ chunk_swap_boot(void)
|
||||
return (true);
|
||||
|
||||
swap_enabled = false;
|
||||
swap_prezeroed = false; /* swap.* mallctl's depend on this. */
|
||||
swap_nfds = 0;
|
||||
swap_fds = NULL;
|
||||
#ifdef JEMALLOC_STATS
|
||||
swap_avail = 0;
|
||||
#endif
|
||||
swap_prezeroed = false;
|
||||
swap_base = NULL;
|
||||
swap_end = NULL;
|
||||
swap_max = NULL;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+437
-168
@@ -1,6 +1,39 @@
|
||||
#define JEMALLOC_STATS_C_
|
||||
#include "internal/jemalloc_internal.h"
|
||||
|
||||
#define CTL_GET(n, v, t) do { \
|
||||
size_t sz = sizeof(t); \
|
||||
xmallctl(n, v, &sz, NULL, 0); \
|
||||
} while (0)
|
||||
|
||||
#define CTL_I_GET(n, v, t) do { \
|
||||
size_t mib[6]; \
|
||||
size_t miblen = sizeof(mib) / sizeof(size_t); \
|
||||
size_t sz = sizeof(t); \
|
||||
xmallctlnametomib(n, mib, &miblen); \
|
||||
mib[2] = i; \
|
||||
xmallctlbymib(mib, miblen, v, &sz, NULL, 0); \
|
||||
} while (0)
|
||||
|
||||
#define CTL_J_GET(n, v, t) do { \
|
||||
size_t mib[6]; \
|
||||
size_t miblen = sizeof(mib) / sizeof(size_t); \
|
||||
size_t sz = sizeof(t); \
|
||||
xmallctlnametomib(n, mib, &miblen); \
|
||||
mib[2] = j; \
|
||||
xmallctlbymib(mib, miblen, v, &sz, NULL, 0); \
|
||||
} while (0)
|
||||
|
||||
#define CTL_IJ_GET(n, v, t) do { \
|
||||
size_t mib[6]; \
|
||||
size_t miblen = sizeof(mib) / sizeof(size_t); \
|
||||
size_t sz = sizeof(t); \
|
||||
xmallctlnametomib(n, mib, &miblen); \
|
||||
mib[2] = i; \
|
||||
mib[4] = j; \
|
||||
xmallctlbymib(mib, miblen, v, &sz, NULL, 0); \
|
||||
} while (0)
|
||||
|
||||
/******************************************************************************/
|
||||
/* Data. */
|
||||
|
||||
@@ -9,9 +42,17 @@ bool opt_stats_print = false;
|
||||
/******************************************************************************/
|
||||
/* Function prototypes for non-inline static functions. */
|
||||
|
||||
static void
|
||||
malloc_vcprintf(void (*write4)(void *, const char *, const char *, const char *,
|
||||
const char *), void *w4opaque, const char *format, va_list ap);
|
||||
#ifdef JEMALLOC_STATS
|
||||
static void malloc_vcprintf(void (*write4)(void *, const char *,
|
||||
const char *, const char *, const char *), void *w4opaque,
|
||||
const char *format, va_list ap);
|
||||
static void stats_arena_bins_print(void (*write4)(void *, const char *,
|
||||
const char *, const char *, const char *), void *w4opaque, unsigned i);
|
||||
static void stats_arena_lruns_print(void (*write4)(void *, const char *,
|
||||
const char *, const char *, const char *), void *w4opaque, unsigned i);
|
||||
static void stats_arena_print(void (*write4)(void *, const char *,
|
||||
const char *, const char *, const char *), void *w4opaque, unsigned i);
|
||||
#endif
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
@@ -106,10 +147,221 @@ malloc_printf(const char *format, ...)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef JEMALLOC_STATS
|
||||
static void
|
||||
stats_arena_bins_print(void (*write4)(void *, const char *, const char *,
|
||||
const char *, const char *), void *w4opaque, unsigned i)
|
||||
{
|
||||
size_t pagesize;
|
||||
bool config_tcache;
|
||||
unsigned nbins, j, gap_start;
|
||||
|
||||
CTL_GET("arenas.pagesize", &pagesize, size_t);
|
||||
|
||||
CTL_GET("config.tcache", &config_tcache, bool);
|
||||
if (config_tcache) {
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"bins: bin size regs pgs nrequests "
|
||||
"nfills nflushes newruns reruns maxruns curruns\n");
|
||||
} else {
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"bins: bin size regs pgs nrequests "
|
||||
"newruns reruns maxruns curruns\n");
|
||||
}
|
||||
CTL_GET("arenas.nbins", &nbins, unsigned);
|
||||
for (j = 0, gap_start = UINT_MAX; j < nbins; j++) {
|
||||
uint64_t nruns;
|
||||
|
||||
CTL_IJ_GET("stats.arenas.0.bins.0.nruns", &nruns, uint64_t);
|
||||
if (nruns == 0) {
|
||||
if (gap_start == UINT_MAX)
|
||||
gap_start = j;
|
||||
} else {
|
||||
unsigned ntbins_, nqbins, ncbins, nsbins;
|
||||
size_t reg_size, run_size;
|
||||
uint32_t nregs;
|
||||
uint64_t nrequests, nfills, nflushes, reruns;
|
||||
size_t highruns, curruns;
|
||||
|
||||
if (gap_start != UINT_MAX) {
|
||||
if (j > gap_start + 1) {
|
||||
/* Gap of more than one size class. */
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"[%u..%u]\n", gap_start,
|
||||
j - 1);
|
||||
} else {
|
||||
/* Gap of one size class. */
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"[%u]\n", gap_start);
|
||||
}
|
||||
gap_start = UINT_MAX;
|
||||
}
|
||||
CTL_GET("arenas.ntbins", &ntbins_, unsigned);
|
||||
CTL_GET("arenas.nqbins", &nqbins, unsigned);
|
||||
CTL_GET("arenas.ncbins", &ncbins, unsigned);
|
||||
CTL_GET("arenas.nsbins", &nsbins, unsigned);
|
||||
CTL_J_GET("arenas.bin.0.size", ®_size, size_t);
|
||||
CTL_J_GET("arenas.bin.0.nregs", &nregs, uint32_t);
|
||||
CTL_J_GET("arenas.bin.0.run_size", &run_size, size_t);
|
||||
CTL_IJ_GET("stats.arenas.0.bins.0.nrequests",
|
||||
&nrequests, uint64_t);
|
||||
if (config_tcache) {
|
||||
CTL_IJ_GET("stats.arenas.0.bins.0.nfills",
|
||||
&nfills, uint64_t);
|
||||
CTL_IJ_GET("stats.arenas.0.bins.0.nflushes",
|
||||
&nflushes, uint64_t);
|
||||
}
|
||||
CTL_IJ_GET("stats.arenas.0.bins.0.nreruns", &reruns,
|
||||
uint64_t);
|
||||
CTL_IJ_GET("stats.arenas.0.bins.0.highruns", &highruns,
|
||||
size_t);
|
||||
CTL_IJ_GET("stats.arenas.0.bins.0.curruns", &curruns,
|
||||
size_t);
|
||||
if (config_tcache) {
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"%13u %1s %5u %4u %3u %10"PRIu64" %9"PRIu64
|
||||
" %9"PRIu64" %9"PRIu64""
|
||||
" %9"PRIu64" %7zu %7zu\n",
|
||||
j,
|
||||
j < ntbins_ ? "T" : j < ntbins_ + nqbins ?
|
||||
"Q" : j < ntbins_ + nqbins + ncbins ? "C" :
|
||||
j < ntbins_ + nqbins + ncbins + nsbins ? "S"
|
||||
: "M",
|
||||
reg_size, nregs, run_size / pagesize,
|
||||
nrequests, nfills, nflushes, nruns, reruns,
|
||||
highruns, curruns);
|
||||
} else {
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"%13u %1s %5u %4u %3u %10"PRIu64" %9"PRIu64
|
||||
" %9"PRIu64" %7zu %7zu\n",
|
||||
j,
|
||||
j < ntbins_ ? "T" : j < ntbins_ + nqbins ?
|
||||
"Q" : j < ntbins_ + nqbins + ncbins ? "C" :
|
||||
j < ntbins_ + nqbins + ncbins + nsbins ? "S"
|
||||
: "M",
|
||||
reg_size, nregs, run_size / pagesize,
|
||||
nrequests, nruns, reruns, highruns,
|
||||
curruns);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gap_start != UINT_MAX) {
|
||||
if (j > gap_start + 1) {
|
||||
/* Gap of more than one size class. */
|
||||
malloc_cprintf(write4, w4opaque, "[%u..%u]\n",
|
||||
gap_start, j - 1);
|
||||
} else {
|
||||
/* Gap of one size class. */
|
||||
malloc_cprintf(write4, w4opaque, "[%u]\n", gap_start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
stats_arena_lruns_print(void (*write4)(void *, const char *, const char *,
|
||||
const char *, const char *), void *w4opaque, unsigned i)
|
||||
{
|
||||
size_t pagesize, nlruns, j;
|
||||
ssize_t gap_start;
|
||||
|
||||
CTL_GET("arenas.pagesize", &pagesize, size_t);
|
||||
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"large: size pages nrequests maxruns curruns\n");
|
||||
CTL_GET("arenas.nlruns", &nlruns, unsigned);
|
||||
for (j = 0, gap_start = -1; j < nlruns; j++) {
|
||||
uint64_t nrequests;
|
||||
size_t run_size, highruns, curruns;
|
||||
|
||||
CTL_IJ_GET("stats.arenas.0.lruns.0.nrequests", &nrequests,
|
||||
uint64_t);
|
||||
if (nrequests == 0) {
|
||||
if (gap_start == -1)
|
||||
gap_start = j;
|
||||
} else {
|
||||
CTL_J_GET("arenas.lrun.0.size", &run_size, size_t);
|
||||
CTL_IJ_GET("stats.arenas.0.lruns.0.highruns", &highruns,
|
||||
size_t);
|
||||
CTL_IJ_GET("stats.arenas.0.lruns.0.curruns", &curruns,
|
||||
size_t);
|
||||
if (gap_start != -1) {
|
||||
malloc_cprintf(write4, w4opaque, "[%zu]\n",
|
||||
j - gap_start);
|
||||
gap_start = -1;
|
||||
}
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"%13zu %5zu %9"PRIu64" %9zu %9zu\n",
|
||||
run_size, run_size / pagesize, nrequests, highruns,
|
||||
curruns);
|
||||
}
|
||||
}
|
||||
if (gap_start != -1)
|
||||
malloc_cprintf(write4, w4opaque, "[%zu]\n", j - gap_start);
|
||||
}
|
||||
|
||||
static void
|
||||
stats_arena_print(void (*write4)(void *, const char *, const char *,
|
||||
const char *, const char *), void *w4opaque, unsigned i)
|
||||
{
|
||||
size_t pactive, pdirty, mapped;
|
||||
uint64_t npurge, nmadvise, purged;
|
||||
size_t small_allocated;
|
||||
uint64_t small_nmalloc, small_ndalloc;
|
||||
size_t medium_allocated;
|
||||
uint64_t medium_nmalloc, medium_ndalloc;
|
||||
size_t large_allocated;
|
||||
uint64_t large_nmalloc, large_ndalloc;
|
||||
|
||||
CTL_I_GET("stats.arenas.0.pactive", &pactive, size_t);
|
||||
CTL_I_GET("stats.arenas.0.pdirty", &pdirty, size_t);
|
||||
CTL_I_GET("stats.arenas.0.npurge", &npurge, uint64_t);
|
||||
CTL_I_GET("stats.arenas.0.nmadvise", &nmadvise, uint64_t);
|
||||
CTL_I_GET("stats.arenas.0.purged", &purged, uint64_t);
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"dirty pages: %zu:%zu active:dirty, %"PRIu64" sweep%s,"
|
||||
" %"PRIu64" madvise%s, %"PRIu64" purged\n",
|
||||
pactive, pdirty, npurge, npurge == 1 ? "" : "s",
|
||||
nmadvise, nmadvise == 1 ? "" : "s", purged);
|
||||
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
" allocated nmalloc ndalloc\n");
|
||||
CTL_I_GET("stats.arenas.0.small.allocated", &small_allocated, size_t);
|
||||
CTL_I_GET("stats.arenas.0.small.nmalloc", &small_nmalloc, uint64_t);
|
||||
CTL_I_GET("stats.arenas.0.small.ndalloc", &small_ndalloc, uint64_t);
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"small: %12zu %12"PRIu64" %12"PRIu64"\n",
|
||||
small_allocated, small_nmalloc, small_ndalloc);
|
||||
CTL_I_GET("stats.arenas.0.medium.allocated", &medium_allocated, size_t);
|
||||
CTL_I_GET("stats.arenas.0.medium.nmalloc", &medium_nmalloc, uint64_t);
|
||||
CTL_I_GET("stats.arenas.0.medium.ndalloc", &medium_ndalloc, uint64_t);
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"medium: %12zu %12"PRIu64" %12"PRIu64"\n",
|
||||
medium_allocated, medium_nmalloc, medium_ndalloc);
|
||||
CTL_I_GET("stats.arenas.0.large.allocated", &large_allocated, size_t);
|
||||
CTL_I_GET("stats.arenas.0.large.nmalloc", &large_nmalloc, uint64_t);
|
||||
CTL_I_GET("stats.arenas.0.large.ndalloc", &large_ndalloc, uint64_t);
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"large: %12zu %12"PRIu64" %12"PRIu64"\n",
|
||||
large_allocated, large_nmalloc, large_ndalloc);
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"total: %12zu %12"PRIu64" %12"PRIu64"\n",
|
||||
small_allocated + medium_allocated + large_allocated,
|
||||
small_nmalloc + medium_nmalloc + large_nmalloc,
|
||||
small_ndalloc + medium_ndalloc + large_ndalloc);
|
||||
CTL_I_GET("stats.arenas.0.mapped", &mapped, size_t);
|
||||
malloc_cprintf(write4, w4opaque, "mapped: %12zu\n", mapped);
|
||||
|
||||
stats_arena_bins_print(write4, w4opaque, i);
|
||||
stats_arena_lruns_print(write4, w4opaque, i);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
stats_print(void (*write4)(void *, const char *, const char *, const char *,
|
||||
const char *), void *w4opaque, const char *opts)
|
||||
{
|
||||
uint64_t epoch;
|
||||
size_t u64sz;
|
||||
char s[UMAX2S_BUFSIZE];
|
||||
bool general = true;
|
||||
bool merged = true;
|
||||
@@ -117,6 +369,11 @@ stats_print(void (*write4)(void *, const char *, const char *, const char *,
|
||||
bool bins = true;
|
||||
bool large = true;
|
||||
|
||||
/* Refresh stats, in case mallctl() was called by the application. */
|
||||
epoch = 1;
|
||||
u64sz = sizeof(uint64_t);
|
||||
xmallctl("epoch", &epoch, &u64sz, &epoch, sizeof(uint64_t));
|
||||
|
||||
if (write4 == NULL) {
|
||||
/*
|
||||
* The caller did not provide an alternate write4 callback
|
||||
@@ -154,165 +411,175 @@ stats_print(void (*write4)(void *, const char *, const char *, const char *,
|
||||
|
||||
write4(w4opaque, "___ Begin jemalloc statistics ___\n", "", "", "");
|
||||
if (general) {
|
||||
write4(w4opaque, "Assertions ",
|
||||
#ifdef NDEBUG
|
||||
"disabled",
|
||||
#else
|
||||
"enabled",
|
||||
#endif
|
||||
int err;
|
||||
bool bv;
|
||||
unsigned uv;
|
||||
ssize_t ssv;
|
||||
size_t sv, bsz, usz, ssz, sssz;
|
||||
|
||||
bsz = sizeof(bool);
|
||||
usz = sizeof(unsigned);
|
||||
ssz = sizeof(size_t);
|
||||
sssz = sizeof(ssize_t);
|
||||
|
||||
CTL_GET("config.debug", &bv, bool);
|
||||
write4(w4opaque, "Assertions ", bv ? "enabled" : "disabled",
|
||||
"\n", "");
|
||||
write4(w4opaque, "Boolean JEMALLOC_OPTIONS: ",
|
||||
opt_abort ? "A" : "a", "", "");
|
||||
#ifdef JEMALLOC_FILL
|
||||
write4(w4opaque, opt_junk ? "J" : "j", "", "", "");
|
||||
#endif
|
||||
#ifdef JEMALLOC_SWAP
|
||||
write4(w4opaque, opt_overcommit ? "O" : "o", "", "", "");
|
||||
#endif
|
||||
|
||||
write4(w4opaque, "Boolean JEMALLOC_OPTIONS: ", "", "", "");
|
||||
if ((err = mallctl("opt.abort", &bv, &bsz, NULL, 0)) == 0)
|
||||
write4(w4opaque, bv ? "A" : "a", "", "", "");
|
||||
if ((err = mallctl("opt.junk", &bv, &bsz, NULL, 0)) == 0)
|
||||
write4(w4opaque, bv ? "J" : "j", "", "", "");
|
||||
if ((err = mallctl("opt.overcommit", &bv, &bsz, NULL, 0)) == 0)
|
||||
write4(w4opaque, bv ? "O" : "o", "", "", "");
|
||||
write4(w4opaque, "P", "", "", "");
|
||||
#ifdef JEMALLOC_TCACHE
|
||||
write4(w4opaque, opt_tcache_sort ? "S" : "s", "", "", "");
|
||||
#endif
|
||||
#ifdef JEMALLOC_TRACE
|
||||
write4(w4opaque, opt_trace ? "T" : "t", "", "", "");
|
||||
#endif
|
||||
#ifdef JEMALLOC_SYSV
|
||||
write4(w4opaque, opt_sysv ? "V" : "v", "", "", "");
|
||||
#endif
|
||||
#ifdef JEMALLOC_XMALLOC
|
||||
write4(w4opaque, opt_xmalloc ? "X" : "x", "", "", "");
|
||||
#endif
|
||||
#ifdef JEMALLOC_FILL
|
||||
write4(w4opaque, opt_zero ? "Z" : "z", "", "", "");
|
||||
#endif
|
||||
if ((err = mallctl("opt.tcache_sort", &bv, &bsz, NULL, 0)) == 0)
|
||||
write4(w4opaque, bv ? "S" : "s", "", "", "");
|
||||
if ((err = mallctl("opt.trace", &bv, &bsz, NULL, 0)) == 0)
|
||||
write4(w4opaque, bv ? "T" : "t", "", "", "");
|
||||
if ((err = mallctl("opt.sysv", &bv, &bsz, NULL, 0)) == 0)
|
||||
write4(w4opaque, bv ? "V" : "v", "", "", "");
|
||||
if ((err = mallctl("opt.xmalloc", &bv, &bsz, NULL, 0)) == 0)
|
||||
write4(w4opaque, bv ? "X" : "x", "", "", "");
|
||||
if ((err = mallctl("opt.zero", &bv, &bsz, NULL, 0)) == 0)
|
||||
write4(w4opaque, bv ? "Z" : "z", "", "", "");
|
||||
write4(w4opaque, "\n", "", "", "");
|
||||
|
||||
write4(w4opaque, "CPUs: ", umax2s(ncpus, 10, s), "\n", "");
|
||||
write4(w4opaque, "Max arenas: ", umax2s(narenas, 10, s), "\n",
|
||||
"");
|
||||
|
||||
CTL_GET("arenas.narenas", &uv, unsigned);
|
||||
write4(w4opaque, "Max arenas: ", umax2s(uv, 10, s), "\n", "");
|
||||
|
||||
write4(w4opaque, "Pointer size: ", umax2s(sizeof(void *), 10,
|
||||
s), "\n", "");
|
||||
write4(w4opaque, "Quantum size: ", umax2s(QUANTUM, 10, s), "\n",
|
||||
|
||||
CTL_GET("arenas.quantum", &sv, size_t);
|
||||
write4(w4opaque, "Quantum size: ", umax2s(sv, 10, s), "\n", "");
|
||||
|
||||
CTL_GET("arenas.cacheline", &sv, size_t);
|
||||
write4(w4opaque, "Cacheline size (assumed): ", umax2s(sv, 10,
|
||||
s), "\n", "");
|
||||
|
||||
CTL_GET("arenas.subpage", &sv, size_t);
|
||||
write4(w4opaque, "Subpage spacing: ", umax2s(sv, 10, s), "\n",
|
||||
"");
|
||||
write4(w4opaque, "Cacheline size (assumed): ", umax2s(CACHELINE,
|
||||
10, s),
|
||||
"\n", "");
|
||||
write4(w4opaque, "Subpage spacing: ", umax2s(SUBPAGE, 10, s),
|
||||
"\n", "");
|
||||
write4(w4opaque, "Medium spacing: ", umax2s((1U << lg_mspace),
|
||||
10, s), "\n", "");
|
||||
#ifdef JEMALLOC_TINY
|
||||
write4(w4opaque, "Tiny 2^n-spaced sizes: [", umax2s((1U <<
|
||||
LG_TINY_MIN), 10, s), "..", "");
|
||||
write4(w4opaque, umax2s((qspace_min >> 1), 10, s), "]\n", "",
|
||||
|
||||
CTL_GET("arenas.medium", &sv, size_t);
|
||||
write4(w4opaque, "Medium spacing: ", umax2s(sv, 10, s), "\n",
|
||||
"");
|
||||
#endif
|
||||
write4(w4opaque, "Quantum-spaced sizes: [", umax2s(qspace_min,
|
||||
10, s), "..", "");
|
||||
write4(w4opaque, umax2s(qspace_max, 10, s), "]\n", "", "");
|
||||
write4(w4opaque, "Cacheline-spaced sizes: [", umax2s(cspace_min,
|
||||
10, s), "..", "");
|
||||
write4(w4opaque, umax2s(cspace_max, 10, s), "]\n", "", "");
|
||||
write4(w4opaque, "Subpage-spaced sizes: [", umax2s(sspace_min,
|
||||
10, s), "..", "");
|
||||
write4(w4opaque, umax2s(sspace_max, 10, s), "]\n", "", "");
|
||||
write4(w4opaque, "Medium sizes: [", umax2s(medium_min, 10, s),
|
||||
|
||||
if ((err = mallctl("arenas.tspace_min", &sv, &ssz, NULL, 0)) ==
|
||||
0) {
|
||||
write4(w4opaque, "Tiny 2^n-spaced sizes: [", umax2s(sv,
|
||||
10, s), "..", "");
|
||||
|
||||
CTL_GET("arenas.tspace_max", &sv, size_t);
|
||||
write4(w4opaque, umax2s(sv, 10, s), "]\n", "", "");
|
||||
}
|
||||
|
||||
CTL_GET("arenas.qspace_min", &sv, size_t);
|
||||
write4(w4opaque, "Quantum-spaced sizes: [", umax2s(sv, 10, s),
|
||||
"..", "");
|
||||
write4(w4opaque, umax2s(medium_max, 10, s), "]\n", "", "");
|
||||
if (opt_lg_dirty_mult >= 0) {
|
||||
CTL_GET("arenas.qspace_max", &sv, size_t);
|
||||
write4(w4opaque, umax2s(sv, 10, s), "]\n", "", "");
|
||||
|
||||
CTL_GET("arenas.cspace_min", &sv, size_t);
|
||||
write4(w4opaque, "Cacheline-spaced sizes: [", umax2s(sv, 10, s),
|
||||
"..", "");
|
||||
CTL_GET("arenas.cspace_max", &sv, size_t);
|
||||
write4(w4opaque, umax2s(sv, 10, s), "]\n", "", "");
|
||||
|
||||
CTL_GET("arenas.sspace_min", &sv, size_t);
|
||||
write4(w4opaque, "Subpage-spaced sizes: [", umax2s(sv, 10, s),
|
||||
"..", "");
|
||||
CTL_GET("arenas.sspace_max", &sv, size_t);
|
||||
write4(w4opaque, umax2s(sv, 10, s), "]\n", "", "");
|
||||
|
||||
CTL_GET("arenas.medium_min", &sv, size_t);
|
||||
write4(w4opaque, "Medium sizes: [", umax2s(sv, 10, s), "..",
|
||||
"");
|
||||
CTL_GET("arenas.medium_max", &sv, size_t);
|
||||
write4(w4opaque, umax2s(sv, 10, s), "]\n", "", "");
|
||||
|
||||
CTL_GET("opt.lg_dirty_mult", &ssv, ssize_t);
|
||||
if (ssv >= 0) {
|
||||
write4(w4opaque,
|
||||
"Min active:dirty page ratio per arena: ",
|
||||
umax2s((1U << opt_lg_dirty_mult), 10, s), ":1\n",
|
||||
"");
|
||||
umax2s((1U << ssv), 10, s), ":1\n", "");
|
||||
} else {
|
||||
write4(w4opaque,
|
||||
"Min active:dirty page ratio per arena: N/A\n", "",
|
||||
"", "");
|
||||
}
|
||||
#ifdef JEMALLOC_TCACHE
|
||||
write4(w4opaque, "Thread cache slots per size class: ",
|
||||
tcache_nslots ? umax2s(tcache_nslots, 10, s) : "N/A", "\n",
|
||||
"");
|
||||
write4(w4opaque, "Thread cache GC sweep interval: ",
|
||||
(tcache_nslots && tcache_gc_incr > 0) ?
|
||||
umax2s((1U << opt_lg_tcache_gc_sweep), 10, s) : "N/A",
|
||||
"", "");
|
||||
write4(w4opaque, " (increment interval: ",
|
||||
(tcache_nslots && tcache_gc_incr > 0) ?
|
||||
umax2s(tcache_gc_incr, 10, s) : "N/A",
|
||||
")\n", "");
|
||||
if ((err = mallctl("opt.lg_tcache_nslots", &sv, &ssz, NULL, 0))
|
||||
== 0) {
|
||||
size_t tcache_nslots, tcache_gc_sweep;
|
||||
|
||||
tcache_nslots = (1U << sv);
|
||||
write4(w4opaque, "Thread cache slots per size class: ",
|
||||
tcache_nslots ? umax2s(tcache_nslots, 10, s) :
|
||||
"N/A", "\n", "");
|
||||
|
||||
CTL_GET("opt.lg_tcache_gc_sweep", &ssv, ssize_t);
|
||||
tcache_gc_sweep = (1U << ssv);
|
||||
write4(w4opaque, "Thread cache GC sweep interval: ",
|
||||
tcache_nslots && ssv >= 0 ? umax2s(tcache_gc_sweep,
|
||||
10, s) : "N/A", "\n", "");
|
||||
}
|
||||
#endif
|
||||
write4(w4opaque, "Chunk size: ", umax2s(chunksize, 10, s), "",
|
||||
"");
|
||||
write4(w4opaque, " (2^", umax2s(opt_lg_chunk, 10, s), ")\n",
|
||||
"");
|
||||
CTL_GET("arenas.chunksize", &sv, size_t);
|
||||
write4(w4opaque, "Chunk size: ", umax2s(sv, 10, s), "", "");
|
||||
CTL_GET("opt.lg_chunk", &sv, size_t);
|
||||
write4(w4opaque, " (2^", umax2s(sv, 10, s), ")\n", "");
|
||||
}
|
||||
|
||||
#ifdef JEMALLOC_STATS
|
||||
{
|
||||
int err;
|
||||
size_t ssz, u64sz;
|
||||
size_t allocated, mapped;
|
||||
unsigned i;
|
||||
arena_t *arena;
|
||||
size_t chunks_current, chunks_high, swap_avail;
|
||||
uint64_t chunks_total;
|
||||
size_t huge_allocated;
|
||||
uint64_t huge_nmalloc, huge_ndalloc;
|
||||
|
||||
/* Calculate and print allocated/mapped stats. */
|
||||
|
||||
/* arenas. */
|
||||
for (i = 0, allocated = 0; i < narenas; i++) {
|
||||
if (arenas[i] != NULL) {
|
||||
malloc_mutex_lock(&arenas[i]->lock);
|
||||
allocated += arenas[i]->stats.allocated_small;
|
||||
allocated += arenas[i]->stats.allocated_large;
|
||||
malloc_mutex_unlock(&arenas[i]->lock);
|
||||
}
|
||||
}
|
||||
|
||||
/* huge/base. */
|
||||
malloc_mutex_lock(&huge_mtx);
|
||||
allocated += huge_allocated;
|
||||
mapped = stats_chunks.curchunks * chunksize;
|
||||
malloc_mutex_unlock(&huge_mtx);
|
||||
ssz = sizeof(size_t);
|
||||
u64sz = sizeof(uint64_t);
|
||||
|
||||
CTL_GET("stats.allocated", &allocated, size_t);
|
||||
CTL_GET("stats.mapped", &mapped, size_t);
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"Allocated: %zu, mapped: %zu\n", allocated, mapped);
|
||||
|
||||
/* Print chunk stats. */
|
||||
{
|
||||
chunk_stats_t chunks_stats;
|
||||
#ifdef JEMALLOC_SWAP
|
||||
size_t swap_avail_chunks;
|
||||
#endif
|
||||
|
||||
malloc_mutex_lock(&huge_mtx);
|
||||
chunks_stats = stats_chunks;
|
||||
malloc_mutex_unlock(&huge_mtx);
|
||||
|
||||
#ifdef JEMALLOC_SWAP
|
||||
malloc_mutex_lock(&swap_mtx);
|
||||
swap_avail_chunks = swap_avail >> opt_lg_chunk;
|
||||
malloc_mutex_unlock(&swap_mtx);
|
||||
#endif
|
||||
CTL_GET("stats.chunks.total", &chunks_total, uint64_t);
|
||||
CTL_GET("stats.chunks.high", &chunks_high, size_t);
|
||||
CTL_GET("stats.chunks.current", &chunks_current, size_t);
|
||||
if ((err = mallctl("swap.avail", &swap_avail, &ssz,
|
||||
NULL, 0)) == 0) {
|
||||
size_t lg_chunk;
|
||||
|
||||
malloc_cprintf(write4, w4opaque, "chunks: nchunks "
|
||||
"highchunks curchunks"
|
||||
#ifdef JEMALLOC_SWAP
|
||||
" swap_avail"
|
||||
#endif
|
||||
"\n");
|
||||
"highchunks curchunks swap_avail\n");
|
||||
CTL_GET("opt.lg_chunk", &lg_chunk, size_t);
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
" %13"PRIu64"%13zu%13zu"
|
||||
#ifdef JEMALLOC_SWAP
|
||||
"%13zu"
|
||||
#endif
|
||||
"\n",
|
||||
chunks_stats.nchunks, chunks_stats.highchunks,
|
||||
chunks_stats.curchunks
|
||||
#ifdef JEMALLOC_SWAP
|
||||
, swap_avail_chunks
|
||||
#endif
|
||||
);
|
||||
" %13"PRIu64"%13zu%13zu%13zu\n",
|
||||
chunks_total, chunks_high, chunks_current,
|
||||
swap_avail << lg_chunk);
|
||||
} else {
|
||||
malloc_cprintf(write4, w4opaque, "chunks: nchunks "
|
||||
"highchunks curchunks\n");
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
" %13"PRIu64"%13zu%13zu\n",
|
||||
chunks_total, chunks_high, chunks_current);
|
||||
}
|
||||
|
||||
/* Print chunk stats. */
|
||||
/* Print huge stats. */
|
||||
CTL_GET("stats.huge.nmalloc", &huge_nmalloc, uint64_t);
|
||||
CTL_GET("stats.huge.ndalloc", &huge_ndalloc, uint64_t);
|
||||
CTL_GET("stats.huge.allocated", &huge_allocated, size_t);
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"huge: nmalloc ndalloc allocated\n");
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
@@ -320,56 +587,58 @@ stats_print(void (*write4)(void *, const char *, const char *, const char *,
|
||||
huge_nmalloc, huge_ndalloc, huge_allocated);
|
||||
|
||||
if (merged) {
|
||||
unsigned nmerged;
|
||||
size_t nactive, ndirty;
|
||||
arena_stats_t astats;
|
||||
malloc_bin_stats_t bstats[nbins];
|
||||
malloc_large_stats_t lstats[((chunksize - PAGE_SIZE) >>
|
||||
PAGE_SHIFT)];
|
||||
unsigned narenas;
|
||||
size_t usz;
|
||||
|
||||
nactive = 0;
|
||||
ndirty = 0;
|
||||
memset(&astats, 0, sizeof(astats));
|
||||
memset(bstats, 0, sizeof(bstats));
|
||||
memset(lstats, 0, sizeof(lstats));
|
||||
usz = sizeof(unsigned);
|
||||
CTL_GET("arenas.narenas", &narenas, unsigned);
|
||||
{
|
||||
bool initialized[narenas];
|
||||
size_t isz;
|
||||
unsigned i, ninitialized;
|
||||
|
||||
/* Create merged arena stats. */
|
||||
for (i = nmerged = 0; i < narenas; i++) {
|
||||
arena = arenas[i];
|
||||
if (arena != NULL) {
|
||||
malloc_mutex_lock(&arena->lock);
|
||||
arena_stats_merge(arena, &nactive,
|
||||
&ndirty, &astats, bstats, lstats);
|
||||
malloc_mutex_unlock(&arena->lock);
|
||||
nmerged++;
|
||||
isz = sizeof(initialized);
|
||||
xmallctl("arenas.initialized", initialized,
|
||||
&isz, NULL, 0);
|
||||
for (i = ninitialized = 0; i < narenas; i++) {
|
||||
if (initialized[i])
|
||||
ninitialized++;
|
||||
}
|
||||
}
|
||||
|
||||
if (nmerged > 1) {
|
||||
/* Print merged arena stats. */
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"\nMerge arenas stats:\n");
|
||||
/*
|
||||
* arenas[0] is used only for invariant bin
|
||||
* settings.
|
||||
*/
|
||||
arena_stats_mprint(arenas[0], nactive, ndirty,
|
||||
&astats, bstats, lstats, bins, large,
|
||||
write4, w4opaque);
|
||||
if (ninitialized > 1) {
|
||||
/* Print merged arena stats. */
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"\nMerge arenas stats:\n");
|
||||
stats_arena_print(write4, w4opaque,
|
||||
narenas);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (unmerged) {
|
||||
unsigned narenas;
|
||||
size_t usz;
|
||||
|
||||
/* Print stats for each arena. */
|
||||
for (i = 0; i < narenas; i++) {
|
||||
arena = arenas[i];
|
||||
if (arena != NULL) {
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"\narenas[%u]:\n", i);
|
||||
malloc_mutex_lock(&arena->lock);
|
||||
arena_stats_print(arena, bins, large,
|
||||
write4, w4opaque);
|
||||
malloc_mutex_unlock(&arena->lock);
|
||||
|
||||
usz = sizeof(unsigned);
|
||||
CTL_GET("arenas.narenas", &narenas, unsigned);
|
||||
{
|
||||
bool initialized[narenas];
|
||||
size_t isz;
|
||||
unsigned i;
|
||||
|
||||
isz = sizeof(initialized);
|
||||
xmallctl("arenas.initialized", initialized,
|
||||
&isz, NULL, 0);
|
||||
|
||||
for (i = 0; i < narenas; i++) {
|
||||
if (initialized[i]) {
|
||||
malloc_cprintf(write4, w4opaque,
|
||||
"\narenas[%u]:\n", i);
|
||||
stats_arena_print(write4,
|
||||
w4opaque, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,11 +254,13 @@ trace_thread_cleanup(void *arg)
|
||||
trace_thread_exit();
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
trace_boot(void)
|
||||
{
|
||||
|
||||
malloc_mutex_init(&trace_mtx);
|
||||
if (malloc_mutex_init(&trace_mtx))
|
||||
return (true);
|
||||
|
||||
/* Flush trace buffers at exit. */
|
||||
atexit(malloc_trace_flush_all);
|
||||
/* Receive thread exit notifications. */
|
||||
@@ -267,6 +269,8 @@ trace_boot(void)
|
||||
": Error in pthread_key_create()\n", "", "");
|
||||
abort();
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
/******************************************************************************/
|
||||
#endif /* JEMALLOC_TRACE */
|
||||
|
||||
Reference in New Issue
Block a user