Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 2c2eb0d

Browse files
committed
Shrink memory contexts struct sizes
Here we reduce the block size fields in AllocSetContext, GenerationContext and SlabContext from Size down to uint32. Ever since c6e0fe1, blocks for non-dedicated palloc chunks can no longer be larger than 1GB, so there's no need to store the various block size fields as 64-bit values. 32 bits are enough to store 2^30. Here we also further reduce the memory context struct sizes by getting rid of the 'keeper' field which stores a pointer to the context's keeper block. All the context types which have this field always allocate the keeper block in the same allocation as the memory context itself, so the keeper block always comes right at the end of the context struct. Add some macros to calculate that address rather than storing it in the context. Overall, in AllocSetContext and GenerationContext, this saves 20 bytes on 64-bit builds which for ALLOCSET_SMALL_SIZES can sometimes mean the difference between having to allocate a 2nd block and storing all the required allocations on the keeper block alone. Such contexts are used in relcache to store cache entries for indexes, of which there can be a large number in a single backend. Author: Melih Mutlu Reviewed-by: David Rowley Discussion: https://postgr.es/m/CAGPVpCSOW3uJ1QJmsMR9_oE3X7fG_z4q0AoU4R_w+2RzvroPFg@mail.gmail.com
1 parent 03d1080 commit 2c2eb0d

File tree

3 files changed

+60
-48
lines changed

3 files changed

+60
-48
lines changed

src/backend/utils/mmgr/aset.c

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,10 @@ typedef struct AllocSetContext
156156
AllocBlock blocks; /* head of list of blocks in this set */
157157
MemoryChunk *freelist[ALLOCSET_NUM_FREELISTS]; /* free chunk lists */
158158
/* Allocation parameters for this context: */
159-
Size initBlockSize; /* initial block size */
160-
Size maxBlockSize; /* maximum block size */
161-
Size nextBlockSize; /* next block size to allocate */
162-
Size allocChunkLimit; /* effective chunk size limit */
163-
AllocBlock keeper; /* keep this block over resets */
159+
uint32 initBlockSize; /* initial block size */
160+
uint32 maxBlockSize; /* maximum block size */
161+
uint32 nextBlockSize; /* next block size to allocate */
162+
uint32 allocChunkLimit; /* effective chunk size limit */
164163
/* freelist this context could be put in, or -1 if not a candidate: */
165164
int freeListIndex; /* index in context_freelists[], or -1 */
166165
} AllocSetContext;
@@ -241,6 +240,13 @@ typedef struct AllocBlockData
241240
*/
242241
#define MAX_FREE_CONTEXTS 100 /* arbitrary limit on freelist length */
243242

243+
/* Obtain the keeper block for an allocation set */
244+
#define KeeperBlock(set) \
245+
((AllocBlock) (((char *) set) + MAXALIGN(sizeof(AllocSetContext))))
246+
247+
/* Check if the block is the keeper block of the given allocation set */
248+
#define IsKeeperBlock(set, block) ((block) == (KeeperBlock(set)))
249+
244250
typedef struct AllocSetFreeList
245251
{
246252
int num_free; /* current list length */
@@ -417,7 +423,7 @@ AllocSetContextCreateInternal(MemoryContext parent,
417423
name);
418424

419425
((MemoryContext) set)->mem_allocated =
420-
set->keeper->endptr - ((char *) set);
426+
KeeperBlock(set)->endptr - ((char *) set);
421427

422428
return (MemoryContext) set;
423429
}
@@ -453,7 +459,7 @@ AllocSetContextCreateInternal(MemoryContext parent,
453459
*/
454460

455461
/* Fill in the initial block's block header */
456-
block = (AllocBlock) (((char *) set) + MAXALIGN(sizeof(AllocSetContext)));
462+
block = KeeperBlock(set);
457463
block->aset = set;
458464
block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
459465
block->endptr = ((char *) set) + firstBlockSize;
@@ -465,15 +471,13 @@ AllocSetContextCreateInternal(MemoryContext parent,
465471

466472
/* Remember block as part of block list */
467473
set->blocks = block;
468-
/* Mark block as not to be released at reset time */
469-
set->keeper = block;
470474

471475
/* Finish filling in aset-specific parts of the context header */
472476
MemSetAligned(set->freelist, 0, sizeof(set->freelist));
473477

474-
set->initBlockSize = initBlockSize;
475-
set->maxBlockSize = maxBlockSize;
476-
set->nextBlockSize = initBlockSize;
478+
set->initBlockSize = (uint32) initBlockSize;
479+
set->maxBlockSize = (uint32) maxBlockSize;
480+
set->nextBlockSize = (uint32) initBlockSize;
477481
set->freeListIndex = freeListIndex;
478482

479483
/*
@@ -544,21 +548,21 @@ AllocSetReset(MemoryContext context)
544548
#endif
545549

546550
/* Remember keeper block size for Assert below */
547-
keepersize = set->keeper->endptr - ((char *) set);
551+
keepersize = KeeperBlock(set)->endptr - ((char *) set);
548552

549553
/* Clear chunk freelists */
550554
MemSetAligned(set->freelist, 0, sizeof(set->freelist));
551555

552556
block = set->blocks;
553557

554558
/* New blocks list will be just the keeper block */
555-
set->blocks = set->keeper;
559+
set->blocks = KeeperBlock(set);
556560

557561
while (block != NULL)
558562
{
559563
AllocBlock next = block->next;
560564

561-
if (block == set->keeper)
565+
if (IsKeeperBlock(set, block))
562566
{
563567
/* Reset the block, but don't return it to malloc */
564568
char *datastart = ((char *) block) + ALLOC_BLOCKHDRSZ;
@@ -614,7 +618,7 @@ AllocSetDelete(MemoryContext context)
614618
#endif
615619

616620
/* Remember keeper block size for Assert below */
617-
keepersize = set->keeper->endptr - ((char *) set);
621+
keepersize = KeeperBlock(set)->endptr - ((char *) set);
618622

619623
/*
620624
* If the context is a candidate for a freelist, put it into that freelist
@@ -663,14 +667,14 @@ AllocSetDelete(MemoryContext context)
663667
{
664668
AllocBlock next = block->next;
665669

666-
if (block != set->keeper)
670+
if (!IsKeeperBlock(set, block))
667671
context->mem_allocated -= block->endptr - ((char *) block);
668672

669673
#ifdef CLOBBER_FREED_MEMORY
670674
wipe_mem(block, block->freeptr - ((char *) block));
671675
#endif
672676

673-
if (block != set->keeper)
677+
if (!IsKeeperBlock(set, block))
674678
free(block);
675679

676680
block = next;
@@ -1547,7 +1551,7 @@ AllocSetCheck(MemoryContext context)
15471551
long nchunks = 0;
15481552
bool has_external_chunk = false;
15491553

1550-
if (set->keeper == block)
1554+
if (IsKeeperBlock(set, block))
15511555
total_allocated += block->endptr - ((char *) set);
15521556
else
15531557
total_allocated += block->endptr - ((char *) block);
@@ -1557,7 +1561,7 @@ AllocSetCheck(MemoryContext context)
15571561
*/
15581562
if (!blk_used)
15591563
{
1560-
if (set->keeper != block)
1564+
if (!IsKeeperBlock(set, block))
15611565
elog(WARNING, "problem in alloc set %s: empty block %p",
15621566
name, block);
15631567
}

src/backend/utils/mmgr/generation.c

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,16 @@ typedef struct GenerationContext
6161
MemoryContextData header; /* Standard memory-context fields */
6262

6363
/* Generational context parameters */
64-
Size initBlockSize; /* initial block size */
65-
Size maxBlockSize; /* maximum block size */
66-
Size nextBlockSize; /* next block size to allocate */
67-
Size allocChunkLimit; /* effective chunk size limit */
64+
uint32 initBlockSize; /* initial block size */
65+
uint32 maxBlockSize; /* maximum block size */
66+
uint32 nextBlockSize; /* next block size to allocate */
67+
uint32 allocChunkLimit; /* effective chunk size limit */
6868

6969
GenerationBlock *block; /* current (most recently allocated) block, or
7070
* NULL if we've just freed the most recent
7171
* block */
7272
GenerationBlock *freeblock; /* pointer to a block that's being recycled,
7373
* or NULL if there's no such block. */
74-
GenerationBlock *keeper; /* keep this block over resets */
7574
dlist_head blocks; /* list of blocks */
7675
} GenerationContext;
7776

@@ -120,6 +119,14 @@ struct GenerationBlock
120119
#define ExternalChunkGetBlock(chunk) \
121120
(GenerationBlock *) ((char *) chunk - Generation_BLOCKHDRSZ)
122121

122+
/* Obtain the keeper block for a generation context */
123+
#define KeeperBlock(set) \
124+
((GenerationBlock *) (((char *) set) + \
125+
MAXALIGN(sizeof(GenerationContext))))
126+
127+
/* Check if the block is the keeper block of the given generation context */
128+
#define IsKeeperBlock(set, block) ((block) == (KeeperBlock(set)))
129+
123130
/* Inlined helper functions */
124131
static inline void GenerationBlockInit(GenerationContext *context,
125132
GenerationBlock *block,
@@ -214,7 +221,7 @@ GenerationContextCreate(MemoryContext parent,
214221
dlist_init(&set->blocks);
215222

216223
/* Fill in the initial block's block header */
217-
block = (GenerationBlock *) (((char *) set) + MAXALIGN(sizeof(GenerationContext)));
224+
block = KeeperBlock(set);
218225
/* determine the block size and initialize it */
219226
firstBlockSize = allocSize - MAXALIGN(sizeof(GenerationContext));
220227
GenerationBlockInit(set, block, firstBlockSize);
@@ -228,13 +235,10 @@ GenerationContextCreate(MemoryContext parent,
228235
/* No free block, yet */
229236
set->freeblock = NULL;
230237

231-
/* Mark block as not to be released at reset time */
232-
set->keeper = block;
233-
234238
/* Fill in GenerationContext-specific header fields */
235-
set->initBlockSize = initBlockSize;
236-
set->maxBlockSize = maxBlockSize;
237-
set->nextBlockSize = initBlockSize;
239+
set->initBlockSize = (uint32) initBlockSize;
240+
set->maxBlockSize = (uint32) maxBlockSize;
241+
set->nextBlockSize = (uint32) initBlockSize;
238242

239243
/*
240244
* Compute the allocation chunk size limit for this context.
@@ -294,14 +298,14 @@ GenerationReset(MemoryContext context)
294298
{
295299
GenerationBlock *block = dlist_container(GenerationBlock, node, miter.cur);
296300

297-
if (block == set->keeper)
301+
if (IsKeeperBlock(set, block))
298302
GenerationBlockMarkEmpty(block);
299303
else
300304
GenerationBlockFree(set, block);
301305
}
302306

303307
/* set it so new allocations to make use of the keeper block */
304-
set->block = set->keeper;
308+
set->block = KeeperBlock(set);
305309

306310
/* Reset block size allocation sequence, too */
307311
set->nextBlockSize = set->initBlockSize;
@@ -440,10 +444,10 @@ GenerationAlloc(MemoryContext context, Size size)
440444
*/
441445
set->freeblock = NULL;
442446
}
443-
else if (GenerationBlockIsEmpty(set->keeper) &&
444-
GenerationBlockFreeBytes(set->keeper) >= required_size)
447+
else if (GenerationBlockIsEmpty(KeeperBlock(set)) &&
448+
GenerationBlockFreeBytes(KeeperBlock(set)) >= required_size)
445449
{
446-
block = set->keeper;
450+
block = KeeperBlock(set);
447451
}
448452
else
449453
{
@@ -594,7 +598,7 @@ static inline void
594598
GenerationBlockFree(GenerationContext *set, GenerationBlock *block)
595599
{
596600
/* Make sure nobody tries to free the keeper block */
597-
Assert(block != set->keeper);
601+
Assert(!IsKeeperBlock(set, block));
598602
/* We shouldn't be freeing the freeblock either */
599603
Assert(block != set->freeblock);
600604

@@ -691,7 +695,7 @@ GenerationFree(void *pointer)
691695
set = block->context;
692696

693697
/* Don't try to free the keeper block, just mark it empty */
694-
if (block == set->keeper)
698+
if (IsKeeperBlock(set, block))
695699
{
696700
GenerationBlockMarkEmpty(block);
697701
return;

src/backend/utils/mmgr/slab.c

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,9 @@ typedef struct SlabContext
104104
{
105105
MemoryContextData header; /* Standard memory-context fields */
106106
/* Allocation parameters for this context: */
107-
Size chunkSize; /* the requested (non-aligned) chunk size */
108-
Size fullChunkSize; /* chunk size with chunk header and alignment */
109-
Size blockSize; /* the size to make each block of chunks */
107+
uint32 chunkSize; /* the requested (non-aligned) chunk size */
108+
uint32 fullChunkSize; /* chunk size with chunk header and alignment */
109+
uint32 blockSize; /* the size to make each block of chunks */
110110
int32 chunksPerBlock; /* number of chunks that fit in 1 block */
111111
int32 curBlocklistIndex; /* index into the blocklist[] element
112112
* containing the fullest, blocks */
@@ -314,7 +314,9 @@ SlabGetNextFreeChunk(SlabContext *slab, SlabBlock *block)
314314
* blockSize: allocation block size
315315
* chunkSize: allocation chunk size
316316
*
317-
* The MAXALIGN(chunkSize) may not exceed MEMORYCHUNK_MAX_VALUE
317+
* The Slab_CHUNKHDRSZ + MAXALIGN(chunkSize + 1) may not exceed
318+
* MEMORYCHUNK_MAX_VALUE.
319+
* 'blockSize' may not exceed MEMORYCHUNK_MAX_BLOCKOFFSET.
318320
*/
319321
MemoryContext
320322
SlabContextCreate(MemoryContext parent,
@@ -330,7 +332,7 @@ SlabContextCreate(MemoryContext parent,
330332
/* ensure MemoryChunk's size is properly maxaligned */
331333
StaticAssertDecl(Slab_CHUNKHDRSZ == MAXALIGN(Slab_CHUNKHDRSZ),
332334
"sizeof(MemoryChunk) is not maxaligned");
333-
Assert(MAXALIGN(chunkSize) <= MEMORYCHUNK_MAX_VALUE);
335+
Assert(blockSize <= MEMORYCHUNK_MAX_BLOCKOFFSET);
334336

335337
/*
336338
* Ensure there's enough space to store the pointer to the next free chunk
@@ -347,6 +349,8 @@ SlabContextCreate(MemoryContext parent,
347349
fullChunkSize = Slab_CHUNKHDRSZ + MAXALIGN(chunkSize);
348350
#endif
349351

352+
Assert(fullChunkSize <= MEMORYCHUNK_MAX_VALUE);
353+
350354
/* compute the number of chunks that will fit on each block */
351355
chunksPerBlock = (blockSize - Slab_BLOCKHDRSZ) / fullChunkSize;
352356

@@ -374,9 +378,9 @@ SlabContextCreate(MemoryContext parent,
374378
*/
375379

376380
/* Fill in SlabContext-specific header fields */
377-
slab->chunkSize = chunkSize;
378-
slab->fullChunkSize = fullChunkSize;
379-
slab->blockSize = blockSize;
381+
slab->chunkSize = (uint32) chunkSize;
382+
slab->fullChunkSize = (uint32) fullChunkSize;
383+
slab->blockSize = (uint32) blockSize;
380384
slab->chunksPerBlock = chunksPerBlock;
381385
slab->curBlocklistIndex = 0;
382386

@@ -506,7 +510,7 @@ SlabAlloc(MemoryContext context, Size size)
506510

507511
/* make sure we only allow correct request size */
508512
if (unlikely(size != slab->chunkSize))
509-
elog(ERROR, "unexpected alloc chunk size %zu (expected %zu)",
513+
elog(ERROR, "unexpected alloc chunk size %zu (expected %u)",
510514
size, slab->chunkSize);
511515

512516
/*

0 commit comments

Comments
 (0)