Bernd Helmle píše v út 08. 12. 2009 v 22:06 +0100:
> 
> --On 8. Dezember 2009 15:51:52 -0500 Greg Smith <g...@2ndquadrant.com> 
> wrote:
> 
> > Try this instead, which will give you a test where checkpoints have a
> > minimal impact, but lots of memory will be thrown around:
> >
> > pgbench -i -s 10 <db>
> > pgbench -S -c 10 -T 600 <db>
> 
> Thanks for the input, will try....
> 

I modified probes to reduce overhead. Prototype patch is attached. Main
point is to remove mcxt_alloc probe and keep only aset_alloc. I did also
some testing with interesting results. At first I prepare special C
store function (attached) which do only allocation and deallocation and
I measured how long it takes:

On 32bit the memory allocation is slow down 8.4%  and on 64bit it is
only 4.6%. Good to mention that I call palloc and pfree but in standard
behavior pfree is not much used and memory is freed when context is
destroyed. It means that we should think about 4.2% and 2.3% instead.

But in normal situation database does also other thing and palloc is
only one part of code path. It is why I run second test and use sun
studio profiling tools (collect/analyzer) to determine how much CPU
ticks cost the probes during pg_bench run. And results are much better.
AllocSet alloc function takes about 4-5% and probes assembler code takes
0.1-0.2% on 64bit. I did not test 32bit but my expectation is that it
should be about 0.3-0.4%.

        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	Wed Dec 09 14:41:34 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	Wed Dec 09 14:41:34 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;
 }
@@ -510,7 +516,8 @@
 		elog(ERROR, "invalid memory alloc request size %lu",
 			 (unsigned long) size);
 
-	return (*context->methods->alloc) (context, size);
+//	TRACE_POSTGRESQL_MCXT_ALLOC(context, size);
+	return ((*context->methods->alloc) (context, size));
 }
 
 /*
@@ -524,6 +531,7 @@
 MemoryContextAllocZero(MemoryContext context, Size size)
 {
 	void	   *ret;
+	StandardChunkHeader *header;
 
 	AssertArg(MemoryContextIsValid(context));
 
@@ -531,7 +539,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 +562,7 @@
 MemoryContextAllocZeroAligned(MemoryContext context, Size size)
 {
 	void	   *ret;
+	StandardChunkHeader *header;
 
 	AssertArg(MemoryContextIsValid(context));
 
@@ -558,6 +572,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 +607,8 @@
 
 	AssertArg(MemoryContextIsValid(header->context));
 
+//	TRACE_POSTGRESQL_MCXT_FREE(header->context, pointer);
+
 	(*header->context->methods->free_p) (header->context, pointer);
 }
 
@@ -620,6 +641,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	Wed Dec 09 14:41:34 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(void *, size_t);
+	probe mcxt__free(void *, void *); */
+	probe mcxt__reset(char *, void *);
+	probe mcxt__realloc(char *, void *, size_t, 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);
 };
#include "postgres.h"

#include "funcapi.h"
#include "utils/builtins.h"

PG_MODULE_MAGIC;

extern Datum pgmemtest(PG_FUNCTION_ARGS);

PG_FUNCTION_INFO_V1(pgmemtest);


Datum
pgmemtest(PG_FUNCTION_ARGS)
{
	int result;
	struct timeval start_tp, stop_tp;
	int n;
	void *x;

	gettimeofday(&start_tp, NULL);

	for( n = 0 ; n < 10000000; n++) {
		x = palloc(373);
		pfree(x);
	}
	
	gettimeofday(&stop_tp, NULL);

	result = (stop_tp.tv_sec - start_tp.tv_sec) * 1000000;
	result += (stop_tp.tv_usec - start_tp.tv_usec);

	PG_RETURN_INT32(result);
}

-- 
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