On Thu, 2015-07-09 at 14:41 +1200, David Rowley wrote:
> Are you going to implement this? or are you happy with the single
> level context tracking is the right thing?
> I'm going to mark the patch as waiting on author for now.
Attached a version of the patch that does multi-level tracking, v12. It
does this is a simpler way, just like an earlier version of the patch:
it simply traverses up the chain and adds to each parent in a
"total_allocated" field.
The idea you mentioned is a possible optimization of this idea, but it
only makes sense if I'm able to detect a difference between v11
(single-level) and v12 (multi-level). I tried Robert's test[1] again and
I didn't see a difference on my workstation (technically, v12 came out
the fastest, which means I'm just seeing noise anyway), so I can't
evaluate whether your idea will improve things.
After talking with a few people at PGCon, small noisy differences in CPU
timings can appear for almost any tweak to the code, and aren't
necessarily cause for major concern.
Regards,
Jeff Davis
[1] pgbench -i -s 300, then do the following 3 times each for master,
v11, and v12, and take the median of logged traces:
start server; set trace_sort=on; reindex index pgbench_accounts_pkey;
stop server
*** a/src/backend/utils/mmgr/aset.c
--- b/src/backend/utils/mmgr/aset.c
***************
*** 242,247 **** typedef struct AllocChunkData
--- 242,249 ----
#define AllocChunkGetPointer(chk) \
((AllocPointer)(((char *)(chk)) + ALLOC_CHUNKHDRSZ))
+ static void update_alloc(MemoryContext context, int64 size);
+
/*
* These functions implement the MemoryContext API for AllocSet contexts.
*/
***************
*** 500,505 **** AllocSetContextCreate(MemoryContext parent,
--- 502,510 ----
errdetail("Failed while creating memory context \"%s\".",
name)));
}
+
+ update_alloc((MemoryContext) set, blksize);
+
block->aset = set;
block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
block->endptr = ((char *) block) + blksize;
***************
*** 590,595 **** AllocSetReset(MemoryContext context)
--- 595,602 ----
else
{
/* Normal case, release the block */
+ update_alloc(context, -(block->endptr - ((char*) block)));
+
#ifdef CLOBBER_FREED_MEMORY
wipe_mem(block, block->freeptr - ((char *) block));
#endif
***************
*** 635,640 **** AllocSetDelete(MemoryContext context)
--- 642,654 ----
#ifdef CLOBBER_FREED_MEMORY
wipe_mem(block, block->freeptr - ((char *) block));
#endif
+
+ /*
+ * Parent is already unlinked from this context, so we can't use
+ * update_alloc(). The caller should have already subtracted from the
+ * parents' total_allocated.
+ */
+
free(block);
block = next;
}
***************
*** 672,677 **** AllocSetAlloc(MemoryContext context, Size size)
--- 686,694 ----
block = (AllocBlock) malloc(blksize);
if (block == NULL)
return NULL;
+
+ update_alloc(context, blksize);
+
block->aset = set;
block->freeptr = block->endptr = ((char *) block) + blksize;
***************
*** 861,866 **** AllocSetAlloc(MemoryContext context, Size size)
--- 878,885 ----
if (block == NULL)
return NULL;
+ update_alloc(context, blksize);
+
block->aset = set;
block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
block->endptr = ((char *) block) + blksize;
***************
*** 964,969 **** AllocSetFree(MemoryContext context, void *pointer)
--- 983,991 ----
set->blocks = block->next;
else
prevblock->next = block->next;
+
+ update_alloc(context, -(block->endptr - ((char*) block)));
+
#ifdef CLOBBER_FREED_MEMORY
wipe_mem(block, block->freeptr - ((char *) block));
#endif
***************
*** 1077,1082 **** AllocSetRealloc(MemoryContext context, void *pointer, Size size)
--- 1099,1105 ----
AllocBlock prevblock = NULL;
Size chksize;
Size blksize;
+ Size oldblksize;
while (block != NULL)
{
***************
*** 1094,1102 **** AllocSetRealloc(MemoryContext context, void *pointer, Size size)
--- 1117,1130 ----
/* Do the realloc */
chksize = MAXALIGN(size);
blksize = chksize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ;
+ oldblksize = block->endptr - ((char *)block);
+
block = (AllocBlock) realloc(block, blksize);
if (block == NULL)
return NULL;
+
+ update_alloc(context, blksize - oldblksize);
+
block->freeptr = block->endptr = ((char *) block) + blksize;
/* Update pointers since block has likely been moved */
***************
*** 1361,1363 **** AllocSetCheck(MemoryContext context)
--- 1389,1407 ----
}
#endif /* MEMORY_CONTEXT_CHECKING */
+
+ /*
+ * Update self_allocated and total_allocated for the context. Size can be
+ * positive or negative.
+ */
+ void
+ update_alloc(MemoryContext context, int64 size)
+ {
+ MemoryContext parent;
+
+ context->self_allocated += size;
+
+ /* update total_allocated for self and all parents */
+ for (parent = context; parent != NULL; parent = parent->parent)
+ parent->total_allocated += size;
+ }
*** a/src/backend/utils/mmgr/mcxt.c
--- b/src/backend/utils/mmgr/mcxt.c
***************
*** 203,208 **** MemoryContextResetChildren(MemoryContext context)
--- 203,210 ----
void
MemoryContextDelete(MemoryContext context)
{
+ MemoryContext parent;
+
AssertArg(MemoryContextIsValid(context));
/* We had better not be deleting TopMemoryContext ... */
Assert(context != TopMemoryContext);
***************
*** 223,229 **** MemoryContextDelete(MemoryContext context)
--- 225,236 ----
* 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
* to the context tree. Better a leak than a crash.
+ *
+ * But first we need to subtract this context's allocation from
+ * total_allocated in the parent contexts.
*/
+ for(parent = context->parent; parent != NULL; parent = parent->parent)
+ parent->total_allocated -= context->total_allocated;
MemoryContextSetParent(context, NULL);
(*context->methods->delete_context) (context);
***************
*** 477,482 **** MemoryContextIsEmpty(MemoryContext context)
--- 484,504 ----
}
/*
+ * Find the memory allocated to blocks for this memory context. If total is
+ * true, also include descendants.
+ */
+ int64
+ MemoryContextMemAllocated(MemoryContext context, bool total)
+ {
+ AssertArg(MemoryContextIsValid(context));
+
+ if (total)
+ return context->total_allocated;
+ else
+ return context->self_allocated;
+ }
+
+ /*
* MemoryContextStats
* Print statistics about the named context and all its descendants.
*
***************
*** 636,641 **** MemoryContextCreate(NodeTag tag, Size size,
--- 658,665 ----
node->firstchild = NULL;
node->nextchild = NULL;
node->isReset = true;
+ node->self_allocated = 0;
+ node->total_allocated = 0;
node->name = ((char *) node) + size;
strcpy(node->name, name);
*** a/src/include/nodes/memnodes.h
--- b/src/include/nodes/memnodes.h
***************
*** 63,68 **** typedef struct MemoryContextData
--- 63,70 ----
MemoryContext nextchild; /* next child of same parent */
char *name; /* context name (just for debugging) */
MemoryContextCallback *reset_cbs; /* list of reset/delete callbacks */
+ int64 self_allocated; /* track memory allocated for this context */
+ int64 total_allocated; /* this context plus all descendants */
} MemoryContextData;
/* utils/palloc.h contains typedef struct MemoryContextData *MemoryContext */
*** a/src/include/utils/memutils.h
--- b/src/include/utils/memutils.h
***************
*** 103,108 **** extern Size GetMemoryChunkSpace(void *pointer);
--- 103,109 ----
extern MemoryContext GetMemoryChunkContext(void *pointer);
extern MemoryContext MemoryContextGetParent(MemoryContext context);
extern bool MemoryContextIsEmpty(MemoryContext context);
+ extern int64 MemoryContextMemAllocated(MemoryContext context, bool recurse);
extern void MemoryContextStats(MemoryContext context);
extern void MemoryContextAllowInCriticalSection(MemoryContext context,
bool allow);
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers