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

Commit e00912e

Browse files
committed
Specialize MemoryContextMemAllocated().
An AllocSet doubles the size of allocated blocks (up to maxBlockSize), which means that the current block can represent half of the total allocated space for the memory context. But the free space in the current block may never have been touched, so don't count the untouched memory as allocated for the purposes of MemoryContextMemAllocated(). Discussion: https://postgr.es/m/ec63d70b668818255486a83ffadc3aec492c1f57.camel@j-davis.com
1 parent 487e986 commit e00912e

File tree

5 files changed

+77
-28
lines changed

5 files changed

+77
-28
lines changed

src/backend/utils/mmgr/aset.c

+33-13
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ typedef struct AllocSetContext
132132
Size maxBlockSize; /* maximum block size */
133133
Size nextBlockSize; /* next block size to allocate */
134134
Size allocChunkLimit; /* effective chunk size limit */
135+
Size memAllocated; /* track memory allocated for this context */
135136
AllocBlock keeper; /* keep this block over resets */
136137
/* freelist this context could be put in, or -1 if not a candidate: */
137138
int freeListIndex; /* index in context_freelists[], or -1 */
@@ -272,6 +273,7 @@ static void *AllocSetRealloc(MemoryContext context, void *pointer, Size size);
272273
static void AllocSetReset(MemoryContext context);
273274
static void AllocSetDelete(MemoryContext context);
274275
static Size AllocSetGetChunkSpace(MemoryContext context, void *pointer);
276+
static Size AllocSetMemAllocated(MemoryContext context);
275277
static bool AllocSetIsEmpty(MemoryContext context);
276278
static void AllocSetStats(MemoryContext context,
277279
MemoryStatsPrintFunc printfunc, void *passthru,
@@ -291,6 +293,7 @@ static const MemoryContextMethods AllocSetMethods = {
291293
AllocSetReset,
292294
AllocSetDelete,
293295
AllocSetGetChunkSpace,
296+
AllocSetMemAllocated,
294297
AllocSetIsEmpty,
295298
AllocSetStats
296299
#ifdef MEMORY_CONTEXT_CHECKING
@@ -464,8 +467,7 @@ AllocSetContextCreateInternal(MemoryContext parent,
464467
parent,
465468
name);
466469

467-
((MemoryContext) set)->mem_allocated =
468-
set->keeper->endptr - ((char *) set);
470+
set->memAllocated = set->keeper->endptr - ((char *) set);
469471

470472
return (MemoryContext) set;
471473
}
@@ -555,7 +557,7 @@ AllocSetContextCreateInternal(MemoryContext parent,
555557
parent,
556558
name);
557559

558-
((MemoryContext) set)->mem_allocated = firstBlockSize;
560+
set->memAllocated = firstBlockSize;
559561

560562
return (MemoryContext) set;
561563
}
@@ -617,7 +619,7 @@ AllocSetReset(MemoryContext context)
617619
else
618620
{
619621
/* Normal case, release the block */
620-
context->mem_allocated -= block->endptr - ((char*) block);
622+
set->memAllocated -= block->endptr - ((char*) block);
621623

622624
#ifdef CLOBBER_FREED_MEMORY
623625
wipe_mem(block, block->freeptr - ((char *) block));
@@ -627,7 +629,7 @@ AllocSetReset(MemoryContext context)
627629
block = next;
628630
}
629631

630-
Assert(context->mem_allocated == keepersize);
632+
Assert(set->memAllocated == keepersize);
631633

632634
/* Reset block size allocation sequence, too */
633635
set->nextBlockSize = set->initBlockSize;
@@ -703,7 +705,7 @@ AllocSetDelete(MemoryContext context)
703705
AllocBlock next = block->next;
704706

705707
if (block != set->keeper)
706-
context->mem_allocated -= block->endptr - ((char *) block);
708+
set->memAllocated -= block->endptr - ((char *) block);
707709

708710
#ifdef CLOBBER_FREED_MEMORY
709711
wipe_mem(block, block->freeptr - ((char *) block));
@@ -715,7 +717,7 @@ AllocSetDelete(MemoryContext context)
715717
block = next;
716718
}
717719

718-
Assert(context->mem_allocated == keepersize);
720+
Assert(set->memAllocated == keepersize);
719721

720722
/* Finally, free the context header, including the keeper block */
721723
free(set);
@@ -758,7 +760,7 @@ AllocSetAlloc(MemoryContext context, Size size)
758760
if (block == NULL)
759761
return NULL;
760762

761-
context->mem_allocated += blksize;
763+
set->memAllocated += blksize;
762764

763765
block->aset = set;
764766
block->freeptr = block->endptr = ((char *) block) + blksize;
@@ -955,7 +957,7 @@ AllocSetAlloc(MemoryContext context, Size size)
955957
if (block == NULL)
956958
return NULL;
957959

958-
context->mem_allocated += blksize;
960+
set->memAllocated += blksize;
959961

960962
block->aset = set;
961963
block->freeptr = ((char *) block) + ALLOC_BLOCKHDRSZ;
@@ -1058,7 +1060,7 @@ AllocSetFree(MemoryContext context, void *pointer)
10581060
if (block->next)
10591061
block->next->prev = block->prev;
10601062

1061-
context->mem_allocated -= block->endptr - ((char*) block);
1063+
set->memAllocated -= block->endptr - ((char*) block);
10621064

10631065
#ifdef CLOBBER_FREED_MEMORY
10641066
wipe_mem(block, block->freeptr - ((char *) block));
@@ -1161,8 +1163,8 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size)
11611163
}
11621164

11631165
/* updated separately, not to underflow when (oldblksize > blksize) */
1164-
context->mem_allocated -= oldblksize;
1165-
context->mem_allocated += blksize;
1166+
set->memAllocated -= oldblksize;
1167+
set->memAllocated += blksize;
11661168

11671169
block->freeptr = block->endptr = ((char *) block) + blksize;
11681170

@@ -1337,6 +1339,24 @@ AllocSetGetChunkSpace(MemoryContext context, void *pointer)
13371339
return result;
13381340
}
13391341

1342+
/*
1343+
* All memory currently allocated for this context (including fragmentation
1344+
* and freed chunks).
1345+
*
1346+
* Allocation sizes double (up to maxBlockSize), so the current block may
1347+
* represent half of the total space allocated to the context. Subtract away
1348+
* the free space at the tail of the current block, which may never have been
1349+
* touched.
1350+
*/
1351+
static Size
1352+
AllocSetMemAllocated(MemoryContext context)
1353+
{
1354+
AllocSet set = (AllocSet) context;
1355+
AllocBlock currentBlock = set->blocks;
1356+
Size tailSpace = currentBlock->endptr - currentBlock->freeptr;
1357+
return set->memAllocated - tailSpace;
1358+
}
1359+
13401360
/*
13411361
* AllocSetIsEmpty
13421362
* Is an allocset empty of any allocated space?
@@ -1538,7 +1558,7 @@ AllocSetCheck(MemoryContext context)
15381558
name, block);
15391559
}
15401560

1541-
Assert(total_allocated == context->mem_allocated);
1561+
Assert(total_allocated == set->memAllocated);
15421562
}
15431563

15441564
#endif /* MEMORY_CONTEXT_CHECKING */

src/backend/utils/mmgr/generation.c

+20-5
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ typedef struct GenerationContext
6161

6262
/* Generational context parameters */
6363
Size blockSize; /* standard block size */
64+
Size memAllocated; /* track memory allocated for this context */
6465

6566
GenerationBlock *block; /* current (most recently allocated) block */
6667
dlist_head blocks; /* list of blocks */
@@ -152,6 +153,7 @@ static void *GenerationRealloc(MemoryContext context, void *pointer, Size size);
152153
static void GenerationReset(MemoryContext context);
153154
static void GenerationDelete(MemoryContext context);
154155
static Size GenerationGetChunkSpace(MemoryContext context, void *pointer);
156+
static Size GenerationMemAllocated(MemoryContext context);
155157
static bool GenerationIsEmpty(MemoryContext context);
156158
static void GenerationStats(MemoryContext context,
157159
MemoryStatsPrintFunc printfunc, void *passthru,
@@ -171,6 +173,7 @@ static const MemoryContextMethods GenerationMethods = {
171173
GenerationReset,
172174
GenerationDelete,
173175
GenerationGetChunkSpace,
176+
GenerationMemAllocated,
174177
GenerationIsEmpty,
175178
GenerationStats
176179
#ifdef MEMORY_CONTEXT_CHECKING
@@ -258,6 +261,7 @@ GenerationContextCreate(MemoryContext parent,
258261

259262
/* Fill in GenerationContext-specific header fields */
260263
set->blockSize = blockSize;
264+
set->memAllocated = 0;
261265
set->block = NULL;
262266
dlist_init(&set->blocks);
263267

@@ -297,7 +301,7 @@ GenerationReset(MemoryContext context)
297301

298302
dlist_delete(miter.cur);
299303

300-
context->mem_allocated -= block->blksize;
304+
set->memAllocated -= block->blksize;
301305

302306
#ifdef CLOBBER_FREED_MEMORY
303307
wipe_mem(block, block->blksize);
@@ -354,7 +358,7 @@ GenerationAlloc(MemoryContext context, Size size)
354358
if (block == NULL)
355359
return NULL;
356360

357-
context->mem_allocated += blksize;
361+
set->memAllocated += blksize;
358362

359363
/* block with a single (used) chunk */
360364
block->blksize = blksize;
@@ -411,7 +415,7 @@ GenerationAlloc(MemoryContext context, Size size)
411415
if (block == NULL)
412416
return NULL;
413417

414-
context->mem_allocated += blksize;
418+
set->memAllocated += blksize;
415419

416420
block->blksize = blksize;
417421
block->nchunks = 0;
@@ -528,7 +532,7 @@ GenerationFree(MemoryContext context, void *pointer)
528532
if (set->block == block)
529533
set->block = NULL;
530534

531-
context->mem_allocated -= block->blksize;
535+
set->memAllocated -= block->blksize;
532536
free(block);
533537
}
534538

@@ -666,6 +670,17 @@ GenerationGetChunkSpace(MemoryContext context, void *pointer)
666670
return result;
667671
}
668672

673+
/*
674+
* All memory currently allocated for this context (including fragmentation
675+
* and freed chunks).
676+
*/
677+
static Size
678+
GenerationMemAllocated(MemoryContext context)
679+
{
680+
GenerationContext *set = (GenerationContext *) context;
681+
return set->memAllocated;
682+
}
683+
669684
/*
670685
* GenerationIsEmpty
671686
* Is a GenerationContext empty of any allocated space?
@@ -844,7 +859,7 @@ GenerationCheck(MemoryContext context)
844859
name, nfree, block, block->nfree);
845860
}
846861

847-
Assert(total_allocated == context->mem_allocated);
862+
Assert(total_allocated == gen->memAllocated);
848863
}
849864

850865
#endif /* MEMORY_CONTEXT_CHECKING */

src/backend/utils/mmgr/mcxt.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ MemoryContextIsEmpty(MemoryContext context)
469469
Size
470470
MemoryContextMemAllocated(MemoryContext context, bool recurse)
471471
{
472-
Size total = context->mem_allocated;
472+
Size total = context->methods->mem_allocated(context);
473473

474474
AssertArg(MemoryContextIsValid(context));
475475

@@ -760,7 +760,6 @@ MemoryContextCreate(MemoryContext node,
760760
node->methods = methods;
761761
node->parent = parent;
762762
node->firstchild = NULL;
763-
node->mem_allocated = 0;
764763
node->prevchild = NULL;
765764
node->name = name;
766765
node->ident = NULL;

src/backend/utils/mmgr/slab.c

+22-7
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ typedef struct SlabContext
6767
Size fullChunkSize; /* chunk size including header and alignment */
6868
Size blockSize; /* block size */
6969
Size headerSize; /* allocated size of context header */
70+
Size memAllocated; /* track memory allocated for this context */
7071
int chunksPerBlock; /* number of chunks per block */
7172
int minFreeChunks; /* min number of free chunks in any block */
7273
int nblocks; /* number of blocks allocated */
@@ -132,6 +133,7 @@ static void *SlabRealloc(MemoryContext context, void *pointer, Size size);
132133
static void SlabReset(MemoryContext context);
133134
static void SlabDelete(MemoryContext context);
134135
static Size SlabGetChunkSpace(MemoryContext context, void *pointer);
136+
static Size SlabMemAllocated(MemoryContext context);
135137
static bool SlabIsEmpty(MemoryContext context);
136138
static void SlabStats(MemoryContext context,
137139
MemoryStatsPrintFunc printfunc, void *passthru,
@@ -150,6 +152,7 @@ static const MemoryContextMethods SlabMethods = {
150152
SlabReset,
151153
SlabDelete,
152154
SlabGetChunkSpace,
155+
SlabMemAllocated,
153156
SlabIsEmpty,
154157
SlabStats
155158
#ifdef MEMORY_CONTEXT_CHECKING
@@ -262,6 +265,7 @@ SlabContextCreate(MemoryContext parent,
262265
slab->fullChunkSize = fullChunkSize;
263266
slab->blockSize = blockSize;
264267
slab->headerSize = headerSize;
268+
slab->memAllocated = 0;
265269
slab->chunksPerBlock = chunksPerBlock;
266270
slab->minFreeChunks = 0;
267271
slab->nblocks = 0;
@@ -286,6 +290,17 @@ SlabContextCreate(MemoryContext parent,
286290
return (MemoryContext) slab;
287291
}
288292

293+
/*
294+
* All memory currently allocated for this context (including fragmentation
295+
* and freed chunks).
296+
*/
297+
static Size
298+
SlabMemAllocated(MemoryContext context)
299+
{
300+
SlabContext *slab = (SlabContext *) context;
301+
return slab->memAllocated;
302+
}
303+
289304
/*
290305
* SlabReset
291306
* Frees all memory which is allocated in the given set.
@@ -322,14 +337,14 @@ SlabReset(MemoryContext context)
322337
#endif
323338
free(block);
324339
slab->nblocks--;
325-
context->mem_allocated -= slab->blockSize;
340+
slab->memAllocated -= slab->blockSize;
326341
}
327342
}
328343

329344
slab->minFreeChunks = 0;
330345

331346
Assert(slab->nblocks == 0);
332-
Assert(context->mem_allocated == 0);
347+
Assert(slab->memAllocated == 0);
333348
}
334349

335350
/*
@@ -407,7 +422,7 @@ SlabAlloc(MemoryContext context, Size size)
407422

408423
slab->minFreeChunks = slab->chunksPerBlock;
409424
slab->nblocks += 1;
410-
context->mem_allocated += slab->blockSize;
425+
slab->memAllocated += slab->blockSize;
411426
}
412427

413428
/* grab the block from the freelist (even the new block is there) */
@@ -501,7 +516,7 @@ SlabAlloc(MemoryContext context, Size size)
501516

502517
SlabAllocInfo(slab, chunk);
503518

504-
Assert(slab->nblocks * slab->blockSize == context->mem_allocated);
519+
Assert(slab->nblocks * slab->blockSize == slab->memAllocated);
505520

506521
return SlabChunkGetPointer(chunk);
507522
}
@@ -578,13 +593,13 @@ SlabFree(MemoryContext context, void *pointer)
578593
{
579594
free(block);
580595
slab->nblocks--;
581-
context->mem_allocated -= slab->blockSize;
596+
slab->memAllocated -= slab->blockSize;
582597
}
583598
else
584599
dlist_push_head(&slab->freelist[block->nfree], &block->node);
585600

586601
Assert(slab->nblocks >= 0);
587-
Assert(slab->nblocks * slab->blockSize == context->mem_allocated);
602+
Assert(slab->nblocks * slab->blockSize == slab->memAllocated);
588603
}
589604

590605
/*
@@ -804,7 +819,7 @@ SlabCheck(MemoryContext context)
804819
}
805820
}
806821

807-
Assert(slab->nblocks * slab->blockSize == context->mem_allocated);
822+
Assert(slab->nblocks * slab->blockSize == slab->memAllocated);
808823
}
809824

810825
#endif /* MEMORY_CONTEXT_CHECKING */

src/include/nodes/memnodes.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ typedef struct MemoryContextMethods
6363
void (*reset) (MemoryContext context);
6464
void (*delete_context) (MemoryContext context);
6565
Size (*get_chunk_space) (MemoryContext context, void *pointer);
66+
Size (*mem_allocated) (MemoryContext context);
6667
bool (*is_empty) (MemoryContext context);
6768
void (*stats) (MemoryContext context,
6869
MemoryStatsPrintFunc printfunc, void *passthru,
@@ -79,7 +80,6 @@ typedef struct MemoryContextData
7980
/* these two fields are placed here to minimize alignment wastage: */
8081
bool isReset; /* T = no space alloced since last reset */
8182
bool allowInCritSection; /* allow palloc in critical section */
82-
Size mem_allocated; /* track memory allocated for this context */
8383
const MemoryContextMethods *methods; /* virtual function table */
8484
MemoryContext parent; /* NULL if no parent (toplevel context) */
8585
MemoryContext firstchild; /* head of linked list of children */

0 commit comments

Comments
 (0)