[MLton-devel] mlton/runtime GC_world.c,1.4,1.5 gc.c,1.43,1.44 gc.h,1.21,1.22
sweeks@users.sourceforge.net
sweeks@users.sourceforge.net
Tue, 23 Apr 2002 20:18:34 -0700
Update of /cvsroot/mlton/mlton/runtime
In directory usw-pr-cvs1:/tmp/cvs-serv11384/runtime
Modified Files:
GC_world.c gc.c gc.h
Log Message:
MAIL
This is a major rewrite of the heap resizing code. The code now closely follows
the idea that there should always be enough space in RAM to fit a semispace plus
the amount of live data. For details, see the comment before computeSemiSize in
gc.c. The functions that handle resizing are prepareToSpace, which runs before
a GC and allocates toSpace and resizeHeap, which runs after a GC and may shrink
the newSpace and/or deallocate old space.
I also completely rewrote the code for handling when a GC fails to produce
enough space for bytesRequested. See the code in GC_doGC for details. The new
approach involves shifting the live portion of the heap into a semispace that is
just large enough to hold it, reallocating a new semispace of the desired size,
and then shifting the live portion into the new semispace. This works better
when address space problems crop up. In doing this, I moved translateHeap from
GC_world.c to gc.c.
Index: GC_world.c
===================================================================
RCS file: /cvsroot/mlton/mlton/runtime/GC_world.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** GC_world.c 26 Mar 2002 17:27:30 -0000 1.4
--- GC_world.c 24 Apr 2002 03:18:32 -0000 1.5
***************
*** 33,65 ****
/* ------------------------------------------------- */
- /* translateHeap */
- /* ------------------------------------------------- */
-
- static void translatePointer(GC_state s, pointer *p) {
- if (1 == s->translateDirection)
- *p += s->translateDiff;
- else
- *p -= s->translateDiff;
- }
-
- /* Translate all pointers to the heap from within the stack and the heap for
- * a heap that has moved from s->base == old to s->base.
- */
- static void translateHeap(GC_state s, pointer old) {
- if (s->base == old)
- return;
- else if (s->base > old) {
- s->translateDiff = s->base - old;
- s->translateDirection = 1;
- } else {
- s->translateDiff = old - s->base;
- s->translateDirection = -1;
- }
- /* Translate globals and heap. */
- GC_foreachGlobal(s, translatePointer);
- GC_foreachPointerInRange(s, s->base, &s->frontier, translatePointer);
- }
-
- /* ------------------------------------------------- */
/* GC_loadWorld */
/* ------------------------------------------------- */
--- 33,36 ----
***************
*** 96,100 ****
* changes pointers in all of them.
*/
! translateHeap(s, base);
GC_setStack(s);
/* Allocate toSpace. We at least must do this if s->useFixedHeap. */
--- 67,71 ----
* changes pointers in all of them.
*/
! GC_translateHeap(s, base, s->base, heapSize);
GC_setStack(s);
/* Allocate toSpace. We at least must do this if s->useFixedHeap. */
Index: gc.c
===================================================================
RCS file: /cvsroot/mlton/mlton/runtime/gc.c,v
retrieving revision 1.43
retrieving revision 1.44
diff -C2 -d -r1.43 -r1.44
*** gc.c 19 Apr 2002 17:06:40 -0000 1.43
--- gc.c 24 Apr 2002 03:18:32 -0000 1.44
***************
*** 23,26 ****
--- 23,29 ----
#endif
+ typedef unsigned long long W64;
+ typedef unsigned long W32;
+
#define METER FALSE /* Displays distribution of object sizes at program exit. */
***************
*** 36,39 ****
--- 39,43 ----
enum {
+ BACKOFF_TRIES = 20,
BOGUS_EXN_STACK = 0xFFFFFFFF,
BOGUS_POINTER = 0x1,
***************
*** 60,63 ****
--- 64,71 ----
} while (0)
+ static inline ulong meg (uint n) {
+ return n / (1024ul * 1024ul);
+ }
+
static inline uint toBytes(uint n) {
return n << 2;
***************
*** 211,214 ****
--- 219,230 ----
#endif
+ static inline void releaseToSpace (GC_state s) {
+ if (s->messages)
+ fprintf (stderr, "Releasing to space.\n");
+ release (s->toBase, s->toSize);
+ s->toBase = NULL;
+ s->toSize = 0;
+ }
+
/* ------------------------------------------------- */
/* roundPage */
***************
*** 419,475 ****
/* ------------------------------------------------- */
! typedef unsigned long long W64;
! typedef unsigned long W32;
! static inline ulong meg (uint n) {
! return n / (1024ul * 1024ul);
! }
! /* computeSemiSize returns the amount of space needed for a semispace,
! * given that live is the number of bytes that will be coped into the space
! * and used is the amount used by the other semispace.
! * It will attempt to make the size live * s->liveRatio, but will not
! * violate the invariant that fromSize + toSize <= maxHeapSize. It will also
! * back off in the case that more space is needed than available RAM.
*
! * It is careful not to overflow when doing the multiply.
*/
- static uint
- computeSemiSize(GC_state s, W64 live, uint used, int try)
- {
- W64 neededLong;
- uint needed;
! assert(not s->useFixedHeap);
! neededLong = live * s->liveRatio;
! if (neededLong <= (W64)s->maxSemi)
! needed = roundPage(s, (W32)neededLong);
! else {
! W64 maybe;
! uint n;
! static double ks[13] = {1.99, 1.99, 1.8, 1.7, 1.6, 1.5,
! 1.4, 1.3, 1.2, 1.15, 1.1, 1.05, 1.01};
! double k;
! assert (0 <= try and try < 13);
! k = ks[try];
! k = ((k-1)/2)+1;
! maybe = (W64)(ks[try] * (double)live);
! n = roundPage(s, maybe > (W64)(s->totalRam + s->totalSwap)
! ? s->totalRam + s->totalSwap
! : (W32)maybe);
! if (n <= s->maxSemi)
! n = s->maxSemi;
! else if (s->messages and try > 0)
! fprintf(stderr, "[Requested %lluMb (> %luMb) cannot be satisfied, allocating %luMb instead. Live = %luMb, k=%.2f]\n",
! neededLong / (1024 * 1024),
! meg(s->maxSemi),
! meg(n), meg(live), ks[try]);
! needed = n;
! }
! if (s->maxHeapSize > 0 and needed > s->maxHeapSize - used)
! return roundPage(s, s->maxHeapSize - used);
else
! return needed;
}
--- 435,483 ----
/* ------------------------------------------------- */
! #define LIVE_RATIO_MIN 1.25
! enum {
! LIVE_RATIO = 8, /* The desired live ratio. */
! };
! /*
! * For computing the semispace size (y) based on the live amount (x), there are
! * three possibilities, depending on x.
*
! * Let R = s->ramSlop * s->totalRam
! *
! * Case 1: x * (1 + LIVE_RATIO) <= R
! * The semispace will easily fit in memory with the live ratio and
! * there will be enough space to do a GC in memory, which requires having
! * the entire old space (of size y = LIVE_RATIO * x) plus the amount of
! * live data in memory (x) in new space.
! * In this case, set y = x * LIVE_RATIO.
! *
! * Case 2: R < x * (1 + LIVE_RATIO) and x * (1 + LIVE_RATIO_MIN) <= R
! * The semispace will not fit into memory with the live ratio, but there
! * is still enough space that we can hope to do the GC in memory if
! * we use a smaller live ratio.
! * In this case set y = R - x. Thus, x + y = R, and we can still do the
! * GC in memory.
! *
! * Case 3: R < x * (1 + LIVE_RATIO_MIN)
! * Trying to do the GC in memory would require too small of a live ratio,
! * so we're gonna page. Use a small live ratio to keep the working set
! * small.
! * In this case, set y = LIVE_RATIO_MIN * x.
*/
! static W32 computeSemiSize (GC_state s, W64 live) {
! W32 res;
! if (live <= s->liveThresh1)
! res = min (live * LIVE_RATIO, s->halfMem);
! else if (live <= s->liveThresh2)
! res = min (s->ramSlop * s->totalRam - live, s->halfMem);
! else if (live <= s->liveThresh3)
! res = live * LIVE_RATIO_MIN;
else
! res = s->totalRam + s->totalSwap;
! return roundPage (s, res);
}
***************
*** 637,641 ****
header = *(word*)p;
! return ((ARRAY_TAG == (header & TAG_MASK))
? p + 2 * WORD_SIZE
: p + WORD_SIZE);
--- 645,649 ----
header = *(word*)p;
! return ((0x0 == (header & 0x80000000))
? p + 2 * WORD_SIZE
: p + WORD_SIZE);
***************
*** 652,656 ****
*/
! inline void
GC_foreachPointerInRange(GC_state s, pointer front, pointer *back,
GC_pointerFun f)
--- 660,664 ----
*/
! static inline void
GC_foreachPointerInRange(GC_state s, pointer front, pointer *back,
GC_pointerFun f)
***************
*** 917,923 ****
/* This toggles back and forth between high and low addresses to decrease
* the chance of virtual memory fragmentation causing an mmap to fail.
! * This is important for large (>1G) heaps.
*/
! static void *smmap_dienot(size_t length, int direction) {
int i;
void *result = (void*)-1;
--- 925,932 ----
/* This toggles back and forth between high and low addresses to decrease
* the chance of virtual memory fragmentation causing an mmap to fail.
! * This is important for large heaps.
*/
! static void *allocateSemi (GC_state s, size_t length) {
! static int direction = 1;
int i;
void *result = (void*)-1;
***************
*** 944,968 ****
MAP_PRIVATE | MAP_ANON, -1, 0);
#endif
! unless ((void*)-1 == result)
break;
}
return result;
}
! static void
! toSpace (GC_state s) {
! static int direction = 1;
! s->toBase = smmap_dienot(s->toSize, direction);
! if (s->toBase != (void*)-1) {
! direction = (direction==0);
! if (s->toSize > s->maxHeapSizeSeen)
! s->maxHeapSizeSeen = s->toSize;
! }
! }
!
! void
! GC_toSpace(GC_state s)
! {
! toSpace(s);
if (s->toBase == (void*)-1)
diee("Out of swap space");
--- 953,968 ----
MAP_PRIVATE | MAP_ANON, -1, 0);
#endif
! unless ((void*)-1 == result) {
! direction = (direction==0);
! if (s->toSize > s->maxHeapSizeSeen)
! s->maxHeapSizeSeen = s->toSize;
break;
+ }
}
return result;
}
! void GC_toSpace (GC_state s) {
! s->toBase = allocateSemi (s, s->toSize);
if (s->toBase == (void*)-1)
diee("Out of swap space");
***************
*** 1154,1158 ****
s->fromSize = roundPage(s, s->fromSize / 2);
} else {
! s->fromSize = computeSemiSize(s, size, 0, 0);
}
if (size + LIMIT_SLOP > s->fromSize)
--- 1154,1158 ----
s->fromSize = roundPage(s, s->fromSize / 2);
} else {
! s->fromSize = computeSemiSize (s, size);
}
if (size + LIMIT_SLOP > s->fromSize)
***************
*** 1175,1182 ****
/*
! * Set RAM and SWAP size. Very Linux specific.
* Note the total amount of RAM is multiplied by ramSlop so that we don't
! * use all of memory or start swapping. It used to be .95, but Linux
! * 2.2 is more aggressive about swapping.
*
* Ensure that s->totalRam + s->totalSwap < 4G.
--- 1175,1181 ----
/*
! * Set RAM and SWAP size.
* Note the total amount of RAM is multiplied by ramSlop so that we don't
! * use all of memory or start swapping.
*
* Ensure that s->totalRam + s->totalSwap < 4G.
***************
*** 1238,1242 ****
s->totalRam = ms.dwTotalPhys;
s->totalSwap = ms.dwTotalPageFile;
- s->maxSemi = roundPage(s, s->ramSlop * (double)s->totalRam / 2);
}
#endif
--- 1237,1240 ----
***************
*** 1322,1333 ****
s->maxHeapSize = 0;
s->maxHeapSizeSeen = 0;
- s->maxLive = 3;
s->maxPause = 0;
s->maxStackSizeSeen = 0;
s->messages = FALSE;
- s->minLive = 20;
s->numGCs = 0;
s->numLCs = 0;
! s->ramSlop = 0.85;
s->savedThread = BOGUS_THREAD;
s->signalHandler = BOGUS_THREAD;
--- 1320,1329 ----
s->maxHeapSize = 0;
s->maxHeapSizeSeen = 0;
s->maxPause = 0;
s->maxStackSizeSeen = 0;
s->messages = FALSE;
s->numGCs = 0;
s->numLCs = 0;
! s->ramSlop = 0.80;
s->savedThread = BOGUS_THREAD;
s->signalHandler = BOGUS_THREAD;
***************
*** 1337,1348 ****
s->startTime = currentTime();
s->summary = FALSE;
- /* The next bit is for heap resizing. */
- /* Set liveRatio (close) to the geometric mean of minLive and maxLive. */
- {
- uint i;
- for (i = s->maxLive; i * i <= s->minLive * s->maxLive; ++i)
- /* Nothing */ ;
- s->liveRatio = i;
- }
readProcessor();
worldFile = NULL;
--- 1333,1336 ----
***************
*** 1404,1411 ****
}
setMemInfo(s);
! s->maxSemi = roundPage(s, s->ramSlop * (double)s->totalRam / 2);
if (DEBUG)
! fprintf(stderr, "totalRam = %u totalSwap = %u maxSemi = %u\n",
! s->totalRam, s->totalSwap, s->maxSemi);
if (s->isOriginal)
newWorld(s);
--- 1392,1404 ----
}
setMemInfo(s);
! s->halfMem =
! roundPage (s, s->ramSlop * (s->totalRam + s->totalSwap) / 2);
! s->halfRam = roundPage (s, s->ramSlop * s->totalRam / 2);
! s->liveThresh1 = s->ramSlop * s->totalRam / (1 + LIVE_RATIO);
! s->liveThresh2 = s->ramSlop * s->totalRam / (1 + LIVE_RATIO_MIN);
! s->liveThresh3 = (s->totalRam + s->totalSwap) / LIVE_RATIO_MIN;
if (DEBUG)
! fprintf(stderr, "totalRam = %u totalSwap = %u\n",
! s->totalRam, s->totalSwap);
if (s->isOriginal)
newWorld(s);
***************
*** 1420,1423 ****
--- 1413,1449 ----
/* ------------------------------------------------- */
+ /* translateHeap */
+ /* ------------------------------------------------- */
+
+ static void translatePointer(GC_state s, pointer *p) {
+ if (1 == s->translateDirection)
+ *p += s->translateDiff;
+ else
+ *p -= s->translateDiff;
+ }
+
+ void GC_translateHeap (GC_state s, pointer from, pointer to, uint size) {
+ pointer limit;
+
+ if (s->messages)
+ fprintf (stderr, "Translating heap of size %s from 0x%x to 0x%x.\n",
+ uintToCommaString (size),
+ (uint)from, (uint)to);
+ if (from == to)
+ return;
+ else if (to > from) {
+ s->translateDiff = to - from;
+ s->translateDirection = 1;
+ } else {
+ s->translateDiff = from - to;
+ s->translateDirection = -1;
+ }
+ /* Translate globals and heap. */
+ GC_foreachGlobal (s, translatePointer);
+ limit = to + size;
+ GC_foreachPointerInRange (s, to, &limit, translatePointer);
+ }
+
+ /* ------------------------------------------------- */
/* forward */
/* ------------------------------------------------- */
***************
*** 1484,1490 ****
*/
if (s->back + size + skip > s->toLimit) {
! showMem ();
! die("Out of memory (forward).\nsize=%u skip=%u remaining=%u s->fromSize=%u s->toSize=%u headerBytes=%d objectBytes=%u header=%x\nDiagnostic: probably a RAM problem.",
! size, skip, s->toLimit - s->back, s->fromSize, s->toSize, headerBytes, objectBytes, header);
}
/* Copy the object. */
--- 1510,1519 ----
*/
if (s->back + size + skip > s->toLimit) {
! if (s->messages) {
! showMem ();
! fprintf (stderr, "size=%u skip=%u remaining=%u s->fromSize=%u s->toSize=%u headerBytes=%d objectBytes=%u header=%x\n",
! size, skip, s->toLimit - s->back, s->fromSize, s->toSize, headerBytes, objectBytes, header);
! }
! die ("Out of memory (forward).\nDiagnostic: probably a RAM problem.");
}
/* Copy the object. */
***************
*** 1540,1552 ****
/* ------------------------------------------------- */
void GC_doGC(GC_state s, uint bytesRequested, uint stackBytesRequested) {
uint gcTime;
uint size;
- W64 live;
- uint needed;
- int try;
pointer front;
struct rusage ru_start, ru_finish, ru_total;
!
assert(invariant(s));
if (DEBUG or s->messages)
--- 1569,1693 ----
/* ------------------------------------------------- */
+ static inline void prepareToSpace (GC_state s, uint bytesRequested,
+ uint stackBytesRequested) {
+ W64 needed;
+ W32 backoff, requested;
+ int i;
+
+ if (s->useFixedHeap)
+ return;
+ needed = (W64)s->bytesLive + (W64)bytesRequested
+ + (W64)stackBytesRequested;
+ requested = computeSemiSize (s, needed);
+ if (0 != s->toSize) {
+ assert (s->fromSize == s->toSize);
+ if (s->toSize < requested / 2)
+ /* The heap needs to grow. */
+ releaseToSpace (s);
+ else
+ /* The heap is fine. */
+ return;
+ }
+ assert (0 == s->toSize and NULL == s->toBase);
+ if (requested < s->fromSize)
+ requested = s->fromSize;
+ s->toSize = requested;
+ backoff = roundPage (s, requested / BACKOFF_TRIES);
+ for (i = 0; i < BACKOFF_TRIES; ++i) {
+ s->toBase = allocateSemi (s, s->toSize);
+ unless ((void*)-1 == s->toBase)
+ return;
+ s->toBase = (void*)NULL;
+ if (s->messages)
+ fprintf(stderr, "[Requested %luM cannot be satisfied, backing off by %luM (need = %luM).\n",
+ meg(s->toSize), meg(backoff), meg(needed));
+ s->toSize -= backoff;
+ }
+ if (s->messages)
+ showMem ();
+ die ("Out of swap space: cannot obtain %u bytes.", s->toSize);
+ }
+
+ static inline void resizeHeap (GC_state s, uint bytesRequested) {
+ W64 needed;
+ uint keep;
+
+ if (s->useFixedHeap)
+ return;
+ needed = (W64)s->bytesLive + bytesRequested;
+ /* Determine the size of new space (now fromSpace). */
+ if (needed <= s->liveThresh1)
+ /* If the ratio of live data to semispace size is too low,
+ * shrink new space.
+ */
+ keep = needed * 20 < (W64)s->fromSize
+ ? roundPage (s, needed * LIVE_RATIO)
+ : s->fromSize;
+ else
+ /* We're in the region where paging is relevant, so shrink
+ * the heap to whatever we think is the optimal size.
+ */
+ keep = computeSemiSize (s, needed);
+ if (keep < s->fromSize) {
+ if (DEBUG or s->messages)
+ fprintf(stderr,
+ "Shrinking new space at %x to %u bytes.\n",
+ (uint)s->base , keep);
+ decommit (s->base + keep, s->fromSize - keep);
+ s->fromSize = keep;
+ }
+ /* Determine the size of old space, and possibly unmap it. */
+ if (s->toSize < s->fromSize)
+ /* toSpace is smaller than fromSpace, so we won't be
+ * able to use it for the next GC anyways.
+ */
+ keep = 0;
+ else if (s->fromSize > s->halfRam)
+ /* Holding on to toSpace may cause swapping. */
+ keep = 0;
+ /* s->fromSize <= s->toSize and s->fromSize < s->halfRam */
+ else if (3 * needed > (W64)s->toSize)
+ /* toSpace is too small */
+ keep = 0;
+ else
+ /* toSpace is about right, so make it the same size as
+ * fromSpace.
+ */
+ keep = s->fromSize;
+ assert (keep <= s->toSize);
+ if (keep < s->toSize) {
+ if (DEBUG or s->messages)
+ fprintf(stderr,
+ "Shrinking old space at %x to %u bytes.\n",
+ (uint)s->toBase , keep);
+ assert(keep <= s->toSize);
+ if (0 == keep)
+ releaseToSpace (s);
+ else {
+ decommit(s->toBase + keep, s->toSize - keep);
+ s->toSize = keep;
+ }
+ }
+ }
+
+ #if (defined (__CYGWIN__))
+ static inline void shrinkFromSpace (GC_state s, W32 keep) {
+
+ }
+ #elif (defined (__linux__))
+ static inline void shrinkFromSpace (GC_state s, W32 keep) {
+ if (keep < s->fromSize) {
+ decommit (s->base + keep, s->fromSize - keep);
+ s->fromSize = keep;
+ }
+ }
+ #endif
+
void GC_doGC(GC_state s, uint bytesRequested, uint stackBytesRequested) {
uint gcTime;
uint size;
pointer front;
struct rusage ru_start, ru_finish, ru_total;
!
assert(invariant(s));
if (DEBUG or s->messages)
***************
*** 1554,1615 ****
bytesRequested);
fixedGetrusage(RUSAGE_SELF, &ru_start);
! live = (W64)s->bytesLive + (W64)bytesRequested
! + (W64)stackBytesRequested;
! unless (s->useFixedHeap) { /* Get toSpace ready. */
! try = 0;
! retry:
! needed = computeSemiSize (s, live, s->fromSize, try);
! /* We would like toSpace to be as big as fromSpace. Although,
! * if we are backing off (try > 1) then we will not insist on
! * this.
! */
! if (needed < s->fromSize and try <= 1)
! needed = s->fromSize;
! /* Massage toSpace so that it is of needed size. */
! if (s->toBase != NULL) {
! if (s->toSize < needed) {
! if (DEBUG or s->messages)
! fprintf(stderr, "Unmapping toSpace\n");
! release(s->toBase, s->toSize);
! s->toBase = NULL;
! } else if (s->toSize > needed) {
! uint delete;
!
! delete = s->toSize - needed;
! if (DEBUG or s->messages)
! fprintf(stderr, "Shrinking toSpace by %u\n",
! delete);
! decommit(s->toBase + needed, delete);
! }
! }
! s->toSize = needed;
! if ((void*)NULL == s->toBase) {
! toSpace(s);
! if ((void*)-1 == s->toBase) {
! s->toBase = (void*)NULL;
! if (++try < 13)
! goto retry;
! else {
! showMem ();
! die ("Out of swap space: cannot obtain %u bytes.", s->toSize);
! }
! }
! }
! }
! /* toSpace is ready. */
! assert(s->toBase != (void*)NULL);
if (DEBUG or s->messages) {
fprintf(stderr, "fromSpace = %x toSpace = %x\n",
(uint)s->base, (uint)s->toBase);
! fprintf(stderr,
! "fromSpace size = %s", uintToCommaString(s->fromSize));
! fprintf(stderr,
! " toSpace %s\n", uintToCommaString(s->toSize));
}
s->numGCs++;
s->bytesAllocated += s->frontier - s->base - s->bytesLive;
s->back = s->toBase;
s->toLimit = s->toBase + s->toSize;
- /* The actual GC. */
front = s->back;
GC_foreachGlobal(s, forward);
--- 1695,1713 ----
bytesRequested);
fixedGetrusage(RUSAGE_SELF, &ru_start);
! prepareToSpace (s, bytesRequested, stackBytesRequested);
! assert (s->toBase != (void*)NULL);
if (DEBUG or s->messages) {
fprintf(stderr, "fromSpace = %x toSpace = %x\n",
(uint)s->base, (uint)s->toBase);
! fprintf(stderr, "fromSpace size = %s",
! uintToCommaString(s->fromSize));
! fprintf(stderr, " toSpace size = %s\n",
! uintToCommaString(s->toSize));
}
s->numGCs++;
s->bytesAllocated += s->frontier - s->base - s->bytesLive;
+ /* The actual GC. */
s->back = s->toBase;
s->toLimit = s->toBase + s->toSize;
front = s->back;
GC_foreachGlobal(s, forward);
***************
*** 1634,1720 ****
if (s->bytesLive > s->maxBytesLive)
s->maxBytesLive = s->bytesLive;
! /* Resize heap, if necessary. */
! unless (s->useFixedHeap) {
! W64 needed;
! uint keep;
!
! needed = (W64)s->bytesLive + bytesRequested;
! /* Determine the size of new space (now fromSpace). */
! if (needed * s->minLive < (W64)s->fromSize) {
! /* The ratio of live data to semispace size is too low,
! * so shrink new space.
! */
! keep = roundPage(s, needed * s->liveRatio);
! } else if (s->fromSize > s->maxSemi) {
! if (2 * needed <= (W64)s->maxSemi) {
! /* The live data fits in a semispace that is half
! * of the RAM size, with a factor of two to
! * spare, so shrink down to maxSemi.
! */
! keep = s->maxSemi;
! } else {
! /* Needed is large. Allocate a factor of two
! * provided that the semispace will still fit
! * in RAM.
! */
! double mult;
! mult = (2 * needed > s->ramSlop * s->totalRam)
! ? 1.25 : 2.0;
! keep = min(s->fromSize,
! roundPage(s, (size_t)needed * mult));
! }
! } else
! /* The heap is about right -- leave new space alone. */
! keep = s->fromSize;
! assert (keep <= s->fromSize);
! if (keep < s->fromSize) {
! if (DEBUG or s->messages)
! fprintf(stderr,
! "Shrinking new space at %x to %u bytes.\n",
! (uint)s->base , keep);
! assert(keep <= s->fromSize);
! decommit(s->base + keep, s->fromSize - keep);
! s->fromSize = keep;
}
! /* Determine the size of old space, and possibly unmap it. */
! if (s->toSize < s->fromSize)
! /* toSpace is smaller than fromSpace, so we won't be
! * able to use it for the next GC anyways.
! */
! keep = 0;
! else if (s->fromSize > s->maxSemi)
! /* Holding on to toSpace may cause swapping. */
! keep = 0;
! else if (s->fromSize == s->maxSemi)
! /* We fit in memory, so keep spaces at s->maxSemi. */
! keep = s->fromSize;
! /* s->fromSize <= s->toSize and s->fromSize < s->maxSemi */
! else if (needed * s->maxLive > (W64)s->toSize)
! /* toSpace is too small */
! keep = 0;
! else
! /* toSpace is about right, so make it the same size as
! * fromSpace.
! */
! keep = s->fromSize;
! assert (keep <= s->toSize);
! if (keep < s->toSize) {
! if (DEBUG or s->messages)
! fprintf(stderr,
! "Shrinking old space at %x to %u bytes.\n",
! (uint)s->toBase , keep);
! assert(keep <= s->toSize);
! if (0 == keep)
! release(s->toBase, s->toSize);
! else
! decommit(s->toBase + keep, s->toSize - keep);
! s->toSize = keep;
! if (0 == keep)
! s->toBase = NULL;
}
}
- setLimit(s);
- s->bytesCopied += s->bytesLive;
fixedGetrusage(RUSAGE_SELF, &ru_finish);
rusageMinusMax(&ru_finish, &ru_start, &ru_total);
--- 1732,1785 ----
if (s->bytesLive > s->maxBytesLive)
s->maxBytesLive = s->bytesLive;
! s->bytesCopied += s->bytesLive;
! setLimit(s);
! /* If the GC didn't create enough space, then release toSpace, shrink
! * fromSpace as much as possible, shifting it to a new location. Then
! * try to allocate the semispace again.
! */
! if (bytesRequested > s->limit - s->frontier) {
! pointer old;
! W32 keep, size;
! if (s->messages)
! fprintf (stderr, "Shifting.\n");
! unless (0 == s->toSize)
! releaseToSpace (s);
! old = s->base;
! size = s->fromSize;
! /* Allocate a new from space that is just large enough. */
! keep = roundPage (s, s->bytesLive);
! s->fromSize = keep;
! s->base = allocateSemi (s, keep);
! if ((void*)-1 == s->base) {
! if (s->messages)
! showMem ();
! die ("Out of memory. Unable to shift from space.");
}
! memcpy (s->base, old, keep);
! GC_translateHeap (s, old, s->base, s->bytesLive);
! release (old, size);
! /* Allocate a new toSpace and copy to it. */
! prepareToSpace (s, bytesRequested, stackBytesRequested);
! old = s->base;
! memcpy (s->toBase, s->base, keep);
! GC_translateHeap (s, old, s->toBase, s->bytesLive);
! release (s->base, keep);
! s->base = s->toBase;
! s->fromSize = s->toSize;
! s->toBase = NULL;
! s->toSize = 0;
! GC_setStack (s);
! s->frontier = s->base + s->bytesLive;
! setLimit (s);
! if (bytesRequested > s->limit - s->frontier) {
! if (s->messages)
! showMem ();
! die ("Out of memory.");
}
+ } else {
+ resizeHeap (s, bytesRequested);
+ setLimit (s);
}
fixedGetrusage(RUSAGE_SELF, &ru_finish);
rusageMinusMax(&ru_finish, &ru_start, &ru_total);
***************
*** 1729,1741 ****
100.0 * ((double) s->bytesLive) / size);
}
- unless (bytesRequested <= s->limit - s->frontier) {
- if (s->useFixedHeap) {
- die("Out of memory (doGC).");
- }
- if (DEBUG)
- fprintf(stderr, "Recursive call to doGC.\n");
- GC_doGC(s, bytesRequested, 0);
- }
- assert(bytesRequested <= s->limit - s->frontier);
if (DEBUG)
GC_display(s, stderr);
--- 1794,1797 ----
***************
*** 1749,1767 ****
void GC_gc(GC_state s, uint bytesRequested, bool force,
string file, int line) {
GC_enter(s);
s->currentThread->bytesNeeded = bytesRequested;
! do {
! uint stackBytesRequested;
! if (DEBUG) {
! fprintf (stderr, "%s %d: ", file, line);
! GC_display(s, stderr);
! }
stackBytesRequested =
(stackTopIsOk(s, s->currentThread->stack))
? 0
: stackBytes(2 * s->currentThread->stack->reserved);
! if (DEBUG)
fprintf(stderr, "bytesRequested = %u stackBytesRequested = %u\n",
bytesRequested, stackBytesRequested);
if (force or
(W64)(W32)s->frontier + (W64)bytesRequested
--- 1805,1823 ----
void GC_gc(GC_state s, uint bytesRequested, bool force,
string file, int line) {
+ uint stackBytesRequested;
+
GC_enter(s);
s->currentThread->bytesNeeded = bytesRequested;
! start:
stackBytesRequested =
(stackTopIsOk(s, s->currentThread->stack))
? 0
: stackBytes(2 * s->currentThread->stack->reserved);
! if (DEBUG) {
! fprintf (stderr, "%s %d: ", file, line);
fprintf(stderr, "bytesRequested = %u stackBytesRequested = %u\n",
bytesRequested, stackBytesRequested);
+ GC_display(s, stderr);
+ }
if (force or
(W64)(W32)s->frontier + (W64)bytesRequested
***************
*** 1771,1775 ****
/* This GC will grow the stack, if necessary. */
GC_doGC (s, bytesRequested, s->currentThread->stack->reserved);
- assert (bytesRequested <= s->limit - s->frontier);
} else if (not (stackTopIsOk (s, s->currentThread->stack))) {
uint size;
--- 1827,1830 ----
***************
*** 1788,1792 ****
s->currentThread->stack = stack;
GC_setStack(s);
- assert (bytesRequested <= s->limit - s->frontier);
} else {
/* Switch to the signal handler thread. */
--- 1843,1846 ----
***************
*** 1807,1813 ****
s->canHandle = 2;
switchToThread(s, s->signalHandler);
}
! } while ((W64)(W32)s->frontier + (W64)s->currentThread->bytesNeeded
! > (W64)(W32)s->limit);
/* The GC_enter and GC_leave must be outside the while loop. If they
* were inside and force == TRUE, a signal handler could intervene just
--- 1861,1869 ----
s->canHandle = 2;
switchToThread(s, s->signalHandler);
+ bytesRequested = s->currentThread->bytesNeeded;
+ if (bytesRequested > s->limit - s->frontier)
+ goto start;
}
! assert (s->currentThread->bytesNeeded <= s->limit - s->frontier);
/* The GC_enter and GC_leave must be outside the while loop. If they
* were inside and force == TRUE, a signal handler could intervene just
***************
*** 1874,1878 ****
GC_enter(s);
release(s->base, s->fromSize);
! if (s->toBase != NULL) release(s->toBase, s->toSize);
if (s->summary) {
double time;
--- 1930,1935 ----
GC_enter(s);
release(s->base, s->fromSize);
! unless (0 == s->toSize)
! releaseToSpace (s);
if (s->summary) {
double time;
Index: gc.h
===================================================================
RCS file: /cvsroot/mlton/mlton/runtime/gc.h,v
retrieving revision 1.21
retrieving revision 1.22
diff -C2 -d -r1.21 -r1.22
*** gc.h 10 Apr 2002 07:02:21 -0000 1.21
--- gc.h 24 Apr 2002 03:18:32 -0000 1.22
***************
*** 231,240 ****
bool native;
- /* Resizing contols (expressed as ratios of heapSize / live data) */
- uint minLive; /* shrink heap when bytesLive * minLive < heapSize */
- uint maxLive; /* grow heap when bytesLive * maxLive > heapSize */
- uint liveRatio; /* when resizing, set heapSize to the smallest multiple
- * of pages greater than liveRatio * numBytesLive
- */
bool useFixedHeap; /* if true, then don't resize the heap */
uint maxHeapSize; /* if zero, then unlimited,
--- 231,234 ----
***************
*** 262,265 ****
--- 256,268 ----
pointer toLimit; /* End of tospace. */
+ /* Memory */
+ uint totalRam; /* bytes */
+ uint totalSwap; /* bytes */
+ uint halfMem; /* bytes */
+ uint halfRam; /* bytes */
+ uint liveThresh1;
+ uint liveThresh2;
+ uint liveThresh3;
+
/* ------------------------------------------------- */
/* loadWorld */
***************
*** 299,305 ****
uint maxBytesLive;
float ramSlop;
- uint totalRam; /* bytes */
- uint totalSwap; /* bytes */
- uint maxSemi; /* bytes */
bool isOriginal;
uint pageSize; /* bytes */
--- 302,305 ----
***************
*** 451,458 ****
typedef void (*GC_pointerFun)(GC_state s, pointer *p);
- /* Apply f to each global pointer into the heap. */
- void GC_foreachGlobal(GC_state s, GC_pointerFun f);
- void GC_foreachPointerInRange(GC_state s, pointer front, pointer *back,
- GC_pointerFun f);
void GC_display(GC_state s, FILE *stream);
void GC_fromSpace(GC_state s);
--- 451,454 ----
***************
*** 462,465 ****
--- 458,466 ----
void GC_setStack(GC_state s);
void GC_toSpace(GC_state s);
+
+ /* Translate all pointers to the heap from within the stack and the heap for
+ * a heap that has moved from s->base == old to s->base.
+ */
+ void GC_translateHeap(GC_state s, pointer from, pointer to, uint size);
pointer GC_foreachPointerInObject(GC_state s, GC_pointerFun f, pointer p);
_______________________________________________
MLton-devel mailing list
MLton-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mlton-devel