1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-03-23 07:12:12 -07:00

Merge branch/2014-09-29/reserved into the master sources.

Copied from Perforce
 Change: 188090
 ServerID: perforce.ravenbrook.com
This commit is contained in:
Gareth Rees 2015-08-07 16:33:43 +01:00
commit 84347b9bbe
11 changed files with 142 additions and 96 deletions

View file

@ -85,7 +85,6 @@ DEFINE_CLASS(AbstractArenaClass, class)
class->varargs = ArgTrivVarargs;
class->init = NULL;
class->finish = NULL;
class->reserved = NULL;
class->purgeSpare = ArenaNoPurgeSpare;
class->extend = ArenaNoExtend;
class->grow = ArenaNoGrow;
@ -113,7 +112,6 @@ Bool ArenaClassCheck(ArenaClass class)
CHECKL(FUNCHECK(class->varargs));
CHECKL(FUNCHECK(class->init));
CHECKL(FUNCHECK(class->finish));
CHECKL(FUNCHECK(class->reserved));
CHECKL(FUNCHECK(class->purgeSpare));
CHECKL(FUNCHECK(class->extend));
CHECKL(FUNCHECK(class->grow));
@ -142,9 +140,12 @@ Bool ArenaCheck(Arena arena)
CHECKD(Reservoir, &arena->reservoirStruct);
}
/* Can't check that limit>=size because we may call ArenaCheck */
/* while the size is being adjusted. */
/* .reserved.check: Would like to check that arena->committed <=
* arena->reserved, but that isn't always true in the VM arena.
* Memory is committed early on when VMChunkCreate calls vmArenaMap
* (to provide a place for the chunk struct) but is not recorded as
* reserved until ChunkInit calls ArenaChunkInsert.
*/
CHECKL(arena->committed <= arena->commitLimit);
CHECKL(arena->spareCommitted <= arena->committed);
@ -206,6 +207,7 @@ Res ArenaInit(Arena arena, ArenaClass class, Size grainSize, ArgList args)
arena->class = class;
arena->reserved = (Size)0;
arena->committed = (Size)0;
/* commitLimit may be overridden by init (but probably not */
/* as there's not much point) */
@ -454,7 +456,6 @@ void ControlFinish(Arena arena)
Res ArenaDescribe(Arena arena, mps_lib_FILE *stream, Count depth)
{
Res res;
Size reserved;
if (!TESTT(Arena, arena))
return ResFAIL;
@ -476,20 +477,9 @@ Res ArenaDescribe(Arena arena, mps_lib_FILE *stream, Count depth)
return res;
}
/* Note: this Describe clause calls a function */
reserved = ArenaReserved(arena);
res = WriteF(stream, depth + 2,
"reserved $W <-- "
"total size of address-space reserved\n",
(WriteFW)reserved,
NULL);
if (res != ResOK)
return res;
res = WriteF(stream, depth + 2,
"committed $W <-- "
"total bytes currently stored (in RAM or swap)\n",
(WriteFW)arena->committed,
"reserved $W\n", (WriteFW)arena->reserved,
"committed $W\n", (WriteFW)arena->committed,
"commitLimit $W\n", (WriteFW)arena->commitLimit,
"spareCommitted $W\n", (WriteFW)arena->spareCommitted,
"spareCommitLimit $W\n", (WriteFW)arena->spareCommitLimit,
@ -669,7 +659,10 @@ Res ControlDescribe(Arena arena, mps_lib_FILE *stream, Count depth)
}
/* ArenaChunkInsert -- insert chunk into arena's chunk tree and ring */
/* ArenaChunkInsert -- insert chunk into arena's chunk tree and ring,
* update the total reserved address space, and set the primary chunk
* if not already set.
*/
void ArenaChunkInsert(Arena arena, Chunk chunk) {
Bool inserted;
@ -687,6 +680,8 @@ void ArenaChunkInsert(Arena arena, Chunk chunk) {
arena->chunkTree = updatedTree;
RingAppend(&arena->chunkRing, &chunk->arenaRing);
arena->reserved += ChunkReserved(chunk);
/* As part of the bootstrap, the first created chunk becomes the primary
chunk. This step allows ArenaFreeLandInsert to allocate pages. */
if (arena->primary == NULL)
@ -694,6 +689,31 @@ void ArenaChunkInsert(Arena arena, Chunk chunk) {
}
/* ArenaChunkRemoved -- chunk was removed from the arena and is being
* finished, so update the total reserved address space, and unset the
* primary chunk if necessary.
*/
void ArenaChunkRemoved(Arena arena, Chunk chunk)
{
Size size;
AVERT(Arena, arena);
AVERT(Chunk, chunk);
size = ChunkReserved(chunk);
AVER(arena->reserved >= size);
arena->reserved -= size;
if (chunk == arena->primary) {
/* The primary chunk must be the last chunk to be removed. */
AVER(RingIsSingle(&arena->chunkRing));
AVER(arena->reserved == 0);
arena->primary = NULL;
}
}
/* arenaAllocPage -- allocate one page from the arena
*
* This is a primitive allocator used to allocate pages for the arena
@ -1231,7 +1251,7 @@ allDeposited:
Size ArenaReserved(Arena arena)
{
AVERT(Arena, arena);
return (*arena->class->reserved)(arena);
return arena->reserved;
}
Size ArenaCommitted(Arena arena)

View file

@ -81,8 +81,15 @@ static Bool ClientChunkCheck(ClientChunk clChunk)
ATTRIBUTE_UNUSED
static Bool ClientArenaCheck(ClientArena clientArena)
{
Arena arena;
CHECKS(ClientArena, clientArena);
CHECKD(Arena, ClientArena2Arena(clientArena));
arena = ClientArena2Arena(clientArena);
CHECKD(Arena, arena);
/* See <code/arena.c#.reserved.check> */
CHECKL(arena->committed <= arena->reserved);
CHECKL(arena->spareCommitted == 0);
return TRUE;
}
@ -125,12 +132,13 @@ static Res clientChunkCreate(Chunk *chunkReturn, ClientArena clientArena,
chunk = ClientChunk2Chunk(clChunk);
res = ChunkInit(chunk, arena, alignedBase,
AddrAlignDown(limit, ArenaGrainSize(arena)), boot);
AddrAlignDown(limit, ArenaGrainSize(arena)),
AddrOffset(base, limit), boot);
if (res != ResOK)
goto failChunkInit;
ClientArena2Arena(clientArena)->committed +=
AddrOffset(base, PageIndexBase(chunk, chunk->allocBase));
arena->committed += ChunkPagesToSize(chunk, chunk->allocBase);
BootBlockFinish(boot);
clChunk->sig = ClientChunkSig;
@ -176,8 +184,10 @@ static Res ClientChunkInit(Chunk chunk, BootBlock boot)
static Bool clientChunkDestroy(Tree tree, void *closureP, Size closureS)
{
Arena arena;
Chunk chunk;
ClientChunk clChunk;
Size size;
AVERT(Tree, tree);
AVER(closureP == UNUSED_POINTER);
@ -187,8 +197,15 @@ static Bool clientChunkDestroy(Tree tree, void *closureP, Size closureS)
chunk = ChunkOfTree(tree);
AVERT(Chunk, chunk);
arena = ChunkArena(chunk);
AVERT(Arena, arena);
clChunk = Chunk2ClientChunk(chunk);
AVERT(ClientChunk, clChunk);
AVER(chunk->pages == clChunk->freePages);
size = ChunkPagesToSize(chunk, chunk->allocBase);
AVER(arena->committed >= size);
arena->committed -= size;
clChunk->sig = SigInvalid;
ChunkFinish(chunk);
@ -324,6 +341,10 @@ static void ClientArenaFinish(Arena arena)
clientArena->sig = SigInvalid;
/* Destroying the chunks should leave nothing behind. */
AVER(arena->reserved == 0);
AVER(arena->committed == 0);
ArenaFinish(arena); /* <code/arena.c#finish.caller> */
}
@ -348,27 +369,6 @@ static Res ClientArenaExtend(Arena arena, Addr base, Size size)
}
/* ClientArenaReserved -- return the amount of reserved address space */
static Size ClientArenaReserved(Arena arena)
{
Size size;
Ring node, nextNode;
AVERT(Arena, arena);
size = 0;
/* .req.extend.slow */
RING_FOR(node, &arena->chunkRing, nextNode) {
Chunk chunk = RING_ELT(Chunk, arenaRing, node);
AVERT(Chunk, chunk);
size += ChunkSize(chunk);
}
return size;
}
/* ClientArenaPagesMarkAllocated -- Mark the pages allocated */
static Res ClientArenaPagesMarkAllocated(Arena arena, Chunk chunk,
@ -376,9 +376,12 @@ static Res ClientArenaPagesMarkAllocated(Arena arena, Chunk chunk,
Pool pool)
{
Index i;
ClientChunk clChunk;
AVERT(Arena, arena);
AVERT(Chunk, chunk);
clChunk = Chunk2ClientChunk(chunk);
AVERT(ClientChunk, clChunk);
AVER(chunk->allocBase <= baseIndex);
AVER(pages > 0);
AVER(baseIndex + pages <= chunk->pages);
@ -387,15 +390,17 @@ static Res ClientArenaPagesMarkAllocated(Arena arena, Chunk chunk,
for (i = 0; i < pages; ++i)
PageAlloc(chunk, baseIndex + i, pool);
Chunk2ClientChunk(chunk)->freePages -= pages;
arena->committed += ChunkPagesToSize(chunk, pages);
AVER(clChunk->freePages >= pages);
clChunk->freePages -= pages;
return ResOK;
}
/* ClientFree - free a region in the arena */
/* ClientArenaFree - free a region in the arena */
static void ClientFree(Addr base, Size size, Pool pool)
static void ClientArenaFree(Addr base, Size size, Pool pool)
{
Arena arena;
Chunk chunk = NULL; /* suppress "may be used uninitialized" */
@ -436,6 +441,8 @@ static void ClientFree(Addr base, Size size, Pool pool)
AVER(BTIsSetRange(chunk->allocTable, baseIndex, limitIndex));
BTResRange(chunk->allocTable, baseIndex, limitIndex);
AVER(arena->committed >= size);
arena->committed -= size;
clChunk->freePages += pages;
}
@ -451,10 +458,9 @@ DEFINE_ARENA_CLASS(ClientArenaClass, this)
this->varargs = ClientArenaVarargs;
this->init = ClientArenaInit;
this->finish = ClientArenaFinish;
this->reserved = ClientArenaReserved;
this->extend = ClientArenaExtend;
this->pagesMarkAllocated = ClientArenaPagesMarkAllocated;
this->free = ClientFree;
this->free = ClientArenaFree;
this->chunkInit = ClientChunkInit;
this->chunkFinish = ClientChunkFinish;
AVERT(ArenaClass, this);

View file

@ -323,7 +323,8 @@ static Res VMChunkCreate(Chunk *chunkReturn, VMArena vmArena, Size size)
/* Copy VM descriptor into its place in the chunk. */
VMCopy(VMChunkVM(vmChunk), vm);
res = ChunkInit(VMChunk2Chunk(vmChunk), arena, base, limit, boot);
res = ChunkInit(VMChunk2Chunk(vmChunk), arena, base, limit,
VMReserved(VMChunkVM(vmChunk)), boot);
if (res != ResOK)
goto failChunkInit;
@ -560,6 +561,7 @@ static Res VMArenaInit(Arena *arenaReturn, ArenaClass class, ArgList args)
res = ArenaInit(arena, class, grainSize, args);
if (res != ResOK)
goto failArenaInit;
arena->reserved = VMReserved(vm);
arena->committed = VMMapped(vm);
/* Copy VM descriptor into its place in the arena. */
@ -640,6 +642,7 @@ static void VMArenaFinish(Arena arena)
RingFinish(&vmArena->spareRing);
/* Destroying the chunks should leave only the arena's own VM. */
AVER(arena->reserved == VMReserved(VMArenaVM(vmArena)));
AVER(arena->committed == VMMapped(VMArenaVM(vmArena)));
vmArena->sig = SigInvalid;
@ -654,25 +657,6 @@ static void VMArenaFinish(Arena arena)
}
/* VMArenaReserved -- return the amount of reserved address space
*
* Add up the reserved space from all the chunks.
*/
static Size VMArenaReserved(Arena arena)
{
Size reserved;
Ring node, next;
reserved = 0;
RING_FOR(node, &arena->chunkRing, next) {
VMChunk vmChunk = Chunk2VMChunk(RING_ELT(Chunk, arenaRing, node));
reserved += VMReserved(VMChunkVM(vmChunk));
}
return reserved;
}
/* vmArenaChunkSize -- choose chunk size for arena extension
*
* .vmchunk.overhead: This code still lacks a proper estimate of
@ -723,7 +707,7 @@ static Res VMArenaGrow(Arena arena, LocusPref pref, Size size)
chunkSize = vmArenaChunkSize(vmArena, size);
EVENT3(vmArenaExtendStart, size, chunkSize,
VMArenaReserved(VMArena2Arena(vmArena)));
ArenaReserved(VMArena2Arena(vmArena)));
/* .chunk-create.fail: If we fail, try again with a smaller size */
{
@ -747,7 +731,7 @@ static Res VMArenaGrow(Arena arena, LocusPref pref, Size size)
for(; chunkSize > chunkHalf; chunkSize -= sliceSize) {
if(chunkSize < chunkMin) {
EVENT2(vmArenaExtendFail, chunkMin,
VMArenaReserved(VMArena2Arena(vmArena)));
ArenaReserved(VMArena2Arena(vmArena)));
return res;
}
res = VMChunkCreate(&newChunk, vmArena, chunkSize);
@ -758,7 +742,7 @@ static Res VMArenaGrow(Arena arena, LocusPref pref, Size size)
}
vmArenaGrow_Done:
EVENT2(vmArenaExtendDone, chunkSize, VMArenaReserved(VMArena2Arena(vmArena)));
EVENT2(vmArenaExtendDone, chunkSize, ArenaReserved(VMArena2Arena(vmArena)));
vmArena->extended(VMArena2Arena(vmArena),
newChunk->base,
AddrOffset(newChunk->base, newChunk->limit));
@ -806,16 +790,23 @@ static Res pageDescMap(VMChunk vmChunk, Index basePI, Index limitPI)
Size before = VMMapped(VMChunkVM(vmChunk));
Arena arena = VMArena2Arena(VMChunkVMArena(vmChunk));
Res res = SparseArrayMap(&vmChunk->pages, basePI, limitPI);
arena->committed += VMMapped(VMChunkVM(vmChunk)) - before;
Size after = VMMapped(VMChunkVM(vmChunk));
AVER(before <= after);
arena->committed += after - before;
return res;
}
static void pageDescUnmap(VMChunk vmChunk, Index basePI, Index limitPI)
{
Size size, after;
Size before = VMMapped(VMChunkVM(vmChunk));
Arena arena = VMArena2Arena(VMChunkVMArena(vmChunk));
SparseArrayUnmap(&vmChunk->pages, basePI, limitPI);
arena->committed += VMMapped(VMChunkVM(vmChunk)) - before;
after = VMMapped(VMChunkVM(vmChunk));
AVER(after <= before);
size = before - after;
AVER(arena->committed >= size);
arena->committed -= size;
}
@ -1144,7 +1135,7 @@ static void VMCompact(Arena arena, Trace trace)
AVERT(VMArena, vmArena);
AVERT(Trace, trace);
vmem1 = VMArenaReserved(arena);
vmem1 = ArenaReserved(arena);
/* Destroy chunks that are completely free, but not the primary
* chunk. See <design/arena/#chunk.delete>
@ -1154,7 +1145,7 @@ static void VMCompact(Arena arena, Trace trace)
{
Size vmem0 = trace->preTraceArenaReserved;
Size vmem2 = VMArenaReserved(arena);
Size vmem2 = ArenaReserved(arena);
/* VMCompact event: emit for all client-requested collections, */
/* plus any others where chunks were gained or lost during the */
@ -1204,7 +1195,6 @@ DEFINE_ARENA_CLASS(VMArenaClass, this)
this->varargs = VMArenaVarargs;
this->init = VMArenaInit;
this->finish = VMArenaFinish;
this->reserved = VMArenaReserved;
this->purgeSpare = VMPurgeSpare;
this->grow = VMArenaGrow;
this->free = VMFree;

View file

@ -568,6 +568,7 @@ extern Res ArenaCollect(Globals globals, int why);
extern Bool ArenaHasAddr(Arena arena, Addr addr);
extern Res ArenaAddrObject(Addr *pReturn, Arena arena, Addr addr);
extern void ArenaChunkInsert(Arena arena, Chunk chunk);
extern void ArenaChunkRemoved(Arena arena, Chunk chunk);
extern void ArenaSetEmergency(Arena arena, Bool emergency);
extern Bool ArenaEmergency(Arena arean);

View file

@ -526,7 +526,6 @@ typedef struct mps_arena_class_s {
ArenaVarargsMethod varargs;
ArenaInitMethod init;
ArenaFinishMethod finish;
ArenaReservedMethod reserved;
ArenaPurgeSpareMethod purgeSpare;
ArenaExtendMethod extend;
ArenaGrowMethod grow;
@ -714,7 +713,8 @@ typedef struct mps_arena_s {
ReservoirStruct reservoirStruct; /* <design/reservoir/> */
Size committed; /* amount of committed RAM */
Size reserved; /* total reserved address space */
Size committed; /* total committed memory */
Size commitLimit; /* client-configurable commit limit */
Size spareCommitted; /* Amount of memory in hysteresis fund */

View file

@ -120,7 +120,6 @@ typedef void (*ArenaVarargsMethod)(ArgStruct args[], va_list varargs);
typedef Res (*ArenaInitMethod)(Arena *arenaReturn,
ArenaClass class, ArgList args);
typedef void (*ArenaFinishMethod)(Arena arena);
typedef Size (*ArenaReservedMethod)(Arena arena);
typedef Size (*ArenaPurgeSpareMethod)(Arena arena, Size size);
typedef Res (*ArenaExtendMethod)(Arena arena, Addr base, Size size);
typedef Res (*ArenaGrowMethod)(Arena arena, LocusPref pref, Size size);

View file

@ -100,6 +100,7 @@ Bool ReservoirCheck(Reservoir reservoir)
}
CHECKL(SizeIsArenaGrains(reservoir->reservoirLimit, arena));
CHECKL(SizeIsArenaGrains(reservoir->reservoirSize, arena));
CHECKL(reservoir->reservoirSize <= reservoir->reservoirLimit);
return TRUE;
}

View file

@ -167,7 +167,8 @@ Bool ChunkCheck(Chunk chunk)
/* ChunkInit -- initialize generic part of chunk */
Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit, BootBlock boot)
Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit, Size reserved,
BootBlock boot)
{
Size size;
Count pages;
@ -192,6 +193,7 @@ Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit, BootBlock boot)
chunk->pageShift = pageShift = SizeLog2(chunk->pageSize);
chunk->base = base;
chunk->limit = limit;
chunk->reserved = reserved;
size = ChunkSize(chunk);
chunk->pages = pages = size >> pageShift;
@ -262,17 +264,16 @@ void ChunkFinish(Chunk chunk)
PageIndexBase(chunk, chunk->allocBase),
chunk->limit);
ArenaChunkRemoved(arena, chunk);
chunk->sig = SigInvalid;
TreeFinish(&chunk->chunkTree);
RingRemove(&chunk->arenaRing);
if (chunk->arena->primary == chunk)
chunk->arena->primary = NULL;
/* Finish all other fields before class finish, because they might be */
/* unmapped there. */
(chunk->arena->class->chunkFinish)(chunk);
(*arena->class->chunkFinish)(chunk);
}

View file

@ -148,6 +148,9 @@ typedef struct ChunkStruct {
BT allocTable; /* page allocation table */
Page pageTable; /* the page table */
Count pageTablePages; /* number of pages occupied by page table */
Size reserved; /* reserved address space for chunk (including overhead
such as losses due to alignment): must not change
(or arena reserved calculation will break) */
} ChunkStruct;
@ -159,10 +162,11 @@ typedef struct ChunkStruct {
#define ChunkSizeToPages(chunk, size) ((Count)((size) >> (chunk)->pageShift))
#define ChunkPage(chunk, pi) (&(chunk)->pageTable[pi])
#define ChunkOfTree(tree) PARENT(ChunkStruct, chunkTree, tree)
#define ChunkReserved(chunk) RVALUE((chunk)->reserved)
extern Bool ChunkCheck(Chunk chunk);
extern Res ChunkInit(Chunk chunk, Arena arena, Addr base, Addr limit,
BootBlock boot);
Size reserved, BootBlock boot);
extern void ChunkFinish(Chunk chunk);
extern Compare ChunkCompare(Tree tree, TreeKey key);
extern TreeKey ChunkKey(Tree tree);

View file

@ -23,6 +23,16 @@ Interface changes
:c:func:`mps_pool_free_size` and :c:func:`mps_pool_total_size`.
Other changes
.............
#. :c:func:`mps_arena_committed` now returns a meaningful value (the
amount of memory marked as in use in the page tables) for
:term:`client arenas`. See job001887_.
.. _job001887: https://www.ravenbrook.com/project/mps/issue/job001887/
.. _release-notes-1.114:
Release 1.114.0

View file

@ -347,9 +347,18 @@ Arena properties
``arena`` is the arena.
Returns the total amount of memory that has been committed to RAM
Returns the total amount of memory that has been committed for use
by the MPS, in :term:`bytes (1)`.
For a :term:`virtual memory arena`, this is the amount of memory
mapped to RAM by the operating system's virtual memory interface.
For a :term:`client arena`, this is the amount of memory marked as
in use in the arena's page tables. This is not particularly
meaningful by itself, but it corresponds to the amount of mapped
memory that the MPS would use if switched to a virtual memory
arena.
The committed memory is generally larger than the sum of the sizes
of the allocated :term:`blocks`. The reasons for this are:
@ -379,7 +388,7 @@ Arena properties
estimate the size of the heap.
If you want to know how much memory the MPS is using then you're
probably interested in the value :c:func:`mps_arena_committed()`
probably interested in the value :c:func:`mps_arena_committed`
:c:func:`mps_arena_spare_committed`.
The amount of committed memory can be limited with the function
@ -403,12 +412,12 @@ Arena properties
.. note::
For a client arena, the reserved address may be lower than the
sum of the :c:macro:`MPS_KEY_ARENA_SIZE` keyword argument
passed to :c:func:`mps_arena_create_k` and the ``size``
arguments passed to :c:func:`mps_arena_extend`, because the
arena may be unable to use the whole of each chunk for reasons
of alignment.
For a :term:`client arena`, the reserved address space may be
lower than the sum of the :c:macro:`MPS_KEY_ARENA_SIZE`
keyword argument passed to :c:func:`mps_arena_create_k` and
the ``size`` arguments passed to :c:func:`mps_arena_extend`,
because the arena may be unable to use the whole of each chunk
for reasons of alignment.
.. c:function:: size_t mps_arena_spare_commit_limit(mps_arena_t arena)
@ -473,6 +482,11 @@ Arena properties
functions for limiting the amount of :term:`committed <mapped>`
memory.
.. note::
:term:`Client arenas` do not use spare committed memory, and
so this function always returns 0.
.. index::
single: arena; states