~ chicken-core (chicken-5) 5a3f3638fe6fa7fb86fb8eea591e103db4420d1f


commit 5a3f3638fe6fa7fb86fb8eea591e103db4420d1f
Author:     Peter Bex <peter@more-magic.net>
AuthorDate: Sun Apr 19 14:50:04 2015 +0200
Commit:     Peter Bex <peter@more-magic.net>
CommitDate: Sun May 31 14:55:25 2015 +0200

    Use precise tracking of scratch space memory usage to reduce the number of "forced" minor GCs

diff --git a/chicken.h b/chicken.h
index 2ffd81d7..4595a75f 100644
--- a/chicken.h
+++ b/chicken.h
@@ -1217,8 +1217,6 @@ extern double trunc(double);
  * stack or reclaim, but in a clever way so it's only done at the
  * "end" of a C function.
  */
-#define C_scratch_usage           (C_scratchspace_top - C_scratchspace_start)
-
 #if C_STACK_GROWS_DOWNWARD
 # define C_demand(n)              (C_stress && ((C_word)(C_stack_pointer - C_stack_limit) > ((n)+C_scratch_usage)))
 # define C_stack_probe(p)         (C_stress && (((C_word *)(p)-C_scratch_usage) >= C_stack_limit))
@@ -1767,6 +1765,7 @@ C_varextern C_TLS C_word
   *C_scratchspace_start,
   *C_scratchspace_top,
   *C_scratchspace_limit,
+   C_scratch_usage,
    C_bignum_type_tag,
    C_ratnum_type_tag,
    C_cplxnum_type_tag;
diff --git a/runtime.c b/runtime.c
index 4c86e228..99fe2034 100644
--- a/runtime.c
+++ b/runtime.c
@@ -336,6 +336,7 @@ C_TLS C_word
   *C_scratchspace_start,
   *C_scratchspace_top,
   *C_scratchspace_limit,
+   C_scratch_usage,
    C_bignum_type_tag,
    C_ratnum_type_tag,
    C_cplxnum_type_tag;
@@ -829,6 +830,7 @@ int CHICKEN_initialize(int heap, int stack, int symbols, void *toplevel)
   C_scratchspace_start = NULL;
   C_scratchspace_top = NULL;
   C_scratchspace_limit = NULL;
+  C_scratch_usage = 0;
   scratchspace_size = 0;
   live_finalizer_count = 0;
   allocated_finalizer_count = 0;
@@ -2904,13 +2906,13 @@ C_regparm C_word C_fcall C_scratch_alloc(C_uword size)
   
   if (C_scratchspace_top + size + 2 >= C_scratchspace_limit) {
     C_word *new_scratch_start, *new_scratch_top, *new_scratch_limit;
-    C_uword needed = scratchspace_size + size + 2,
-            new_size = nmax(scratchspace_size, DEFAULT_SCRATCH_SPACE_SIZE);
+    C_uword needed = C_scratch_usage + size + 2,
+            new_size = nmax(scratchspace_size << 1, 2UL << C_ilen(needed));
 
-    /* Increase by a factor of 2^n so we can store the requested size */
-    while (new_size < needed) new_size <<= 1;
+    /* Shrink if the needed size is much smaller, but not below minimum */
+    if (needed < (new_size >> 4)) new_size >>= 1;
+    new_size = nmax(new_size, DEFAULT_SCRATCH_SPACE_SIZE);
     
-  scratchspace_realloc:
     /* TODO: Maybe we should work with two semispaces to reduce mallocs? */
     new_scratch_start = (C_word *)C_malloc(C_wordstobytes(new_size));
     if (new_scratch_start == NULL)
@@ -2992,14 +2994,9 @@ C_regparm C_word C_fcall C_scratch_alloc(C_uword size)
     C_scratchspace_start = new_scratch_start;
     C_scratchspace_top = new_scratch_top;
     C_scratchspace_limit = new_scratch_limit;
+    /* Scratch space is now tightly packed */
+    C_scratch_usage = (new_scratch_top - new_scratch_start);
     scratchspace_size = new_size;
-
-    needed = nmax(C_scratch_usage + size + 2, DEFAULT_SCRATCH_SPACE_SIZE);
-    /* Allow scratch space to shrink if we go below an eighth of its usage */
-    if (needed < (new_size >> 3)) {
-      new_size = nmax(new_size >> 2, DEFAULT_SCRATCH_SPACE_SIZE);
-      goto scratchspace_realloc;
-    }
   }
   assert(C_scratchspace_top + size + 2 <= C_scratchspace_limit);
 
@@ -3007,6 +3004,8 @@ C_regparm C_word C_fcall C_scratch_alloc(C_uword size)
   *(C_scratchspace_top+1) = (C_word)NULL; /* Nothing points here 'til mutated */
   result = (C_word)(C_scratchspace_top+2);
   C_scratchspace_top += size + 2;
+  /* This will only be marked as "used" when it's claimed by a pointer */
+  /* C_scratch_usage += size + 2; */
   return result;
 }
 
@@ -3062,7 +3061,10 @@ C_migrate_buffer_object(C_word **ptr, C_word *start, C_word *end, C_word obj)
             C_word *sp = (C_word *)slot;
 
             if (*(sp-1) == ALIGNMENT_HOLE_MARKER) --sp;
+            if (*(sp-1) != (C_word)NULL && p == NULL)
+              C_scratch_usage -= *(sp-2) + 2;
             *(sp-1) = (C_word)p; /* This is why we traverse even if p = NULL */
+
             *data = C_SCHEME_UNBOUND; /* Ensure old reference is killed dead */
           }
         } else { /* Slot is not a scratchspace object: check sub-objects */
@@ -3087,6 +3089,10 @@ C_regparm C_word C_fcall C_mutate_scratch_slot(C_word *slot, C_word val)
   assert(C_in_scratchspacep(val));
   assert(slot == NULL || C_in_stackp((C_word)slot));
   if (*(ptr-1) == ALIGNMENT_HOLE_MARKER) --ptr;
+  if (*(ptr-1) == (C_word)NULL && slot != NULL)
+    C_scratch_usage += *(ptr-2) + 2;
+  if (*(ptr-1) != (C_word)NULL && slot == NULL)
+    C_scratch_usage -= *(ptr-2) + 2;
   *(ptr-1) = (C_word)slot; /* Remember the slot pointing here, for realloc */
   if (slot != NULL) *slot = val;
   return val; 
@@ -3455,6 +3461,7 @@ C_regparm void C_fcall C_reclaim(void *trampoline, void *proc)
     C_scratchspace_start = NULL;
     C_scratchspace_top = NULL;
     C_scratchspace_limit = NULL;
+    C_scratch_usage = 0;
     scratchspace_size = 0;
   }
 
Trap