*** 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_allocation(MemoryContext context, size_t size);
+ 
  /*
   * These functions implement the MemoryContext API for AllocSet contexts.
   */
***************
*** 250,256 **** static void AllocSetFree(MemoryContext context, void *pointer);
  static void *AllocSetRealloc(MemoryContext context, void *pointer, Size size);
  static void AllocSetInit(MemoryContext context);
  static void AllocSetReset(MemoryContext context);
! static void AllocSetDelete(MemoryContext context);
  static Size AllocSetGetChunkSpace(MemoryContext context, void *pointer);
  static bool AllocSetIsEmpty(MemoryContext context);
  static void AllocSetStats(MemoryContext context, int level);
--- 252,258 ----
  static void *AllocSetRealloc(MemoryContext context, void *pointer, Size size);
  static void AllocSetInit(MemoryContext context);
  static void AllocSetReset(MemoryContext context);
! static void AllocSetDelete(MemoryContext context, MemoryContext parent);
  static Size AllocSetGetChunkSpace(MemoryContext context, void *pointer);
  static bool AllocSetIsEmpty(MemoryContext context);
  static void AllocSetStats(MemoryContext context, int level);
***************
*** 500,505 **** AllocSetContextCreate(MemoryContext parent,
--- 502,510 ----
  					 errdetail("Failed while creating memory context \"%s\".",
  							   name)));
  		}
+ 
+ 		update_allocation((MemoryContext) context, blksize);
+ 
  		block->aset = context;
  		block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
  		block->endptr = ((char *) block) + blksize;
***************
*** 590,595 **** AllocSetReset(MemoryContext context)
--- 595,601 ----
  		else
  		{
  			/* Normal case, release the block */
+ 			update_allocation(context, -(block->endptr - ((char*) block)));
  #ifdef CLOBBER_FREED_MEMORY
  			wipe_mem(block, block->freeptr - ((char *) block));
  #endif
***************
*** 611,617 **** AllocSetReset(MemoryContext context)
   * But note we are not responsible for deleting the context node itself.
   */
  static void
! AllocSetDelete(MemoryContext context)
  {
  	AllocSet	set = (AllocSet) context;
  	AllocBlock	block = set->blocks;
--- 617,623 ----
   * But note we are not responsible for deleting the context node itself.
   */
  static void
! AllocSetDelete(MemoryContext context, MemoryContext parent)
  {
  	AllocSet	set = (AllocSet) context;
  	AllocBlock	block = set->blocks;
***************
*** 623,628 **** AllocSetDelete(MemoryContext context)
--- 629,644 ----
  	AllocSetCheck(context);
  #endif
  
+ 	/*
+ 	 * Parent is already unlinked from context, so can't use
+ 	 * update_allocation().
+ 	 */
+ 	while (parent != NULL)
+ 	{
+ 		parent->total_allocated -= context->total_allocated;
+ 		parent = parent->parent;
+ 	}
+ 
  	/* Make it look empty, just in case... */
  	MemSetAligned(set->freelist, 0, sizeof(set->freelist));
  	set->blocks = NULL;
***************
*** 678,683 **** AllocSetAlloc(MemoryContext context, Size size)
--- 694,702 ----
  					 errmsg("out of memory"),
  					 errdetail("Failed on request of size %zu.", size)));
  		}
+ 
+ 		update_allocation(context, blksize);
+ 
  		block->aset = set;
  		block->freeptr = block->endptr = ((char *) block) + blksize;
  
***************
*** 873,878 **** AllocSetAlloc(MemoryContext context, Size size)
--- 892,899 ----
  					 errdetail("Failed on request of size %zu.", size)));
  		}
  
+ 		update_allocation(context, blksize);
+ 
  		block->aset = set;
  		block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
  		block->endptr = ((char *) block) + blksize;
***************
*** 976,981 **** AllocSetFree(MemoryContext context, void *pointer)
--- 997,1003 ----
  			set->blocks = block->next;
  		else
  			prevblock->next = block->next;
+ 		update_allocation(context, -(block->endptr - ((char*) block)));
  #ifdef CLOBBER_FREED_MEMORY
  		wipe_mem(block, block->freeptr - ((char *) block));
  #endif
***************
*** 1088,1093 **** AllocSetRealloc(MemoryContext context, void *pointer, Size size)
--- 1110,1116 ----
  		AllocBlock	prevblock = NULL;
  		Size		chksize;
  		Size		blksize;
+ 		Size		oldblksize;
  
  		while (block != NULL)
  		{
***************
*** 1105,1110 **** AllocSetRealloc(MemoryContext context, void *pointer, Size size)
--- 1128,1135 ----
  		/* 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)
  		{
***************
*** 1114,1119 **** AllocSetRealloc(MemoryContext context, void *pointer, Size size)
--- 1139,1145 ----
  					 errmsg("out of memory"),
  					 errdetail("Failed on request of size %zu.", size)));
  		}
+ 		update_allocation(context, blksize - oldblksize);
  		block->freeptr = block->endptr = ((char *) block) + blksize;
  
  		/* Update pointers since block has likely been moved */
***************
*** 1277,1282 **** AllocSetStats(MemoryContext context, int level)
--- 1303,1333 ----
  }
  
  
+ /*
+  * update_allocation
+  *
+  * Track newly-allocated or newly-freed memory (freed memory should be
+  * negative).
+  */
+ static void
+ update_allocation(MemoryContext context, size_t size_bytes)
+ {
+ 	MemoryContext		parent;
+ 	uint32				size_kb = size_bytes/1024;
+ 
+ 	/* the maximum memory we can track is INT32_MAX * 1024 */
+ 	Assert(size_bytes/1024 <= UINT32_MAX);
+ 
+ 	context->self_allocated += size_kb;
+ 
+ 	for (parent = context; parent != NULL; parent = parent->parent)
+ 	{
+ 		parent->total_allocated += size_kb;
+ 		Assert(parent->self_allocated >= 0);
+ 		Assert(parent->total_allocated >= 0);
+ 	}
+ }
+ 
  #ifdef MEMORY_CONTEXT_CHECKING
  
  /*
*** a/src/backend/utils/mmgr/mcxt.c
--- b/src/backend/utils/mmgr/mcxt.c
***************
*** 187,192 **** MemoryContextResetChildren(MemoryContext context)
--- 187,194 ----
  void
  MemoryContextDelete(MemoryContext context)
  {
+ 	MemoryContext parent = context->parent;
+ 
  	AssertArg(MemoryContextIsValid(context));
  	/* We had better not be deleting TopMemoryContext ... */
  	Assert(context != TopMemoryContext);
***************
*** 202,208 **** MemoryContextDelete(MemoryContext context)
  	 */
  	MemoryContextSetParent(context, NULL);
  
! 	(*context->methods->delete_context) (context);
  	VALGRIND_DESTROY_MEMPOOL(context);
  	pfree(context);
  }
--- 204,211 ----
  	 */
  	MemoryContextSetParent(context, NULL);
  
! 	/* pass the parent in case it's needed, however */
! 	(*context->methods->delete_context) (context, parent);
  	VALGRIND_DESTROY_MEMPOOL(context);
  	pfree(context);
  }
***************
*** 324,329 **** MemoryContextAllowInCriticalSection(MemoryContext context, bool allow)
--- 327,347 ----
  }
  
  /*
+  * MemoryContextGetAllocated
+  *
+  * Return memory allocated by the system to this context. If total is true,
+  * include child contexts. Context must have track_mem set.
+  */
+ int64
+ MemoryContextGetAllocated(MemoryContext context, bool total)
+ {
+ 	if (total)
+ 		return (int64)context->total_allocated * 1024L;
+ 	else
+ 		return (int64)context->self_allocated * 1024L;
+ }
+ 
+ /*
   * GetMemoryChunkSpace
   *		Given a currently-allocated chunk, determine the total space
   *		it occupies (including all memory-allocation overhead).
***************
*** 576,581 **** MemoryContextCreate(NodeTag tag, Size size,
--- 594,601 ----
  	node->firstchild = NULL;
  	node->nextchild = NULL;
  	node->isReset = true;
+ 	node->total_allocated = 0;
+ 	node->self_allocated = 0;
  	node->name = ((char *) node) + size;
  	strcpy(node->name, name);
  
*** a/src/include/nodes/memnodes.h
--- b/src/include/nodes/memnodes.h
***************
*** 41,47 **** typedef struct MemoryContextMethods
  	void	   *(*realloc) (MemoryContext context, void *pointer, Size size);
  	void		(*init) (MemoryContext context);
  	void		(*reset) (MemoryContext context);
! 	void		(*delete_context) (MemoryContext context);
  	Size		(*get_chunk_space) (MemoryContext context, void *pointer);
  	bool		(*is_empty) (MemoryContext context);
  	void		(*stats) (MemoryContext context, int level);
--- 41,48 ----
  	void	   *(*realloc) (MemoryContext context, void *pointer, Size size);
  	void		(*init) (MemoryContext context);
  	void		(*reset) (MemoryContext context);
! 	void		(*delete_context) (MemoryContext context,
! 								   MemoryContext parent);
  	Size		(*get_chunk_space) (MemoryContext context, void *pointer);
  	bool		(*is_empty) (MemoryContext context);
  	void		(*stats) (MemoryContext context, int level);
***************
*** 59,64 **** typedef struct MemoryContextData
--- 60,67 ----
  	MemoryContext firstchild;	/* head of linked list of children */
  	MemoryContext nextchild;	/* next child of same parent */
  	char	   *name;			/* context name (just for debugging) */
+ 	uint32		total_allocated; /* kB; including child contexts */
+ 	uint32		self_allocated; /* kB; not including child contexts */
  	bool		isReset;		/* T = no space alloced since last reset */
  #ifdef USE_ASSERT_CHECKING
  	bool		allowInCritSection;	/* allow palloc in critical section */
*** a/src/include/utils/memutils.h
--- b/src/include/utils/memutils.h
***************
*** 96,101 **** extern void MemoryContextDeleteChildren(MemoryContext context);
--- 96,102 ----
  extern void MemoryContextResetAndDeleteChildren(MemoryContext context);
  extern void MemoryContextSetParent(MemoryContext context,
  					   MemoryContext new_parent);
+ extern int64 MemoryContextGetAllocated(MemoryContext context, bool total);
  extern Size GetMemoryChunkSpace(void *pointer);
  extern MemoryContext GetMemoryChunkContext(void *pointer);
  extern MemoryContext MemoryContextGetParent(MemoryContext context);
