[MLton-commit] r7051

Matthew Fluet fluet at mlton.org
Wed Apr 8 05:31:33 PDT 2009


Make sizeofHeapDesired based on heap size with maps. Avoid overflow in computaton of desired heap size.
----------------------------------------------------------------------

U   mlton/trunk/runtime/gc/heap.c

----------------------------------------------------------------------

Modified: mlton/trunk/runtime/gc/heap.c
===================================================================
--- mlton/trunk/runtime/gc/heap.c	2009-04-08 12:31:28 UTC (rev 7050)
+++ mlton/trunk/runtime/gc/heap.c	2009-04-08 12:31:31 UTC (rev 7051)
@@ -1,4 +1,5 @@
-/* Copyright (C) 2005-2008 Henry Cejtin, Matthew Fluet, Suresh
+/* Copyright (C) 2009 Matthew Fluet.
+ * Copyright (C) 2005-2008 Henry Cejtin, Matthew Fluet, Suresh
  *    Jagannathan, and Stephen Weeks.
  *
  * MLton is released under a BSD-style license.
@@ -37,80 +38,109 @@
  * given that the current heap size is cs.
  */
 size_t sizeofHeapDesired (GC_state s, size_t liveSize, size_t currentSize) {
-  size_t liveWithMapsSize;
-  size_t res;
-  float withMapsRatio;
+  size_t liveMapsSize, liveWithMapsSize;
+  size_t currentMapsSize, currentWithMapsSize;
+  size_t resSize, resWithMapsSize;
+  size_t syslimSize, syslimMapsSize, syslimWithMapsSize;
+  double ratio;
 
+  syslimWithMapsSize = alignDown (SIZE_MAX, s->sysvals.pageSize);
+  syslimSize = invertSizeofCardMapAndCrossMap (s, syslimWithMapsSize);
+  syslimMapsSize = sizeofCardMapAndCrossMap (s, syslimSize);
+  assert (syslimSize + syslimMapsSize <= syslimWithMapsSize);
+
   liveSize = align (liveSize, s->sysvals.pageSize);
-  liveWithMapsSize = liveSize + sizeofCardMapAndCrossMap (s, liveSize);
+  if (syslimSize < liveSize)
+    die ("Out of memory with system-limit heap size %s.\n",
+         uintmaxToCommaString(syslimSize));
+  liveMapsSize = sizeofCardMapAndCrossMap (s, liveSize);
+  liveWithMapsSize = liveSize + liveMapsSize;
 
-  withMapsRatio = (float)s->sysvals.ram / (float)liveWithMapsSize;
-  if (withMapsRatio >= s->controls.ratios.live + s->controls.ratios.grow) {
+  assert (isAligned (currentSize, s->sysvals.pageSize));
+  currentMapsSize = sizeofCardMapAndCrossMap (s, currentSize);
+  currentWithMapsSize = currentSize + currentMapsSize;
+
+  ratio = (double)s->sysvals.ram / (double)liveWithMapsSize;
+
+  if (ratio >= s->controls.ratios.live + s->controls.ratios.grow) {
     /* Cheney copying fits in RAM with desired ratios.live. */
-    res = liveSize * s->controls.ratios.live;
+    resWithMapsSize = liveWithMapsSize * s->controls.ratios.live;
     /* If the heap is currently close in size to what we want, leave
      * it alone.  Favor growing over shrinking.
      */
-    unless (1.1 * currentSize <= res
-            or res <= .5 * currentSize)
-      res = currentSize;
+    if (0.5 * currentWithMapsSize <= resWithMapsSize
+        and resWithMapsSize <= 1.1 * currentWithMapsSize) {
+      resWithMapsSize = currentWithMapsSize;
+    } else {
+      resWithMapsSize = align (resWithMapsSize, s->sysvals.pageSize);
+    }
   } else if (s->controls.ratios.grow >= s->controls.ratios.copy
-             and withMapsRatio >= 2 * s->controls.ratios.copy) {
+             and ratio >= 2.0 * s->controls.ratios.copy) {
     /* Split RAM in half.  Round down by pageSize so that the total
      * amount of space taken isn't greater than RAM once rounding
      * happens.  This is so resizeHeapSecondary doesn't get confused
      * and free a semispace in a misguided attempt to avoid paging.
      */
-    res = alignDown (s->sysvals.ram / 2, s->sysvals.pageSize);
-  } else if (withMapsRatio >= s->controls.ratios.copy + s->controls.ratios.grow) {
+    resWithMapsSize = alignDown (s->sysvals.ram / 2, s->sysvals.pageSize);
+  } else if (ratio >= s->controls.ratios.copy + s->controls.ratios.grow) {
     /* Cheney copying fits in RAM. */
-    res = s->sysvals.ram - s->controls.ratios.grow * liveSize;
+    resWithMapsSize = s->sysvals.ram - s->controls.ratios.grow * liveWithMapsSize;
     /* If the heap isn't too much smaller than what we want, leave it
-     * alone.  On the other hand, if it is bigger we want to leave res
-     * as is so that the heap is shrunk, to try to avoid paging.
+     * alone.  On the other hand, if it is bigger we want to leave
+     * resWithMapsSize as is so that the heap is shrunk, to try to
+     * avoid paging.
      */
-    if (currentSize <= res
-        and res <= 1.1 * currentSize)
-      res = currentSize;
-  } else if (withMapsRatio >= s->controls.ratios.markCompact) {
+    if (1.0 * currentWithMapsSize <= resWithMapsSize
+        and resWithMapsSize <= 1.1 * currentWithMapsSize) {
+      resWithMapsSize = currentWithMapsSize;
+    } else {
+      resWithMapsSize = align (resWithMapsSize, s->sysvals.pageSize);
+    }
+  } else if (ratio >= s->controls.ratios.markCompact) {
     /* Mark compact fits in RAM.  It doesn't matter what the current
      * size is.  If the heap is currently smaller, we are using
      * copying and should switch to mark-compact.  If the heap is
      * currently bigger, we want to shrink back to RAM to avoid
      * paging.
      */
-    res = s->sysvals.ram;
+    resWithMapsSize = s->sysvals.ram;
   } else { /* Required live ratio. */
-    res = liveSize * s->controls.ratios.markCompact;
-    /* If the current heap is bigger than res, then shrinking always
-     * sounds like a good idea.  However, depending on what pages the
-     * VM keeps around, growing could be very expensive, if it
-     * involves paging the entire heap.  Hopefully the copy loop in
-     * growHeap will make the right thing happen.
+    double resWithMapsSizeD = liveWithMapsSize * (double)(s->controls.ratios.markCompact);
+    if (resWithMapsSizeD > (double)syslimWithMapsSize) {
+      resWithMapsSize = syslimWithMapsSize;
+    } else {
+      resWithMapsSize = align ((size_t)resWithMapsSizeD, s->sysvals.pageSize);
+    }
+    /* If the current heap is bigger than resWithMapsSize, then
+     * shrinking always sounds like a good idea.  However, depending
+     * on what pages the VM keeps around, growing could be very
+     * expensive, if it involves paging the entire heap.  Hopefully
+     * the copy loop in growHeap will make the right thing happen.
      */
   }
   if (s->controls.fixedHeap > 0) {
-    if (res > s->controls.fixedHeap / 2)
-      res = s->controls.fixedHeap;
+    if (resWithMapsSize > s->controls.fixedHeap / 2)
+      resWithMapsSize = s->controls.fixedHeap;
     else
-      res = s->controls.fixedHeap / 2;
-    if (res < liveSize)
+      resWithMapsSize = s->controls.fixedHeap / 2;
+    if (resWithMapsSize < liveWithMapsSize)
       die ("Out of memory with fixed heap size %s.",
            uintmaxToCommaString(s->controls.fixedHeap));
   } else if (s->controls.maxHeap > 0) {
-    if (res > s->controls.maxHeap)
-      res = s->controls.maxHeap;
-    if (res < liveSize)
+    if (resWithMapsSize > s->controls.maxHeap)
+      resWithMapsSize = s->controls.maxHeap;
+    if (resWithMapsSize < liveWithMapsSize)
       die ("Out of memory with max heap size %s.",
            uintmaxToCommaString(s->controls.maxHeap));
   }
+  resSize = invertSizeofCardMapAndCrossMap (s, resWithMapsSize);
   if (DEBUG_RESIZING)
     fprintf (stderr, "%s = sizeofHeapDesired (%s, %s)\n",
-             uintmaxToCommaString(res),
+             uintmaxToCommaString(resSize),
              uintmaxToCommaString(liveSize),
              uintmaxToCommaString(currentSize));
-  assert (res >= liveSize);
-  return res;
+  assert (resSize >= liveSize);
+  return resSize;
 }
 
 void releaseHeap (GC_state s, GC_heap h) {




More information about the MLton-commit mailing list