1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-01-10 05:30:45 -08:00

When growing an arena: (i) don't create a chunk that's too small for the allocation that's going to follow; (ii) don't create a chunk that's larger than necessary.

Copied from Perforce
 Change: 190952
 ServerID: perforce.ravenbrook.com
This commit is contained in:
Gareth Rees 2016-04-11 20:33:38 +01:00
parent 86c96d8455
commit 13ec8a0e2c
2 changed files with 84 additions and 35 deletions

View file

@ -308,8 +308,7 @@ static Res VMChunkCreate(Chunk *chunkReturn, VMArena vmArena, Size size)
if (res != ResOK)
goto failBootInit;
/* Allocate and map the descriptor. */
/* See <design/arena/>.@@@@ */
/* .overhead.chunk-struct: Allocate and map the chunk structure. */
res = BootAlloc(&p, boot, sizeof(VMChunkStruct), MPS_PF_ALIGN);
if (res != ResOK)
goto failChunkAlloc;
@ -361,11 +360,13 @@ static Res VMChunkInit(Chunk chunk, BootBlock boot)
vmChunk = Chunk2VMChunk(chunk);
AVERT(BootBlock, boot);
/* .overhead.sa-mapped */
res = BootAlloc(&p, boot, BTSize(chunk->pages), MPS_PF_ALIGN);
if (res != ResOK)
goto failSaMapped;
saMapped = p;
/* .overhead.sa-pages */
res = BootAlloc(&p, boot, BTSize(chunk->pageTablePages), MPS_PF_ALIGN);
if (res != ResOK)
goto failSaPages;
@ -373,8 +374,8 @@ static Res VMChunkInit(Chunk chunk, BootBlock boot)
overheadLimit = AddrAdd(chunk->base, (Size)BootAllocated(boot));
/* Put the page table as late as possible, as in VM systems we don't want */
/* to map it. */
/* .overhead.page-table: Put the page table as late as possible, as
* in VM systems we don't want to map it. */
res = BootAlloc(&p, boot, chunk->pageTablePages << chunk->pageShift, chunk->pageSize);
if (res != ResOK)
goto failAllocPageTable;
@ -491,6 +492,64 @@ static void vmArenaTrivContracted(Arena arena, Addr base, Size size)
}
/* vmArenaChunkSize -- compute chunk size
*
* Compute the size of the smallest chunk that has size bytes of usable
* address space (that is, after all overheads are accounted for).
*
* If successful, update *chunkSizeReturn with the computed chunk size
* and return ResOK. If size is too large for a chunk, leave
* *chunkSizeReturn unchanged and return ResRESOURCE.
*/
static Res vmArenaChunkSize(Size *chunkSizeReturn, VMArena vmArena, Size size)
{
Size grainSize; /* Arena grain size. */
Shift grainShift; /* The corresponding Shift. */
Count pages; /* Number of usable pages in chunk. */
Size pageTableSize; /* Size of the page table. */
Count pageTablePages; /* Number of pages in the page table. */
Size chunkSize; /* Size of the chunk. */
Size overhead; /* Total overheads for the chunk. */
AVER(chunkSizeReturn != NULL);
AVERT(VMArena, vmArena);
AVER(size > 0);
grainSize = ArenaGrainSize(VMArena2Arena(vmArena));
grainShift = SizeLog2(grainSize);
overhead = 0;
do {
chunkSize = size + overhead;
/* .overhead.chunk-struct */
overhead = SizeAlignUp(sizeof(VMChunkStruct), MPS_PF_ALIGN);
/* .overhead.pages */
pages = chunkSize >> grainShift;
overhead += SizeAlignUp(BTSize(pages), MPS_PF_ALIGN);
/* .overhead.sa-mapped */
overhead += SizeAlignUp(BTSize(pages), MPS_PF_ALIGN);
/* .overhead.sa-pages */
pageTableSize = SizeAlignUp(pages * sizeof(PageUnion), grainSize);
pageTablePages = pageTableSize >> grainShift;
overhead += SizeAlignUp(BTSize(pageTablePages), MPS_PF_ALIGN);
/* .overhead.page-table */
overhead = SizeAlignUp(overhead, grainSize);
overhead += SizeAlignUp(pageTableSize, grainSize);
if (SizeMAX - overhead < size)
return ResRESOURCE;
} while (chunkSize < size + overhead);
*chunkSizeReturn = chunkSize;
return ResOK;
}
/* VMArenaInit -- create and initialize the VM arena
*
* .arena.init: Once the arena has been allocated, we call ArenaInit
@ -589,6 +648,19 @@ static Res VMArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args)
if (res != ResOK)
goto failChunkCreate;
#if defined(AVER_AND_CHECK_ALL)
/* Check that the computation of the chunk size in vmArenaChunkSize
* was correct, now that we have the actual chunk for comparison. */
{
Size usableSize, computedChunkSize;
usableSize = AddrOffset(PageIndexBase(chunk, chunk->allocBase),
chunk->limit);
res = vmArenaChunkSize(&computedChunkSize, vmArena, usableSize);
AVER(res == ResOK);
AVER(computedChunkSize == ChunkSize(chunk));
}
#endif
/* .zoneshift: Set the zone shift to divide the chunk into the same */
/* number of stripes as will fit into a reference set (the number of */
/* bits in a word). Fail if the chunk is so small stripes are smaller */
@ -655,42 +727,16 @@ static void VMArenaFinish(Arena arena)
}
/* vmArenaChunkSize -- choose chunk size for arena extension
*
* .vmchunk.overhead: This code still lacks a proper estimate of
* the overhead required by a vmChunk for chunkStruct, page tables
* etc. For now, estimate it as 10%. RHSK 2007-12-21
*/
static Size vmArenaChunkSize(VMArena vmArena, Size size)
{
Size fraction = 10; /* 10% -- see .vmchunk.overhead */
Size chunkSize;
Size chunkOverhead;
/* 1: use extendBy, if it is big enough for size + overhead */
chunkSize = vmArena->extendBy;
chunkOverhead = chunkSize / fraction;
if(chunkSize > size && (chunkSize - size) >= chunkOverhead)
return chunkSize;
/* 2: use size + overhead (unless it overflows SizeMAX) */
chunkOverhead = size / (fraction - 1);
if((SizeMAX - size) >= chunkOverhead)
return size + chunkOverhead;
/* 3: use SizeMAX */
return SizeMAX;
}
/* VMArenaGrow -- Extend the arena by making a new chunk
*
* The size arg specifies how much we wish to allocate after the extension.
* size specifies how much we wish to allocate after the extension.
* pref specifies the preference for the location of the allocation.
*/
static Res VMArenaGrow(Arena arena, LocusPref pref, Size size)
{
Chunk newChunk;
Size chunkSize;
Size chunkMin;
Res res;
VMArena vmArena;
@ -702,7 +748,10 @@ static Res VMArenaGrow(Arena arena, LocusPref pref, Size size)
AVERT(LocusPref, pref);
UNUSED(pref);
chunkSize = vmArenaChunkSize(vmArena, size);
res = vmArenaChunkSize(&chunkMin, vmArena, size);
if (res != ResOK)
return res;
chunkSize = vmArena->extendBy;
EVENT3(vmArenaExtendStart, size, chunkSize,
ArenaReserved(VMArena2Arena(vmArena)));
@ -711,7 +760,6 @@ static Res VMArenaGrow(Arena arena, LocusPref pref, Size size)
{
unsigned fidelity = 8; /* max fraction of addr-space we may 'waste' */
Size chunkHalf;
Size chunkMin = 4 * 1024; /* typical single page */
Size sliceSize;
if (vmArena->extendMin > chunkMin)

View file

@ -197,6 +197,7 @@ Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit, Size reserved,
chunk->reserved = reserved;
size = ChunkSize(chunk);
/* .overhead.pages */
chunk->pages = pages = size >> pageShift;
res = BootAlloc(&p, boot, (size_t)BTSize(pages), MPS_PF_ALIGN);
if (res != ResOK)