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

Reply via email to