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

Mps: added (untested) internals for messagetypegcstart

Copied from Perforce
 Change: 39768
 ServerID: perforce.ravenbrook.com
This commit is contained in:
David Jones 2003-02-19 13:27:16 +00:00
parent 5e4a1006a6
commit eb7fb7e384
13 changed files with 273 additions and 34 deletions

View file

@ -209,6 +209,10 @@
#define TraceLIMIT ((size_t)1)
/* I count 4 function calls to scan, 10 to copy. */
#define TraceCopyScanRATIO (1.5)
/* Length (in chars) of a char buffer used to store the reason why a
collection started in the TraceStartMessageStruct (used by
mps_message_type_gc_start). */
#define TRACE_START_MESSAGE_WHY_LEN 64
@ -316,7 +320,7 @@
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2003 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -628,8 +628,9 @@ Bool ArenaStep(Globals globals, double interval, double multiplier)
stepped = FALSE;
if (arenaShouldCollectWorld(arena, interval, multiplier,
start, clocks_per_sec)) {
ArenaStartCollect(globals);
start, clocks_per_sec))
{
ArenaStartCollect(globals, TraceStartWhyOPPORTUNISM);
arena->lastWorldCollect = start;
stepped = TRUE;
}

View file

@ -73,6 +73,10 @@ Bool MessageClassCheck(MessageClass class)
CHECKL(class->name != NULL);
CHECKL(FUNCHECK(class->delete));
CHECKL(FUNCHECK(class->finalizationRef));
CHECKL(FUNCHECK(class->gcLiveSize));
CHECKL(FUNCHECK(class->gcCondemnedSize));
CHECKL(FUNCHECK(class->gcNotCondemnedSize));
CHECKL(FUNCHECK(class->gcStartWhy));
CHECKL(class->endSig == MessageClassSig);
return TRUE;
@ -352,6 +356,14 @@ Size MessageGCNotCondemnedSize(Message message)
return (*message->class->gcNotCondemnedSize)(message);
}
const char *MessageGCStartWhy(Message message)
{
AVERT(Message, message);
AVER(message->type == MessageTypeGCSTART);
return (*message->class->gcStartWhy)(message);
}
/* type-specific stub methods */
@ -396,6 +408,16 @@ Size MessageNoGCNotCondemnedSize(Message message)
return (Size)0;
}
const char *MessageNoGCStartWhy(Message message)
{
AVERT(Message, message);
UNUSED(message);
NOTREACHED;
return NULL;
}
/* C. COPYRIGHT AND LICENSE
*

View file

@ -1,7 +1,7 @@
/* messtest.c: MESSAGE TEST
*
* $Id$
* Copyright (c) 2001 Ravenbrook Limited. See end of file for license.
* Copyright (c) 2001-2003 Ravenbrook Limited. See end of file for license.
*/
#include "mpm.h"
@ -34,7 +34,8 @@ static MessageClassStruct DFMessageClassStruct = {
MessageNoFinalizationRef, /* FinalizationRef */
MessageNoGCLiveSize, /* GCLiveSize */
MessageNoGCCondemnedSize, /* GCCondemnedSize */
MessageNoGCNotCondemnedSize, /* GCNoteCondemnedSize */
MessageNoGCNotCondemnedSize, /* GCNotCondemnedSize */
MessageNoGCStartWhy, /* GCStartWhy */
MessageClassSig /* <design/message/#class.sig.double> */
};
@ -49,6 +50,7 @@ static MessageClassStruct DGCMessageClassStruct = {
MessageNoGCLiveSize, /* GCLiveSize */
MessageNoGCCondemnedSize, /* GCCondemnedSize */
MessageNoGCNotCondemnedSize, /* GCNoteCondemnedSize */
MessageNoGCStartWhy, /* GCStartWhy */
MessageClassSig /* <design/message/#class.sig.double> */
};
@ -271,7 +273,7 @@ extern int main(int argc, char *argv[])
/* C. COPYRIGHT AND LICENSE
*
* Copyright (C) 2001-2002 Ravenbrook Limited <http://www.ravenbrook.com/>.
* Copyright (C) 2001-2003 Ravenbrook Limited <http://www.ravenbrook.com/>.
* All rights reserved. This is an open source license. Contact
* Ravenbrook for commercial licensing options.
*

View file

@ -90,6 +90,17 @@ typedef const struct SrcIdStruct {
#define STR_(x) #x
#define STR(x) STR_(x)
/* NELEMS -- counts number of elements in an array
*
* NELEMS(a) expands into an expression that is the number
* of elements in the array a.
*
* WARNING: expands a more than once (you'd have to write obviously
* perverse code for this to matter though).
*/
#define NELEMS(a) (sizeof(a)/sizeof((a)[0]))
/* DISCARD -- discards an expression, but checks syntax
*

View file

@ -309,6 +309,7 @@ extern void MessageFinalizationRef(Ref *refReturn,
extern Size MessageGCLiveSize(Message message);
extern Size MessageGCCondemnedSize(Message message);
extern Size MessageGCNotCondemnedSize(Message message);
extern const char *MessageGCStartWhy(Message message);
/* Convenience methods */
extern void MessageNoFinalizationRef(Ref *refReturn,
@ -316,6 +317,7 @@ extern void MessageNoFinalizationRef(Ref *refReturn,
extern Size MessageNoGCLiveSize(Message message);
extern Size MessageNoGCCondemnedSize(Message message);
extern Size MessageNoGCNotCondemnedSize(Message message);
extern const char *MessageNoGCStartWhy(Message message);
/* Trace Interface -- see <code/trace.c> */
@ -350,7 +352,7 @@ extern RefSet ScanStateSummary(ScanState ss);
extern Bool TraceIdCheck(TraceId id);
extern Bool TraceSetCheck(TraceSet ts);
extern Bool TraceCheck(Trace trace);
extern Res TraceCreate(Trace *traceReturn, Arena arena);
extern Res TraceCreate(Trace *traceReturn, Arena arena, int why);
extern void TraceDestroy(Trace trace);
extern Res TraceAddWhite(Trace trace, Seg seg);
@ -475,8 +477,8 @@ extern Bool (ArenaStep)(Globals globals, double interval, double multiplier);
extern void ArenaClamp(Globals globals);
extern void ArenaRelease(Globals globals);
extern void ArenaPark(Globals globals);
extern Res ArenaStartCollect(Globals globals);
extern Res ArenaCollect(Globals globals);
extern Res ArenaStartCollect(Globals globals, int why);
extern Res ArenaCollect(Globals globals, int why);
extern Bool ArenaHasAddr(Arena arena, Addr addr);
extern Res ControlInit(Arena arena);

View file

@ -200,9 +200,20 @@ typedef struct MessageClassStruct {
/* methods specific to MessageTypeGC */
MessageGCLiveSizeMethod gcLiveSize;
/* methods specific to MessageTypeGC and MessageTypeGCGen */
MessageGCCondemnedSizeMethod gcCondemnedSize;
MessageGCNotCondemnedSizeMethod gcNotCondemnedSize;
/* methods specific to MessageTypeGCStart */
MessageGCStartWhyMethod gcStartWhy;
/* methods specific to MessageTypeGCGen */
#if 0 /* @@@@ */
MessageGCGenNameMethod gcGenName;
MessageGCGenForwardMethod gcGenForward;
#endif
Sig endSig; /* <design/message/#class.sig.double> */
} MessageClassStruct;
@ -442,6 +453,20 @@ typedef struct LDStruct {
RefSet rs; /* RefSet of Add'ed references */
} LDStruct;
/* TraceStartMessage
*
* See <design/message-gc/>.
*
* Embedded in TraceStruct. */
#define TraceStartMessageSig ((Sig)0x51926535) /* SIG TRaceStartMeSsage */
typedef struct TraceStartMessageStruct {
Sig sig;
char why[TRACE_START_MESSAGE_WHY_LEN];
MessageStruct messageStruct;
} TraceStartMessageStruct;
/* ScanState
*
@ -525,6 +550,9 @@ typedef struct TraceStruct {
Size preservedInPlaceSize; /* bytes preserved in place */
STATISTIC_DECL(Count reclaimCount); /* segments reclaimed */
STATISTIC_DECL(Count reclaimSize); /* bytes reclaimed */
/* Always allocated message structure. Implements
mps_message_type_gc_start(). See <design/message-gc/> */
TraceStartMessageStruct startMessage;
} TraceStruct;

View file

@ -76,6 +76,8 @@ typedef PoolClass AbstractBufferPoolClass; /* <code/poolabs.c> */
typedef PoolClass AbstractSegBufPoolClass; /* <code/poolabs.c> */
typedef PoolClass AbstractScanPoolClass; /* <code/poolabs.c> */
typedef PoolClass AbstractCollectPoolClass; /* <code/poolabs.c> */
typedef struct TraceStartMessageStruct
*TraceStartMessage; /* <design/mesage-gc> */
typedef struct TraceStruct *Trace; /* <design/trace/> */
typedef struct ScanStateStruct *ScanState; /* <design/trace/> */
typedef struct ChainStruct *Chain; /* <design/trace/> */
@ -232,6 +234,7 @@ typedef void (*MessageFinalizationRefMethod)
typedef Size (*MessageGCLiveSizeMethod)(Message message);
typedef Size (*MessageGCCondemnedSizeMethod)(Message message);
typedef Size (*MessageGCNotCondemnedSizeMethod)(Message message);
typedef const char * (*MessageGCStartWhyMethod)(Message message);
/* Message Types -- <design/message/> and elsewhere */
@ -401,6 +404,18 @@ enum {
TraceFINISHED
};
/* TraceStart reasons. Reasons for why a trace is started. */
enum {
TraceStartWhyBASE = 1, /* not a reason, the base of the enum. */
TraceStartWhyNURSERY = TraceStartWhyBASE,
TraceStartWhyGLOBAL,
TraceStartWhyOPPORTUNISM,
TraceStartWhyCLIENT,
TraceStartWhyWALK,
TraceStartWhyLIMIT /* not a reason, the limit of the enum. */
};
/* MessageTypes -- see <design/message/> */
/* .message.types: Keep in sync with <code/mps.h#message.types> */
@ -408,6 +423,7 @@ enum {
enum {
MessageTypeFINALIZATION,
MessageTypeGC,
MessageTypeGCSTART,
MessageTypeLIMIT
};

View file

@ -65,17 +65,20 @@ enum {
MPS_RES_PARAM /* illegal user parameter value */
};
/* .message.types: Keep in sync with <code/mpmtypes.h#message.types> */
/* <a id="message.types"> Keep in sync with
* <code/mpmtypes.h#message.types> */
/* Not meant to be used by clients, they should use the macros below. */
enum {
MPS_MESSAGE_TYPE_FINALIZATION,
MPS_MESSAGE_TYPE_GC
MPS_MESSAGE_TYPE_GC,
MPS_MESSAGE_TYPE_GC_START
};
/* Message Types
* This is what clients should use. */
#define mps_message_type_finalization() MPS_MESSAGE_TYPE_FINALIZATION
#define mps_message_type_gc() MPS_MESSAGE_TYPE_GC
#define mps_message_type_gc_start() MPS_MESSAGE_TYPE_GC_START
/* Reference Ranks

View file

@ -346,7 +346,7 @@ mps_res_t mps_arena_start_collect(mps_space_t mps_space)
Res res;
Arena arena = (Arena)mps_space;
ArenaEnter(arena);
res = ArenaStartCollect(ArenaGlobals(arena));
res = ArenaStartCollect(ArenaGlobals(arena), TraceStartWhyCLIENT);
ArenaLeave(arena);
return res;
}
@ -356,7 +356,7 @@ mps_res_t mps_arena_collect(mps_space_t mps_space)
Res res;
Arena arena = (Arena)mps_space;
ArenaEnter(arena);
res = ArenaCollect(ArenaGlobals(arena));
res = ArenaCollect(ArenaGlobals(arena), TraceStartWhyCLIENT);
ArenaLeave(arena);
return res;
}

View file

@ -463,7 +463,8 @@ static MessageClassStruct MRGMessageClassStruct = {
MRGMessageFinalizationRef, /* FinalizationRef */
MessageNoGCLiveSize, /* GCLiveSize */
MessageNoGCCondemnedSize, /* GCCondemnedSize */
MessageNoGCNotCondemnedSize, /* GCNoteCondemnedSize */
MessageNoGCNotCondemnedSize, /* GCNotCondemnedSize */
MessageNoGCStartWhy, /* GCStartWhy */
MessageClassSig /* <design/message/#class.sig.double> */
};

View file

@ -12,11 +12,16 @@
SRCID(trace, "$Id$");
/* Forward declarations */
static void TraceStartMessageInit(Arena arena, TraceStartMessage tsMessage);
/* Types */
enum {traceAccountingPhaseRootScan = 1, traceAccountingPhaseSegScan,
traceAccountingPhaseSingleScan};
enum {
traceAccountingPhaseRootScan = 1,
traceAccountingPhaseSegScan,
traceAccountingPhaseSingleScan
};
typedef int traceAccountingPhase;
@ -32,7 +37,7 @@ typedef struct TraceMessageStruct {
MessageStruct messageStruct;
} TraceMessageStruct, *TraceMessage;
#define TraceMessageMessage(TraceMessage) (&((TraceMessage)->messageStruct))
#define TraceMessageMessage(traceMessage) (&((traceMessage)->messageStruct))
#define MessageTraceMessage(message) \
(PARENT(TraceMessageStruct, messageStruct, message))
@ -102,6 +107,7 @@ static MessageClassStruct TraceMessageClassStruct = {
TraceMessageLiveSize, /* GCLiveSize */
TraceMessageCondemnedSize, /* GCCondemnedSize */
TraceMessageNotCondemnedSize, /* GCNotCondemnedSize */
MessageNoGCStartWhy, /* GCStartWhy */
MessageClassSig /* <design/message/#class.sig.double> */
};
@ -119,6 +125,135 @@ static void TraceMessageInit(Arena arena, TraceMessage tMessage)
AVERT(TraceMessage, tMessage);
}
/* TraceStartMessage - manages info needed by start of trace message
(mps_message_type_gc_start).
(structure declared in <code/mpmst.h> ) */
#define TraceStartMessageMessage(traceStartMessage) \
(&((traceStartMessage)->messageStruct))
#define MessageTraceStartMessage(message) \
(PARENT(TraceStartMessageStruct, messageStruct, message))
static Bool TraceStartMessageCheck(TraceStartMessage message)
{
size_t i;
CHECKS(TraceStartMessage, message);
CHECKD(Message, TraceStartMessageMessage(message));
CHECKL(MessageGetType(TraceStartMessageMessage(message)) ==
MessageTypeGCSTART);
/* Check that why is NUL terminated. */
for(i=0; i<NELEMS(message->why); ++i) {
if(message->why[i] == 0) {
break;
}
}
CHECKL(i<NELEMS(message->why));
return TRUE;
}
static void TraceStartMessageDelete(Message message)
{
TraceStartMessage tsMessage;
AVERT(Message, message);
tsMessage = MessageTraceStartMessage(message);
AVERT(TraceStartMessage, tsMessage);
TraceStartMessageInit(MessageArena(message), tsMessage);
return;
}
static const char *TraceStartMessageWhy(Message message)
{
TraceStartMessage tsMessage;
AVERT(Message, message);
tsMessage = MessageTraceStartMessage(message);
AVERT(TraceStartMessage, tsMessage);
return tsMessage->why;
}
static MessageClassStruct TraceStartMessageClassStruct = {
MessageClassSig, /* sig */
"TraceGCStart", /* name */
TraceStartMessageDelete, /* Delete */
MessageNoFinalizationRef, /* FinalizationRef */
MessageNoGCLiveSize, /* GCLiveSize */
MessageNoGCCondemnedSize, /* GCCondemnedSize */
MessageNoGCNotCondemnedSize, /* GCNotCondemnedSize */
TraceStartMessageWhy, /* GCStartWhy */
MessageClassSig /* <design/message/#class.sig.double> */
};
static void TraceStartMessageInit(Arena arena, TraceStartMessage tsMessage)
{
AVERT(Arena, arena);
MessageInit(arena, TraceStartMessageMessage(tsMessage),
&TraceStartMessageClassStruct, MessageTypeGCSTART);
tsMessage->why[0] = '\0';
tsMessage->sig = TraceStartMessageSig;
AVERT(TraceStartMessage, tsMessage);
return;
}
/* traceStartWhyToString
*
* Converts a TraceStartWhy* code into a string description.
* s specifies the beginning of the buffer to write the string
* into, len specifies the length of the buffer.
* The string written into will be NUL terminated (truncated if
* necessary). */
static void traceStartWhyToString(char *s, size_t len, int why)
{
const char *r;
size_t i;
AVER(s);
/* len can be anything, including 0. */
AVER(TraceStartWhyBASE <= why);
AVER(why < TraceStartWhyLIMIT);
switch(why) {
case TraceStartWhyNURSERY:
r = "Nursery generation is full.";
break;
case TraceStartWhyGLOBAL:
r = "Preventing global exhaustion of memory.";
break;
case TraceStartWhyOPPORTUNISM:
r = "Opportunism.";
break;
case TraceStartWhyCLIENT:
r = "Client request.";
break;
case TraceStartWhyWALK:
r = "Walking.";
break;
default:
NOTREACHED;
r = "Unknown reason (internal error).";
break;
}
for(i=0; i<len; ++i) {
s[i] = r[i];
if(r[i] == '\0')
break;
}
s[len-1] = '\0';
return;
}
/* ScanStateCheck -- check consistency of a ScanState object */
@ -162,8 +297,9 @@ void ScanStateInit(ScanState ss, TraceSet ts, Arena arena,
ss->fix = TraceFix;
TRACE_SET_ITER(ti, trace, ts, arena)
if (trace->emergency)
if (trace->emergency) {
ss->fix = TraceFixEmergency;
}
TRACE_SET_ITER_END(ti, trace, ts, arena);
ss->rank = rank;
ss->traces = ts;
@ -580,6 +716,8 @@ static void traceFlip(Trace trace)
/* collector), so that we allocate grey or white before the flip */
/* and black afterwards. For instance, see */
/* <design/poolams/#invariant.alloc>. */
/* (surely we mean "write-barrier" not "read-barrier" above? */
/* drj 2003-02-19) */
/* Now that the mutator is black we must prevent it from reading */
/* grey objects so that it can't obtain white pointers. This is */
@ -625,7 +763,7 @@ static void traceFlip(Trace trace)
* This code is written to be adaptable to allocating Trace objects
* dynamically. */
Res TraceCreate(Trace *traceReturn, Arena arena)
Res TraceCreate(Trace *traceReturn, Arena arena, int why)
{
TraceId ti;
Trace trace;
@ -678,6 +816,9 @@ found:
trace->preservedInPlaceSize = (Size)0; /* see .message.data */
STATISTIC(trace->reclaimCount = (Count)0);
STATISTIC(trace->reclaimSize = (Size)0);
TraceStartMessageInit(arena, &trace->startMessage);
traceStartWhyToString(trace->startMessage.why,
sizeof trace->startMessage.why, why);
trace->sig = TraceSig;
arena->busyTraces = TraceSetAdd(arena->busyTraces, trace);
AVERT(Trace, trace);
@ -1373,8 +1514,9 @@ static Res rootGrey(Root root, void *p)
AVERT(Root, root);
AVERT(Trace, trace);
if (ZoneSetInter(RootSummary(root), trace->white) != ZoneSetEMPTY)
if (ZoneSetInter(RootSummary(root), trace->white) != ZoneSetEMPTY) {
RootGrey(root, trace);
}
return ResOK;
}
@ -1389,9 +1531,10 @@ void TraceStart(Trace trace, double mortality, double finishingTime)
AVERT(Trace, trace);
AVER(trace->state == TraceINIT);
AVER(0.0 <= mortality && mortality <= 1.0);
arena = trace->arena;
AVER(finishingTime >= 0.0);
arena = trace->arena;
/* From the already set up white set, derive a grey set. */
/* @@@@ Instead of iterating over all the segments, we could */
@ -1420,13 +1563,15 @@ void TraceStart(Trace trace, double mortality, double finishingTime)
/* approximation to the white set. */
if (ZoneSetInter(SegSummary(seg), trace->white) != ZoneSetEMPTY) {
PoolGrey(SegPool(seg), trace, seg);
if (TraceSetIsMember(SegGrey(seg), trace))
if (TraceSetIsMember(SegGrey(seg), trace)) {
trace->foundation += size;
}
}
if ((SegPool(seg)->class->attr & AttrGC)
&& !TraceSetIsMember(SegWhite(seg), trace))
&& !TraceSetIsMember(SegWhite(seg), trace)) {
trace->notCondemned += size;
}
}
} while (SegNext(&seg, arena, base));
}
@ -1508,9 +1653,12 @@ static void traceQuantum(Trace trace)
}
/* traceStartCollectAll: start a trace which condemns everything in
* the arena. */
* the arena.
*
* "why" is a TraceStartWhy* enum member that specifies why the
* collection is starting. */
static Res traceStartCollectAll(Trace *traceReturn, Arena arena)
static Res traceStartCollectAll(Trace *traceReturn, Arena arena, int why)
{
Trace trace;
Res res;
@ -1519,16 +1667,17 @@ static Res traceStartCollectAll(Trace *traceReturn, Arena arena)
AVERT(Arena, arena);
AVER(arena->busyTraces == TraceSetEMPTY);
res = TraceCreate(&trace, arena);
res = TraceCreate(&trace, arena, why);
AVER(res == ResOK); /* succeeds because no other trace is busy */
res = traceCondemnAll(trace);
if (res != ResOK) /* should try some other trace, really @@@@ */
goto failCondemn;
finishingTime = ArenaAvail(arena)
- trace->condemned * (1.0 - TraceTopGenMortality);
if (finishingTime < 0)
if (finishingTime < 0) {
/* Run out of time, should really try a smaller collection. @@@@ */
finishingTime = 0.0;
}
TraceStart(trace, TraceTopGenMortality, finishingTime);
*traceReturn = trace;
return ResOK;
@ -1572,7 +1721,7 @@ Size TracePoll(Globals globals)
dynamicDeferral = (double)ArenaAvail(arena) - (double)sConsTrace;
if (dynamicDeferral < 0.0) { /* start full GC */
res = traceStartCollectAll(&trace, arena);
res = traceStartCollectAll(&trace, arena, TraceStartWhyGLOBAL);
if (res != ResOK)
goto failStart;
scannedSize = traceWorkClock(trace);
@ -1596,7 +1745,7 @@ Size TracePoll(Globals globals)
if (firstTime < 0) {
double mortality;
res = TraceCreate(&trace, arena);
res = TraceCreate(&trace, arena, TraceStartWhyNURSERY);
AVER(res == ResOK);
res = ChainCondemnAuto(&mortality, firstChain, trace);
if (res != ResOK) /* should try some other trace, really @@@@ */
@ -1675,7 +1824,7 @@ void ArenaPark(Globals globals)
/* ArenaStartCollect -- start a collection of everything in the
* arena; leave unclamped. */
Res ArenaStartCollect(Globals globals)
Res ArenaStartCollect(Globals globals, int why)
{
Arena arena;
Res res;
@ -1685,7 +1834,7 @@ Res ArenaStartCollect(Globals globals)
arena = GlobalsArena(globals);
ArenaPark(globals);
res = traceStartCollectAll(&trace, arena);
res = traceStartCollectAll(&trace, arena, why);
if (res != ResOK)
goto failStart;
ArenaRelease(globals);
@ -1698,12 +1847,12 @@ failStart:
/* ArenaCollect -- collect everything in arena; leave clamped */
Res ArenaCollect(Globals globals)
Res ArenaCollect(Globals globals, int why)
{
Res res;
AVERT(Globals, globals);
res = ArenaStartCollect(globals);
res = ArenaStartCollect(globals, why);
if (res != ResOK)
return res;

View file

@ -310,7 +310,7 @@ static Res ArenaRootsWalk(Globals arenaGlobals, mps_roots_stepper_t f,
/* call the client closure. This fix method must perform no tracing */
/* operations of its own. */
res = TraceCreate(&trace, arena);
res = TraceCreate(&trace, arena, TraceStartWhyWALK);
/* Have to fail if no trace available. Unlikely due to .assume.parked. */
if (res != ResOK)
return res;