Bernd Helmle píše v út 08. 12. 2009 v 22:06 +0100:
>
> --On 8. Dezember 2009 15:51:52 -0500 Greg Smith <[email protected]>
> 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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers