2010-01-17 01:53:50 +08:00
|
|
|
#define JEMALLOC_STATS_C_
|
2010-01-17 17:49:20 +08:00
|
|
|
#include "internal/jemalloc_internal.h"
|
2010-01-17 01:53:50 +08:00
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
/* Data. */
|
|
|
|
|
|
|
|
bool opt_stats_print = false;
|
|
|
|
|
2010-01-18 07:49:25 +08:00
|
|
|
/******************************************************************************/
|
|
|
|
/* Function prototypes for non-inline static functions. */
|
|
|
|
|
|
|
|
static void
|
2010-01-20 04:11:25 +08:00
|
|
|
malloc_vcprintf(void (*write4)(void *, const char *, const char *, const char *,
|
|
|
|
const char *), void *w4opaque, const char *format, va_list ap);
|
2010-01-18 07:49:25 +08:00
|
|
|
|
2010-01-17 01:53:50 +08:00
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We don't want to depend on vsnprintf() for production builds, since that can
|
|
|
|
* cause unnecessary bloat for static binaries. umax2s() provides minimal
|
|
|
|
* integer printing functionality, so that malloc_printf() use can be limited to
|
|
|
|
* JEMALLOC_STATS code.
|
|
|
|
*/
|
|
|
|
char *
|
|
|
|
umax2s(uintmax_t x, unsigned base, char *s)
|
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
i = UMAX2S_BUFSIZE - 1;
|
|
|
|
s[i] = '\0';
|
|
|
|
switch (base) {
|
|
|
|
case 10:
|
|
|
|
do {
|
|
|
|
i--;
|
|
|
|
s[i] = "0123456789"[x % 10];
|
|
|
|
x /= 10;
|
|
|
|
} while (x > 0);
|
|
|
|
break;
|
|
|
|
case 16:
|
|
|
|
do {
|
|
|
|
i--;
|
|
|
|
s[i] = "0123456789abcdef"[x & 0xf];
|
|
|
|
x >>= 4;
|
|
|
|
} while (x > 0);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
do {
|
|
|
|
i--;
|
|
|
|
s[i] = "0123456789abcdefghijklmnopqrstuvwxyz"[x % base];
|
|
|
|
x /= base;
|
|
|
|
} while (x > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (&s[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef JEMALLOC_STATS
|
2010-01-18 07:49:25 +08:00
|
|
|
static void
|
2010-01-20 04:11:25 +08:00
|
|
|
malloc_vcprintf(void (*write4)(void *, const char *, const char *, const char *,
|
|
|
|
const char *), void *w4opaque, const char *format, va_list ap)
|
2010-01-18 07:49:25 +08:00
|
|
|
{
|
|
|
|
char buf[4096];
|
|
|
|
|
|
|
|
if (write4 == NULL) {
|
|
|
|
/*
|
|
|
|
* The caller did not provide an alternate write4 callback
|
|
|
|
* function, so use the default one. malloc_write4() is an
|
|
|
|
* inline function, so use malloc_message() directly here.
|
|
|
|
*/
|
|
|
|
write4 = JEMALLOC_P(malloc_message);
|
2010-01-20 04:11:25 +08:00
|
|
|
w4opaque = NULL;
|
2010-01-18 07:49:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
vsnprintf(buf, sizeof(buf), format, ap);
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, buf, "", "", "");
|
2010-01-18 07:49:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Print to a callback function in such a way as to (hopefully) avoid memory
|
|
|
|
* allocation.
|
|
|
|
*/
|
2010-01-20 04:11:25 +08:00
|
|
|
JEMALLOC_ATTR(format(printf, 3, 4))
|
2010-01-18 07:49:25 +08:00
|
|
|
void
|
2010-01-20 04:11:25 +08:00
|
|
|
malloc_cprintf(void (*write4)(void *, const char *, const char *, const char *,
|
|
|
|
const char *), void *w4opaque, const char *format, ...)
|
2010-01-18 07:49:25 +08:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start(ap, format);
|
2010-01-20 04:11:25 +08:00
|
|
|
malloc_vcprintf(write4, w4opaque, format, ap);
|
2010-01-18 07:49:25 +08:00
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
2010-01-17 01:53:50 +08:00
|
|
|
/*
|
|
|
|
* Print to stderr in such a way as to (hopefully) avoid memory allocation.
|
|
|
|
*/
|
2010-01-18 07:49:25 +08:00
|
|
|
JEMALLOC_ATTR(format(printf, 1, 2))
|
2010-01-17 01:53:50 +08:00
|
|
|
void
|
|
|
|
malloc_printf(const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
va_start(ap, format);
|
2010-01-20 04:11:25 +08:00
|
|
|
malloc_vcprintf(NULL, NULL, format, ap);
|
2010-01-17 01:53:50 +08:00
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void
|
2010-01-24 18:53:40 +08:00
|
|
|
stats_print(void (*write4)(void *, const char *, const char *, const char *,
|
|
|
|
const char *), void *w4opaque, const char *opts)
|
2010-01-17 01:53:50 +08:00
|
|
|
{
|
|
|
|
char s[UMAX2S_BUFSIZE];
|
|
|
|
bool general = true;
|
2010-01-18 09:35:19 +08:00
|
|
|
bool merged = true;
|
|
|
|
bool unmerged = true;
|
2010-01-17 01:53:50 +08:00
|
|
|
bool bins = true;
|
|
|
|
bool large = true;
|
|
|
|
|
2010-01-18 07:49:25 +08:00
|
|
|
if (write4 == NULL) {
|
|
|
|
/*
|
|
|
|
* The caller did not provide an alternate write4 callback
|
|
|
|
* function, so use the default one. malloc_write4() is an
|
|
|
|
* inline function, so use malloc_message() directly here.
|
|
|
|
*/
|
|
|
|
write4 = JEMALLOC_P(malloc_message);
|
2010-01-20 04:11:25 +08:00
|
|
|
w4opaque = NULL;
|
2010-01-18 07:49:25 +08:00
|
|
|
}
|
|
|
|
|
2010-01-17 01:53:50 +08:00
|
|
|
if (opts != NULL) {
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
for (i = 0; opts[i] != '\0'; i++) {
|
|
|
|
switch (opts[i]) {
|
|
|
|
case 'g':
|
|
|
|
general = false;
|
|
|
|
break;
|
2010-01-18 09:35:19 +08:00
|
|
|
case 'm':
|
|
|
|
merged = false;
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
unmerged = false;
|
|
|
|
break;
|
2010-01-17 01:53:50 +08:00
|
|
|
case 'b':
|
|
|
|
bins = false;
|
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
large = false;
|
|
|
|
break;
|
|
|
|
default:;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, "___ Begin jemalloc statistics ___\n", "", "", "");
|
2010-01-17 01:53:50 +08:00
|
|
|
if (general) {
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, "Assertions ",
|
2010-01-17 01:53:50 +08:00
|
|
|
#ifdef NDEBUG
|
|
|
|
"disabled",
|
|
|
|
#else
|
|
|
|
"enabled",
|
|
|
|
#endif
|
|
|
|
"\n", "");
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, "Boolean JEMALLOC_OPTIONS: ",
|
|
|
|
opt_abort ? "A" : "a", "", "");
|
2010-01-17 01:53:50 +08:00
|
|
|
#ifdef JEMALLOC_FILL
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, opt_junk ? "J" : "j", "", "", "");
|
2010-01-24 18:53:40 +08:00
|
|
|
#endif
|
|
|
|
#ifdef JEMALLOC_SWAP
|
|
|
|
write4(w4opaque, opt_overcommit ? "O" : "o", "", "", "");
|
2010-01-17 01:53:50 +08:00
|
|
|
#endif
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, "P", "", "", "");
|
2010-01-17 01:53:50 +08:00
|
|
|
#ifdef JEMALLOC_TCACHE
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, opt_tcache_sort ? "S" : "s", "", "", "");
|
2010-01-17 01:53:50 +08:00
|
|
|
#endif
|
|
|
|
#ifdef JEMALLOC_TRACE
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, opt_trace ? "T" : "t", "", "", "");
|
2010-01-17 01:53:50 +08:00
|
|
|
#endif
|
|
|
|
#ifdef JEMALLOC_SYSV
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, opt_sysv ? "V" : "v", "", "", "");
|
2010-01-17 01:53:50 +08:00
|
|
|
#endif
|
|
|
|
#ifdef JEMALLOC_XMALLOC
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, opt_xmalloc ? "X" : "x", "", "", "");
|
2010-01-17 01:53:50 +08:00
|
|
|
#endif
|
|
|
|
#ifdef JEMALLOC_FILL
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, opt_zero ? "Z" : "z", "", "", "");
|
2010-01-17 01:53:50 +08:00
|
|
|
#endif
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, "\n", "", "", "");
|
2010-01-17 01:53:50 +08:00
|
|
|
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, "CPUs: ", umax2s(ncpus, 10, s), "\n", "");
|
|
|
|
write4(w4opaque, "Max arenas: ", umax2s(narenas, 10, s), "\n",
|
|
|
|
"");
|
|
|
|
write4(w4opaque, "Pointer size: ", umax2s(sizeof(void *), 10,
|
|
|
|
s), "\n", "");
|
|
|
|
write4(w4opaque, "Quantum size: ", umax2s(QUANTUM, 10, s), "\n",
|
2010-01-17 01:53:50 +08:00
|
|
|
"");
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, "Cacheline size (assumed): ", umax2s(CACHELINE,
|
|
|
|
10, s),
|
2010-01-18 07:49:25 +08:00
|
|
|
"\n", "");
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, "Subpage spacing: ", umax2s(SUBPAGE, 10, s),
|
2010-01-17 01:53:50 +08:00
|
|
|
"\n", "");
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, "Medium spacing: ", umax2s((1U << lg_mspace),
|
|
|
|
10, s), "\n", "");
|
2010-01-17 01:53:50 +08:00
|
|
|
#ifdef JEMALLOC_TINY
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, "Tiny 2^n-spaced sizes: [", umax2s((1U <<
|
|
|
|
LG_TINY_MIN), 10, s), "..", "");
|
|
|
|
write4(w4opaque, umax2s((qspace_min >> 1), 10, s), "]\n", "",
|
|
|
|
"");
|
2010-01-17 01:53:50 +08:00
|
|
|
#endif
|
2010-01-20 04:11:25 +08:00
|
|
|
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),
|
2010-01-18 07:49:25 +08:00
|
|
|
"..", "");
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, umax2s(medium_max, 10, s), "]\n", "", "");
|
2010-01-17 01:53:50 +08:00
|
|
|
if (opt_lg_dirty_mult >= 0) {
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque,
|
|
|
|
"Min active:dirty page ratio per arena: ",
|
2010-01-17 01:53:50 +08:00
|
|
|
umax2s((1U << opt_lg_dirty_mult), 10, s), ":1\n",
|
|
|
|
"");
|
|
|
|
} else {
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque,
|
|
|
|
"Min active:dirty page ratio per arena: N/A\n", "",
|
|
|
|
"", "");
|
2010-01-17 01:53:50 +08:00
|
|
|
}
|
|
|
|
#ifdef JEMALLOC_TCACHE
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, "Thread cache slots per size class: ",
|
2010-01-18 07:49:25 +08:00
|
|
|
tcache_nslots ? umax2s(tcache_nslots, 10, s) : "N/A", "\n",
|
|
|
|
"");
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, "Thread cache GC sweep interval: ",
|
2010-01-17 01:53:50 +08:00
|
|
|
(tcache_nslots && tcache_gc_incr > 0) ?
|
|
|
|
umax2s((1U << opt_lg_tcache_gc_sweep), 10, s) : "N/A",
|
|
|
|
"", "");
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, " (increment interval: ",
|
2010-01-17 01:53:50 +08:00
|
|
|
(tcache_nslots && tcache_gc_incr > 0) ?
|
|
|
|
umax2s(tcache_gc_incr, 10, s) : "N/A",
|
|
|
|
")\n", "");
|
|
|
|
#endif
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, "Chunk size: ", umax2s(chunksize, 10, s), "",
|
|
|
|
"");
|
|
|
|
write4(w4opaque, " (2^", umax2s(opt_lg_chunk, 10, s), ")\n",
|
|
|
|
"");
|
2010-01-17 01:53:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef JEMALLOC_STATS
|
|
|
|
{
|
|
|
|
size_t allocated, mapped;
|
|
|
|
unsigned i;
|
|
|
|
arena_t *arena;
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
2010-01-20 04:11:25 +08:00
|
|
|
malloc_cprintf(write4, w4opaque,
|
|
|
|
"Allocated: %zu, mapped: %zu\n", allocated, mapped);
|
2010-01-17 01:53:50 +08:00
|
|
|
|
|
|
|
/* Print chunk stats. */
|
|
|
|
{
|
|
|
|
chunk_stats_t chunks_stats;
|
2010-01-25 08:41:01 +08:00
|
|
|
#ifdef JEMALLOC_SWAP
|
|
|
|
size_t swap_avail_chunks;
|
|
|
|
#endif
|
2010-01-17 01:53:50 +08:00
|
|
|
|
|
|
|
malloc_mutex_lock(&huge_mtx);
|
|
|
|
chunks_stats = stats_chunks;
|
|
|
|
malloc_mutex_unlock(&huge_mtx);
|
|
|
|
|
2010-01-25 08:41:01 +08:00
|
|
|
#ifdef JEMALLOC_SWAP
|
|
|
|
malloc_mutex_lock(&swap_mtx);
|
|
|
|
swap_avail_chunks = swap_avail >> opt_lg_chunk;
|
|
|
|
malloc_mutex_unlock(&swap_mtx);
|
|
|
|
#endif
|
|
|
|
|
2010-01-20 04:11:25 +08:00
|
|
|
malloc_cprintf(write4, w4opaque, "chunks: nchunks "
|
2010-01-24 18:53:40 +08:00
|
|
|
"highchunks curchunks"
|
|
|
|
#ifdef JEMALLOC_SWAP
|
|
|
|
" swap_avail"
|
|
|
|
#endif
|
|
|
|
"\n");
|
2010-01-25 08:41:01 +08:00
|
|
|
malloc_cprintf(write4, w4opaque,
|
|
|
|
" %13"PRIu64"%13zu%13zu"
|
2010-01-24 18:53:40 +08:00
|
|
|
#ifdef JEMALLOC_SWAP
|
|
|
|
"%13zu"
|
|
|
|
#endif
|
|
|
|
"\n",
|
2010-01-17 01:53:50 +08:00
|
|
|
chunks_stats.nchunks, chunks_stats.highchunks,
|
2010-01-24 18:53:40 +08:00
|
|
|
chunks_stats.curchunks
|
|
|
|
#ifdef JEMALLOC_SWAP
|
2010-01-25 08:41:01 +08:00
|
|
|
, swap_avail_chunks
|
2010-01-24 18:53:40 +08:00
|
|
|
#endif
|
|
|
|
);
|
2010-01-17 01:53:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Print chunk stats. */
|
2010-01-20 04:11:25 +08:00
|
|
|
malloc_cprintf(write4, w4opaque,
|
2010-01-17 01:53:50 +08:00
|
|
|
"huge: nmalloc ndalloc allocated\n");
|
2010-01-25 08:41:01 +08:00
|
|
|
malloc_cprintf(write4, w4opaque,
|
|
|
|
" %12"PRIu64" %12"PRIu64" %12zu\n",
|
2010-01-20 04:11:25 +08:00
|
|
|
huge_nmalloc, huge_ndalloc, huge_allocated);
|
2010-01-17 01:53:50 +08:00
|
|
|
|
2010-01-18 09:35:19 +08:00
|
|
|
if (merged) {
|
2010-01-25 09:21:47 +08:00
|
|
|
unsigned nmerged;
|
2010-01-18 09:35:19 +08:00
|
|
|
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));
|
|
|
|
|
|
|
|
/* Create merged arena stats. */
|
2010-01-25 09:21:47 +08:00
|
|
|
for (i = nmerged = 0; i < narenas; i++) {
|
2010-01-18 09:35:19 +08:00
|
|
|
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);
|
2010-01-25 09:21:47 +08:00
|
|
|
nmerged++;
|
2010-01-18 09:35:19 +08:00
|
|
|
}
|
|
|
|
}
|
2010-01-25 09:21:47 +08:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
2010-01-18 09:35:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (unmerged) {
|
|
|
|
/* Print stats for each arena. */
|
|
|
|
for (i = 0; i < narenas; i++) {
|
|
|
|
arena = arenas[i];
|
|
|
|
if (arena != NULL) {
|
2010-01-20 04:11:25 +08:00
|
|
|
malloc_cprintf(write4, w4opaque,
|
2010-01-18 09:35:19 +08:00
|
|
|
"\narenas[%u]:\n", i);
|
|
|
|
malloc_mutex_lock(&arena->lock);
|
|
|
|
arena_stats_print(arena, bins, large,
|
2010-01-20 04:11:25 +08:00
|
|
|
write4, w4opaque);
|
2010-01-18 09:35:19 +08:00
|
|
|
malloc_mutex_unlock(&arena->lock);
|
|
|
|
}
|
2010-01-17 01:53:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* #ifdef JEMALLOC_STATS */
|
2010-01-20 04:11:25 +08:00
|
|
|
write4(w4opaque, "--- End jemalloc statistics ---\n", "", "", "");
|
2010-01-17 01:53:50 +08:00
|
|
|
}
|