Attached patch contains new dtrace probes for memory management. Main purpose is to analyze memory footprint - for example how many memory needs transaction, peak memory per context, when memory block is reused or when it is allocate by malloc and so on.
There are three groups of probes: 1) general memory context operation: mcxt-alloc mcxt-create mcxt-delete mcxt-free mcxt-realloc mcxt-reset 2) AllocSet operations (called from mcxt) aset-alloc aset-delete aset-free aset-realloc aset-reset 3) AllocSet Block operations. aset-block-free aset-block-new aset-block-realloc aset-block-reset Zdenek
diff -r 68b8827f4738 src/backend/utils/mmgr/aset.c --- a/src/backend/utils/mmgr/aset.c Fri Nov 13 11:17:04 2009 +0000 +++ b/src/backend/utils/mmgr/aset.c Fri Nov 13 21:24:56 2009 +0100 @@ -64,6 +64,7 @@ #include "postgres.h" +#include "pg_trace.h" #include "utils/memutils.h" /* Define this to detail debug alloc information */ @@ -463,6 +464,8 @@ AssertArg(AllocSetIsValid(set)); + TRACE_POSTGRESQL_ASET_RESET(context); + /* Nothing to do if no pallocs since startup or last reset */ if (set->isReset) return; @@ -495,6 +498,8 @@ #endif block->freeptr = datastart; block->next = NULL; + TRACE_POSTGRESQL_ASET_BLOCK_RESET(context, block, + block->endptr - ((char *) block)); } else { @@ -503,6 +508,8 @@ /* Wipe freed memory for debugging purposes */ memset(block, 0x7F, block->freeptr - ((char *) block)); #endif + TRACE_POSTGRESQL_ASET_BLOCK_FREE(context, block, + block->endptr - ((char *) block)); free(block); } block = next; @@ -529,6 +536,7 @@ AllocBlock block = set->blocks; AssertArg(AllocSetIsValid(set)); + TRACE_POSTGRESQL_ASET_DELETE(context); #ifdef MEMORY_CONTEXT_CHECKING /* Check for corruption and leaks before freeing */ @@ -548,6 +556,8 @@ /* Wipe freed memory for debugging purposes */ memset(block, 0x7F, block->freeptr - ((char *) block)); #endif + TRACE_POSTGRESQL_ASET_BLOCK_FREE(context, block, + block->endptr - ((char *) block)); free(block); block = next; } @@ -570,6 +580,7 @@ AssertArg(AllocSetIsValid(set)); + TRACE_POSTGRESQL_ASET_ALLOC(context, size); /* * If requested size exceeds maximum for chunks, allocate an entire block * for this request. @@ -623,6 +634,7 @@ set->isReset = false; AllocAllocInfo(set, chunk); + TRACE_POSTGRESQL_ASET_BLOCK_NEW(context, block, blksize); return AllocChunkGetPointer(chunk); } @@ -771,6 +783,7 @@ errdetail("Failed on request of size %lu.", (unsigned long) size))); } + TRACE_POSTGRESQL_ASET_BLOCK_NEW(context, block, blksize); block->aset = set; block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ; @@ -830,6 +843,7 @@ AllocChunk chunk = AllocPointerGetChunk(pointer); AllocFreeInfo(set, chunk); + TRACE_POSTGRESQL_ASET_FREE(context, pointer); #ifdef MEMORY_CONTEXT_CHECKING /* Test for someone scribbling on unused space in chunk */ @@ -866,6 +880,9 @@ set->blocks = block->next; else prevblock->next = block->next; + + TRACE_POSTGRESQL_ASET_BLOCK_FREE(context, block, + block->endptr - ((char *) block)); #ifdef CLOBBER_FREED_MEMORY /* Wipe freed memory for debugging purposes */ memset(block, 0x7F, block->freeptr - ((char *) block)); @@ -905,6 +922,8 @@ AllocChunk chunk = AllocPointerGetChunk(pointer); Size oldsize = chunk->size; + TRACE_POSTGRESQL_ASET_REALLOC(context, pointer, size, oldsize); + #ifdef MEMORY_CONTEXT_CHECKING /* Test for someone scribbling on unused space in chunk */ if (chunk->requested_size < oldsize) @@ -948,6 +967,7 @@ */ AllocBlock block = set->blocks; AllocBlock prevblock = NULL; + AllocBlock newblock; Size chksize; Size blksize; @@ -967,7 +987,11 @@ /* Do the realloc */ chksize = MAXALIGN(size); blksize = chksize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ; - block = (AllocBlock) realloc(block, blksize); + newblock = (AllocBlock) realloc(block, blksize); + + TRACE_POSTGRESQL_ASET_BLOCK_REALLOC(context, block, newblock, blksize); + block = newblock; + if (block == NULL) { MemoryContextStats(TopMemoryContext); diff -r 68b8827f4738 src/backend/utils/mmgr/mcxt.c --- a/src/backend/utils/mmgr/mcxt.c Fri Nov 13 11:17:04 2009 +0000 +++ b/src/backend/utils/mmgr/mcxt.c Fri Nov 13 21:24:56 2009 +0100 @@ -22,7 +22,7 @@ #include "postgres.h" #include "utils/memutils.h" - +#include "pg_trace.h" /***************************************************************************** * GLOBAL MEMORY * @@ -123,6 +123,8 @@ { AssertArg(MemoryContextIsValid(context)); + TRACE_POSTGRESQL_MCXT_RESET(context->name, context); + /* save a function call in common case where there are no children */ if (context->firstchild != NULL) MemoryContextResetChildren(context); @@ -168,6 +170,8 @@ MemoryContextDeleteChildren(context); + TRACE_POSTGRESQL_MCXT_DELETE(context->name, context, context->parent); + /* * We delink the context from its parent before deleting it, so that if * there's an error we won't have deleted/busted contexts still attached @@ -490,6 +494,8 @@ parent->firstchild = node; } + TRACE_POSTGRESQL_MCXT_CREATE(node->name, node, parent); + /* Return to type-specific creation routine to finish up */ return node; } @@ -504,13 +510,24 @@ void * MemoryContextAlloc(MemoryContext context, Size size) { + void *ret; + StandardChunkHeader *header; + AssertArg(MemoryContextIsValid(context)); if (!AllocSizeIsValid(size)) elog(ERROR, "invalid memory alloc request size %lu", (unsigned long) size); + + ret = (*context->methods->alloc) (context, size); + header = (StandardChunkHeader *) + ((char *) ret - STANDARDCHUNKHEADERSIZE); - return (*context->methods->alloc) (context, size); + Assert(header->context == context); + Assert(header->size >= size); + TRACE_POSTGRESQL_MCXT_ALLOC(context->name, context, size, header->size, false); + + return ret; } /* @@ -524,6 +541,7 @@ MemoryContextAllocZero(MemoryContext context, Size size) { void *ret; + StandardChunkHeader *header; AssertArg(MemoryContextIsValid(context)); @@ -531,7 +549,12 @@ elog(ERROR, "invalid memory alloc request size %lu", (unsigned long) size); + ret = (*context->methods->alloc) (context, size); + header = (StandardChunkHeader *) + ((char *) ret - STANDARDCHUNKHEADERSIZE); + + TRACE_POSTGRESQL_MCXT_ALLOC(context->name, context, size, header->size, true); MemSetAligned(ret, 0, size); @@ -549,6 +572,7 @@ MemoryContextAllocZeroAligned(MemoryContext context, Size size) { void *ret; + StandardChunkHeader *header; AssertArg(MemoryContextIsValid(context)); @@ -558,6 +582,11 @@ ret = (*context->methods->alloc) (context, size); + header = (StandardChunkHeader *) + ((char *) ret - STANDARDCHUNKHEADERSIZE); + + TRACE_POSTGRESQL_MCXT_ALLOC(context->name, context, size, header->size, true); + MemSetLoop(ret, 0, size); return ret; @@ -588,6 +617,8 @@ AssertArg(MemoryContextIsValid(header->context)); + TRACE_POSTGRESQL_MCXT_FREE(header->context->name, header->context, header->size); + (*header->context->methods->free_p) (header->context, pointer); } @@ -620,6 +651,8 @@ elog(ERROR, "invalid memory alloc request size %lu", (unsigned long) size); + TRACE_POSTGRESQL_MCXT_REALLOC(header->context->name, header->context, header->size, size); + return (*header->context->methods->realloc) (header->context, pointer, size); } diff -r 68b8827f4738 src/backend/utils/probes.d --- a/src/backend/utils/probes.d Fri Nov 13 11:17:04 2009 +0000 +++ b/src/backend/utils/probes.d Fri Nov 13 21:24:56 2009 +0100 @@ -90,4 +90,21 @@ probe xlog__switch(); probe wal__buffer__write__dirty__start(); probe wal__buffer__write__dirty__done(); + + probe mcxt__create(char *, void *, void *); + probe mcxt__delete(char *, void *, void *); + probe mcxt__alloc(char *, void *, size_t, size_t, bool); + probe mcxt__reset(char *, void *); + probe mcxt__realloc(char *, void *, size_t, size_t); + probe mcxt__free(char *, void *, size_t); + + probe aset__delete(void *); + probe aset__reset(void *); + probe aset__alloc(void *, size_t); + probe aset__realloc(void *, void *, size_t, size_t); + probe aset__free(void *, void *); + probe aset__block__reset(void *, void *, size_t); + probe aset__block__free(void *, void *, size_t); + probe aset__block__new(void *, void *, size_t); + probe aset__block__realloc(void *, void *, void *, size_t); };
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers