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:
Jason Evans
2010-01-27 13:10:55 -08:00
parent fbbb624fc1
commit 3c2343518c
17 changed files with 2654 additions and 470 deletions
+2 -8
View File
@@ -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);
+2
View File
@@ -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
+108
View File
@@ -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"
+1 -1
View File
@@ -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
View File
@@ -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.
*/
+6 -7
View File
@@ -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
};
+2 -196
View File
@@ -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
+9 -2
View File
@@ -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
+1 -1
View File
@@ -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);
+16 -4
View File
@@ -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
View File
@@ -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", &reg_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);
}
}
}
}
+6 -2
View File
@@ -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 */