Em seg., 6 de jun. de 2022 às 21:14, Ranier Vilela <ranier...@gmail.com>
escreveu:

> Em seg., 6 de jun. de 2022 às 20:37, David Rowley <dgrowle...@gmail.com>
> escreveu:
>
>> On Mon, 6 Jun 2022 at 07:28, Ranier Vilela <ranier...@gmail.com> wrote:
>> > 4) 004-generation-reduces-memory-consumption-BUG.patch
>> > Same to the (2), but with BUG.
>> > It only takes a few tweaks to completely remove the field block.
>>
>> > This fails with make check.
>> > I couldn't figure out why it doesn't work with 16 bits (struct
>> GenerationChunk).
>>
>> Hi David, thanks for taking a look at this.
>
>
>> I think you're misunderstanding how blocks and chunks work here.  A
>> block can have many chunks.  You can't find the block that a chunk is
>> on by subtracting Generation_BLOCKHDRSZ from the pointer given to
>> GenerationFree(). That would only work if the chunk happened to be the
>> first chunk on a block. If it's anything apart from that then you'll
>> be making adjustments to the memory of some prior chunk on the block.
>> I imagine this is the reason you can't get the tests to pass.
>>
> Ok, I am still learning about this.
> Can you explain why subtracting Generation_BLOCKHDRSZ from the pointer,
> works for sizeof(struct GenerationChunk) = 24 bits,
> When all references for the block field have been removed.
> This pass check-world.
>
>
>>
>> Can you also explain why you think moving code around randomly or
>> adding unlikely() macros helps reduce the memory consumption overheads
>> of generation contexts?
>
> Of course, those changes do not reduce memory consumption.
> But, IMO, I think those changes improve the access to memory regions,
> because of the locality of the data.
>
> About "unlikely macros", this helps the branchs prediction, when most of
> the time,
> malloc and related functions, will not fail.
>
>
>>   I imagine you think that's helping to further
>> improve performance, but you've not offered any evidence of that
>> separately from the other changes you've made. If you think those are
>> useful changes then I recommend you run individual benchmarks and
>> offer those as proof that those changes are worthwhile.
>>
> Ok, I can understand, are changes unrelated.
>
Let's restart this, to simplify the review and commit work.

Regarding the patches now, we have:
1) v1-001-aset-reduces-memory-consumption.patch
Reduces memory used by struct AllocBlockData by minus 8 bits,
reducing the total size to 32 bits, which leads to "fitting" two structs in
a 64bit cache.

Remove tests elog(ERROR, "could not find block containing chunk %p" and
elog(ERROR, "could not find block containing chunk %p", moving them to
MEMORY_CONTEXT_CHECKING context.

Since 8.2 versions, nobody complains about these tests.

But if is not acceptable, have the option (3)
v1-003-aset-reduces-memory-consumption.patch

2) v1-002-generation-reduces-memory-consumption.patch
Reduces memory used by struct GenerationBlock, by minus 8 bits,
reducing the total size to 32 bits, which leads to "fitting" two structs in
a 64bit cache.

3) v1-003-aset-reduces-memory-consumption.patch
Same to the (1), but without remove the tests:
elog(ERROR, "could not find block containing chunk %p" and
elog(ERROR, "could not find block containing chunk %p",
But at the cost of removing a one tiny part of the tests and
moving them to MEMORY_CONTEXT_CHECKING context.

Since 8.2 versions, nobody complains about these tests.

regards,
Ranier Vilela
diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c
index ec3e264a73..901a954508 100644
--- a/src/backend/utils/mmgr/aset.c
+++ b/src/backend/utils/mmgr/aset.c
@@ -150,11 +150,13 @@ typedef AllocSetContext *AllocSet;
  */
 typedef struct AllocBlockData
 {
-	AllocSet	aset;			/* aset that owns this block */
 	AllocBlock	prev;			/* prev block in aset's blocks list, if any */
 	AllocBlock	next;			/* next block in aset's blocks list, if any */
 	char	   *freeptr;		/* start of free space in this block */
 	char	   *endptr;			/* end of space in this block */
+#ifdef MEMORY_CONTEXT_CHECKING
+	AllocSet	aset;			/* aset that owns this block */
+#endif
 }			AllocBlockData;
 
 /*
@@ -485,11 +487,13 @@ AllocSetContextCreateInternal(MemoryContext parent,
 
 	/* Fill in the initial block's block header */
 	block = (AllocBlock) (((char *) set) + MAXALIGN(sizeof(AllocSetContext)));
-	block->aset = set;
 	block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
 	block->endptr = ((char *) set) + firstBlockSize;
 	block->prev = NULL;
 	block->next = NULL;
+#ifdef MEMORY_CONTEXT_CHECKING
+	block->aset = set;
+#endif
 
 	/* Mark unallocated space NOACCESS; leave the block header alone. */
 	VALGRIND_MAKE_MEM_NOACCESS(block->freeptr, block->endptr - block->freeptr);
@@ -743,8 +747,10 @@ AllocSetAlloc(MemoryContext context, Size size)
 
 		context->mem_allocated += blksize;
 
-		block->aset = set;
 		block->freeptr = block->endptr = ((char *) block) + blksize;
+#ifdef MEMORY_CONTEXT_CHECKING
+		block->aset = set;
+#endif
 
 		chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ);
 		chunk->aset = set;
@@ -936,9 +942,11 @@ AllocSetAlloc(MemoryContext context, Size size)
 
 		context->mem_allocated += blksize;
 
-		block->aset = set;
 		block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
 		block->endptr = ((char *) block) + blksize;
+#ifdef MEMORY_CONTEXT_CHECKING
+		block->aset = set;
+#endif
 
 		/* Mark unallocated space NOACCESS. */
 		VALGRIND_MAKE_MEM_NOACCESS(block->freeptr,
@@ -1014,6 +1022,7 @@ AllocSetFree(MemoryContext context, void *pointer)
 		 */
 		AllocBlock	block = (AllocBlock) (((char *) chunk) - ALLOC_BLOCKHDRSZ);
 
+#ifdef MEMORY_CONTEXT_CHECKING
 		/*
 		 * Try to verify that we have a sane block pointer: it should
 		 * reference the correct aset, and freeptr and endptr should point
@@ -1024,6 +1033,7 @@ AllocSetFree(MemoryContext context, void *pointer)
 			block->freeptr != ((char *) block) +
 			(chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ))
 			elog(ERROR, "could not find block containing chunk %p", chunk);
+#endif
 
 		/* OK, remove block from aset's list and free it */
 		if (block->prev)
@@ -1103,6 +1113,7 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size)
 		Size		blksize;
 		Size		oldblksize;
 
+#ifdef MEMORY_CONTEXT_CHECKING
 		/*
 		 * Try to verify that we have a sane block pointer: it should
 		 * reference the correct aset, and freeptr and endptr should point
@@ -1113,6 +1124,7 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size)
 			block->freeptr != ((char *) block) +
 			(oldsize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ))
 			elog(ERROR, "could not find block containing chunk %p", chunk);
+#endif
 
 		/*
 		 * Even if the new request is less than set->allocChunkLimit, we stick
diff --git a/src/backend/utils/mmgr/generation.c b/src/backend/utils/mmgr/generation.c
index e530e272e0..2f4d7ced5f 100644
--- a/src/backend/utils/mmgr/generation.c
+++ b/src/backend/utils/mmgr/generation.c
@@ -89,7 +89,6 @@ typedef struct GenerationContext
 struct GenerationBlock
 {
 	dlist_node	node;			/* doubly-linked list of blocks */
-	Size		blksize;		/* allocated size of this block */
 	int			nchunks;		/* number of chunks in the block */
 	int			nfree;			/* number of free chunks */
 	char	   *freeptr;		/* start of free space in this block */
@@ -414,7 +413,6 @@ GenerationAlloc(MemoryContext context, Size size)
 		context->mem_allocated += blksize;
 
 		/* block with a single (used) chunk */
-		block->blksize = blksize;
 		block->nchunks = 1;
 		block->nfree = 0;
 
@@ -576,7 +574,6 @@ GenerationAlloc(MemoryContext context, Size size)
 static inline void
 GenerationBlockInit(GenerationBlock *block, Size blksize)
 {
-	block->blksize = blksize;
 	block->nchunks = 0;
 	block->nfree = 0;
 
@@ -647,10 +644,10 @@ GenerationBlockFree(GenerationContext *set, GenerationBlock *block)
 	/* release the block from the list of blocks */
 	dlist_delete(&block->node);
 
-	((MemoryContext) set)->mem_allocated -= block->blksize;
+	((MemoryContext) set)->mem_allocated -= block->endptr - ((char *) block);
 
 #ifdef CLOBBER_FREED_MEMORY
-	wipe_mem(block, block->blksize);
+	wipe_mem(block, block->endptr - ((char *) block));
 #endif
 
 	free(block);
@@ -732,7 +729,8 @@ GenerationFree(MemoryContext context, void *pointer)
 	 */
 	dlist_delete(&block->node);
 
-	context->mem_allocated -= block->blksize;
+	context->mem_allocated -= block->endptr - ((char *) block);
+	
 	free(block);
 }
 
@@ -926,7 +924,7 @@ GenerationStats(MemoryContext context,
 		nblocks++;
 		nchunks += block->nchunks;
 		nfreechunks += block->nfree;
-		totalspace += block->blksize;
+		totalspace += block->endptr - ((char *) block);
 		freespace += (block->endptr - block->freeptr);
 	}
 
@@ -977,7 +975,7 @@ GenerationCheck(MemoryContext context)
 					nchunks;
 		char	   *ptr;
 
-		total_allocated += block->blksize;
+		total_allocated += block->endptr - ((char *) block);
 
 		/*
 		 * nfree > nchunks is surely wrong.  Equality is allowed as the block
diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c
index ec3e264a73..fbe33ad87e 100644
--- a/src/backend/utils/mmgr/aset.c
+++ b/src/backend/utils/mmgr/aset.c
@@ -150,11 +150,13 @@ typedef AllocSetContext *AllocSet;
  */
 typedef struct AllocBlockData
 {
-	AllocSet	aset;			/* aset that owns this block */
 	AllocBlock	prev;			/* prev block in aset's blocks list, if any */
 	AllocBlock	next;			/* next block in aset's blocks list, if any */
 	char	   *freeptr;		/* start of free space in this block */
 	char	   *endptr;			/* end of space in this block */
+#ifdef MEMORY_CONTEXT_CHECKING
+	AllocSet	aset;			/* aset that owns this block */
+#endif
 }			AllocBlockData;
 
 /*
@@ -485,11 +487,13 @@ AllocSetContextCreateInternal(MemoryContext parent,
 
 	/* Fill in the initial block's block header */
 	block = (AllocBlock) (((char *) set) + MAXALIGN(sizeof(AllocSetContext)));
-	block->aset = set;
 	block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
 	block->endptr = ((char *) set) + firstBlockSize;
 	block->prev = NULL;
 	block->next = NULL;
+#ifdef MEMORY_CONTEXT_CHECKING
+	block->aset = set;
+#endif
 
 	/* Mark unallocated space NOACCESS; leave the block header alone. */
 	VALGRIND_MAKE_MEM_NOACCESS(block->freeptr, block->endptr - block->freeptr);
@@ -743,8 +747,10 @@ AllocSetAlloc(MemoryContext context, Size size)
 
 		context->mem_allocated += blksize;
 
-		block->aset = set;
 		block->freeptr = block->endptr = ((char *) block) + blksize;
+#ifdef MEMORY_CONTEXT_CHECKING
+		block->aset = set;
+#endif
 
 		chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ);
 		chunk->aset = set;
@@ -936,9 +942,11 @@ AllocSetAlloc(MemoryContext context, Size size)
 
 		context->mem_allocated += blksize;
 
-		block->aset = set;
 		block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
 		block->endptr = ((char *) block) + blksize;
+#ifdef MEMORY_CONTEXT_CHECKING
+		block->aset = set;
+#endif
 
 		/* Mark unallocated space NOACCESS. */
 		VALGRIND_MAKE_MEM_NOACCESS(block->freeptr,
@@ -1019,8 +1027,10 @@ AllocSetFree(MemoryContext context, void *pointer)
 		 * reference the correct aset, and freeptr and endptr should point
 		 * just past the chunk.
 		 */
-		if (block->aset != set ||
-			block->freeptr != block->endptr ||
+		if (block->freeptr != block->endptr ||
+#ifdef MEMORY_CONTEXT_CHECKING
+			block->aset != set ||
+#endif
 			block->freeptr != ((char *) block) +
 			(chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ))
 			elog(ERROR, "could not find block containing chunk %p", chunk);
@@ -1108,8 +1118,10 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size)
 		 * reference the correct aset, and freeptr and endptr should point
 		 * just past the chunk.
 		 */
-		if (block->aset != set ||
-			block->freeptr != block->endptr ||
+		if (block->freeptr != block->endptr ||
+#ifdef MEMORY_CONTEXT_CHECKING
+			block->aset != set ||
+#endif
 			block->freeptr != ((char *) block) +
 			(oldsize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ))
 			elog(ERROR, "could not find block containing chunk %p", chunk);

Reply via email to