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