static void AllocSetDelete(MemoryContext context);
static Size AllocSetGetChunkSpace(MemoryContext context, void *pointer);
static bool AllocSetIsEmpty(MemoryContext context);
-static void AllocSetStats(MemoryContext context, int level);
+static void AllocSetStats(MemoryContext context, int level, bool print,
+ MemoryContextCounters *totals);
#ifdef MEMORY_CONTEXT_CHECKING
static void AllocSetCheck(MemoryContext context);
/*
* AllocSetStats
- * Displays stats about memory consumption of an allocset.
+ * Compute stats about memory consumption of an allocset.
+ *
+ * level: recursion level (0 at top level); used for print indentation.
+ * print: true to print stats to stderr.
+ * totals: if not NULL, add stats about this allocset into *totals.
*/
static void
-AllocSetStats(MemoryContext context, int level)
+AllocSetStats(MemoryContext context, int level, bool print,
+ MemoryContextCounters *totals)
{
AllocSet set = (AllocSet) context;
Size nblocks = 0;
- Size nchunks = 0;
+ Size freechunks = 0;
Size totalspace = 0;
Size freespace = 0;
AllocBlock block;
- AllocChunk chunk;
int fidx;
- int i;
for (block = set->blocks; block != NULL; block = block->next)
{
}
for (fidx = 0; fidx < ALLOCSET_NUM_FREELISTS; fidx++)
{
+ AllocChunk chunk;
+
for (chunk = set->freelist[fidx]; chunk != NULL;
chunk = (AllocChunk) chunk->aset)
{
- nchunks++;
+ freechunks++;
freespace += chunk->size + ALLOC_CHUNKHDRSZ;
}
}
- for (i = 0; i < level; i++)
- fprintf(stderr, " ");
+ if (print)
+ {
+ int i;
- fprintf(stderr,
+ for (i = 0; i < level; i++)
+ fprintf(stderr, " ");
+ fprintf(stderr,
"%s: %zu total in %zd blocks; %zu free (%zd chunks); %zu used\n",
- set->header.name, totalspace, nblocks, freespace, nchunks,
- totalspace - freespace);
+ set->header.name, totalspace, nblocks, freespace, freechunks,
+ totalspace - freespace);
+ }
+
+ if (totals)
+ {
+ totals->nblocks += nblocks;
+ totals->freechunks += freechunks;
+ totals->totalspace += totalspace;
+ totals->freespace += freespace;
+ }
}
MemoryContext PortalContext = NULL;
static void MemoryContextCallResetCallbacks(MemoryContext context);
-static void MemoryContextStatsInternal(MemoryContext context, int level);
+static void MemoryContextStatsInternal(MemoryContext context, int level,
+ bool print, int max_children,
+ MemoryContextCounters *totals);
/*
* You should not do memory allocations within a critical section, because
* MemoryContextStats
* Print statistics about the named context and all its descendants.
*
- * This is just a debugging utility, so it's not fancy. The statistics
- * are merely sent to stderr.
+ * This is just a debugging utility, so it's not very fancy. However, we do
+ * make some effort to summarize when the output would otherwise be very long.
+ * The statistics are sent to stderr.
*/
void
MemoryContextStats(MemoryContext context)
{
- MemoryContextStatsInternal(context, 0);
+ /* A hard-wired limit on the number of children is usually good enough */
+ MemoryContextStatsDetail(context, 100);
}
+/*
+ * MemoryContextStatsDetail
+ *
+ * Entry point for use if you want to vary the number of child contexts shown.
+ */
+void
+MemoryContextStatsDetail(MemoryContext context, int max_children)
+{
+ MemoryContextCounters grand_totals;
+
+ memset(&grand_totals, 0, sizeof(grand_totals));
+
+ MemoryContextStatsInternal(context, 0, true, max_children, &grand_totals);
+
+ fprintf(stderr,
+ "Grand total: %zu bytes in %zd blocks; %zu free (%zd chunks); %zu used\n",
+ grand_totals.totalspace, grand_totals.nblocks,
+ grand_totals.freespace, grand_totals.freechunks,
+ grand_totals.totalspace - grand_totals.freespace);
+}
+
+/*
+ * MemoryContextStatsInternal
+ * One recursion level for MemoryContextStats
+ *
+ * Print this context if print is true, but in any case accumulate counts into
+ * *totals (if given).
+ */
static void
-MemoryContextStatsInternal(MemoryContext context, int level)
+MemoryContextStatsInternal(MemoryContext context, int level,
+ bool print, int max_children,
+ MemoryContextCounters *totals)
{
+ MemoryContextCounters local_totals;
MemoryContext child;
+ int ichild;
AssertArg(MemoryContextIsValid(context));
- (*context->methods->stats) (context, level);
- for (child = context->firstchild; child != NULL; child = child->nextchild)
- MemoryContextStatsInternal(child, level + 1);
+ /* Examine the context itself */
+ (*context->methods->stats) (context, level, print, totals);
+
+ /*
+ * Examine children. If there are more than max_children of them, we do
+ * not print the rest explicitly, but just summarize them.
+ */
+ memset(&local_totals, 0, sizeof(local_totals));
+
+ for (child = context->firstchild, ichild = 0;
+ child != NULL;
+ child = child->nextchild, ichild++)
+ {
+ if (ichild < max_children)
+ MemoryContextStatsInternal(child, level + 1,
+ print, max_children,
+ totals);
+ else
+ MemoryContextStatsInternal(child, level + 1,
+ false, max_children,
+ &local_totals);
+ }
+
+ /* Deal with excess children */
+ if (ichild > max_children)
+ {
+ if (print)
+ {
+ int i;
+
+ for (i = 0; i <= level; i++)
+ fprintf(stderr, " ");
+ fprintf(stderr,
+ "%d more child contexts containing %zu total in %zd blocks; %zu free (%zd chunks); %zu used\n",
+ ichild - max_children,
+ local_totals.totalspace,
+ local_totals.nblocks,
+ local_totals.freespace,
+ local_totals.freechunks,
+ local_totals.totalspace - local_totals.freespace);
+ }
+
+ if (totals)
+ {
+ totals->nblocks += local_totals.nblocks;
+ totals->freechunks += local_totals.freechunks;
+ totals->totalspace += local_totals.totalspace;
+ totals->freespace += local_totals.freespace;
+ }
+ }
}
/*
#include "nodes/nodes.h"
+/*
+ * MemoryContextCounters
+ * Summarization state for MemoryContextStats collection.
+ *
+ * The set of counters in this struct is biased towards AllocSet; if we ever
+ * add any context types that are based on fundamentally different approaches,
+ * we might need more or different counters here. A possible API spec then
+ * would be to print only nonzero counters, but for now we just summarize in
+ * the format historically used by AllocSet.
+ */
+typedef struct MemoryContextCounters
+{
+ Size nblocks; /* Total number of malloc blocks */
+ Size freechunks; /* Total number of free chunks */
+ Size totalspace; /* Total bytes requested from malloc */
+ Size freespace; /* The unused portion of totalspace */
+} MemoryContextCounters;
+
/*
* MemoryContext
* A logical context in which memory allocations occur.
void (*delete_context) (MemoryContext context);
Size (*get_chunk_space) (MemoryContext context, void *pointer);
bool (*is_empty) (MemoryContext context);
- void (*stats) (MemoryContext context, int level);
+ void (*stats) (MemoryContext context, int level, bool print,
+ MemoryContextCounters *totals);
#ifdef MEMORY_CONTEXT_CHECKING
void (*check) (MemoryContext context);
#endif