new collection policy
authorChristian Thaeter <ct@pipapo.org>
Mon, 8 Jan 2007 11:45:15 +0000 (12:45 +0100)
committerChristian Thaeter <ct@pipapo.org>
Mon, 8 Jan 2007 11:45:15 +0000 (12:45 +0100)
lib/acogc.c
lib/acogc.h

index 58fee19..ebcc8e5 100644 (file)
@@ -48,7 +48,6 @@ acogc_root_init (AcogcRoot self)
   REQUIRE (self);
   INFO (acogc, "self %p", self);
   llist_init (&self->factories);
-  self->collection_freq_avg = 0;
   self->allocation_counter = 0;
   self->stack = NULL;
   self->last = NULL;
@@ -96,11 +95,10 @@ acogc_root_erase (AcogcRoot self)
       /* reset factory */
       f->objects_allocated = 0;
       f->objects_used = 0;
-      f->was_free = 0;
+      f->objects_new = 0;
     }
 
   /* reset self */
-  self->collection_freq_avg = 0;
   self->allocation_counter = 0;
   self->state = ACOGC_STATE_FIRST;
   self->stack = NULL;
@@ -113,12 +111,9 @@ acogc_root_collect (AcogcRoot self, acogc_freeing_policy pol)
   NOTICE (acogc_collect, "start collection %p", self);
 
   /* we can short-circruit the collection we just did one and no user-code has been run */
-  if (self->allocation_counter != 0 || pol >= ACOGC_COLLECT_FORCEALL || pol == ACOGC_COLLECT_DONTFREE)
+  if (self->allocation_counter != 0 || pol > ACOGC_COLLECT_USER1 || pol == ACOGC_COLLECT_DONTFREE)
     {
-      /* calculate new average and reset stat */
-      self->collection_freq_avg = (self->collection_freq_avg + self->allocation_counter) / 2 + 1; 
       self->allocation_counter = 0;
-      NOTICE (acogc_collect, "start collection %p, collection_freq %lu", self, self->collection_freq_avg);
 
       /* move all previous alive objects to the tmp lists */
       LLIST_FOREACH (&self->factories, fnode)
@@ -147,11 +142,13 @@ acogc_root_collect (AcogcRoot self, acogc_freeing_policy pol)
         {
           AcogcFactory f = LLIST_TO_STRUCTP (fnode, acogc_factory, factories);
           f->objects_used = 0;
+          f->objects_new = 0;
           LLIST_FOREACH (&f->roots, i)
             {
               TRACE_DBG (acogc_collect, "root marker %p",
                        acogc_memory_from_object (LLIST_TO_STRUCTP (i, acogc_object, node)));
               acogc_object_markreally (LLIST_TO_STRUCTP (i, acogc_object, node));
+              ++f->objects_used;
             }
         }
       // and for all root->stack references
@@ -165,7 +162,7 @@ acogc_root_collect (AcogcRoot self, acogc_freeing_policy pol)
       LLIST_FOREACH (&self->factories, fnode)
         {
           AcogcFactory f = LLIST_TO_STRUCTP (fnode, acogc_factory, factories);
-          NOTICE (acogc_collect, "collected %d objects", llist_count (&f->tmp));
+          NOTICE (acogc_collect, "collected %d %s", llist_count (&f->tmp), f->factory_name);
           llist_insert_list_before (&f->tmp, &f->dead);
         }
     }
@@ -194,36 +191,34 @@ acogc_root_collect (AcogcRoot self, acogc_freeing_policy pol)
     {
       AcogcFactory f = LLIST_TO_STRUCTP (fnode, acogc_factory, factories);
 
-      unsigned free_limit = 0;
+      unsigned keep_limit = 0;
       switch (pol)
         {
         case ACOGC_COLLECT_DONTFREE:
-          free_limit = 100;
+          keep_limit = 100;
           break;
         case ACOGC_COLLECT_NORMAL:
-          free_limit = f->high_water;
+          keep_limit = f->high_water;
           break;
         case ACOGC_COLLECT_FORCEMID:
-          free_limit = (f->high_water + f->low_water)/2;
+          keep_limit = (f->high_water + f->low_water)/2;
           break;
         case ACOGC_COLLECT_FORCELOW:
-          free_limit = f->low_water;
+          keep_limit = f->low_water;
           break;
         case ACOGC_COLLECT_FORCEALL:
-          free_limit = 0;
+          keep_limit = 0;
           break;
         case ACOGC_COLLECT_USER1:
         case ACOGC_COLLECT_USER2:
         case ACOGC_COLLECT_USER3:
         case ACOGC_COLLECT_FAILED:
-          ; /*unreached*/
+          NOTREACHED;
         }
 
-      f->was_free = f->objects_allocated?100 - (f->objects_used * 100 / f->objects_allocated):0;
-      NOTICE (acogc_collect, "was free: %d", f->was_free);
-
-      while (!llist_is_empty (&f->dead) && f->objects_allocated && f->was_free > free_limit)
+      while (!llist_is_empty (&f->dead) && (f->objects_used * 100 / f->objects_allocated > keep_limit))
         {
+          NOTICE (acogc_collect, "free rate: %lu", f->objects_used * 100 / f->objects_allocated);
           AcogcObject tmp = LLIST_TO_STRUCTP (llist_get_head (&f->dead), acogc_object, node);
 
           TRACE_DBG (acogc_collect, "freeing %p", acogc_memory_from_object (tmp));
@@ -237,6 +232,7 @@ acogc_root_collect (AcogcRoot self, acogc_freeing_policy pol)
           acogc_free (&tmp);
           --f->objects_allocated;
         }
+      NOTICE (acogc_collect, "allocated %lu, used %lu, ", f->objects_allocated,f->objects_used);
     }
 
   NOTICE_DBG (acogc_collect, "collection complete");
@@ -276,8 +272,9 @@ acogc_factory_init (AcogcFactory self,
 
   self->root = root;
 
-  self->objects_allocated = self->objects_used = 0;
-  self->was_free = 0;
+  self->objects_allocated = 0;
+  self->objects_used = 0;
+  self->objects_new = 0;
   self->high_water = high_water;
   self->low_water = low_water;
   self->size = size;
@@ -294,16 +291,15 @@ acogc_factory_alloc (AcogcFactory self)
   REQUIRE (self);
   AcogcObject object;
 
-  INFO (acogc_alloc, "%s allocated: %lu in-use: %lu", self->factory_name, self->objects_allocated, self->objects_used);
+  INFO (acogc_alloc, "%s allocated: %lu", self->factory_name, self->objects_allocated);
 
   ++self->root->allocation_counter;
 
-  /* call a collection if the freelist is empty */
+  /* maybe call a collection if the freelist is empty */
   if (llist_is_empty (&self->dead) &&
-      (/* and there where enough free objects last time */
-       (self->was_free > self->low_water) ||
-       /* or we did more allocations so far than we did on average */
-       self->root->allocation_counter > self->root->collection_freq_avg))
+      self->objects_allocated
+      ? self->objects_new * 100 / self->objects_allocated > (self->low_water + self->high_water)/2
+      : 0)
     {
       acogc_root_collect (self->root, ACOGC_COLLECT_NORMAL);
     }
@@ -343,6 +339,7 @@ acogc_factory_alloc (AcogcFactory self)
   object->weakrefs = (AcogcWeakref)&object->weakrefs;
   object->state = self->root->state;
 
+  ++self->objects_new;
   ++self->objects_used;
 
   return acogc_memory_from_object (object);
@@ -355,20 +352,17 @@ acogc_mark_result
 acogc_object_markreally (AcogcObject self)
 {
  tailcall:
-  REQUIRE (self);
-
   TRACE_DBG (acogc_mark, "mark object %p, state %d", acogc_memory_from_object (self), self->state);
 
   REQUIRE (self->state != self->factory->root->state, "marking already marked object %p", acogc_memory_from_object (self));
 
   if (!self->factory->mark || self->factory->mark (acogc_memory_from_object (self)) == ACOGC_KEEP)
     {
-      if (self->state <= ACOGC_STATE_ROOT || self->state >= ACOGC_STATE_BUSY)
-        /* is a dynamically allocated object */
-        ++self->factory->objects_used;
-
-      if (self->state >= ACOGC_STATE_BUSY )
+      if (self->state >= ACOGC_STATE_BUSY)
         {
+          /* is a dynamically allocated object */
+          ++self->factory->objects_used;
+
           /* is a collectable object, store it in the alive list */
           llist_insert_tail (&self->factory->alive, &self->node);
           self->state = self->factory->root->state;
index fe899da..f3bb6ee 100644 (file)
@@ -80,6 +80,12 @@ ACOGC_DECLARE(weakref,Weakref);
 /*
   tracking pointers on the stack with the GC
 */
+struct acogc_stack_struct
+{
+  void* ptr;
+  AcogcStack prev;
+};
+
 #define ACOGC_STACK_ENTER(gcroot)                                                               \
 AcogcStack_ref acogc_stack_root = &(gcroot)->stack;                                             \
 AcogcStack acogc_stack_entry NOBUG_CLEANUP (acogc_assert_stackframeleft) = *acogc_stack_root
@@ -98,16 +104,10 @@ name.stack.prev = *acogc_stack_root;            \
 *acogc_stack_root = acogc_stack_entry;                  \
 acogc_stack_entry = (AcogcStack)&acogc_stack_entry
 
-struct acogc_stack_struct
-{
-  void* ptr;
-  AcogcStack prev;
-};
-
 void
 acogc_assert_stackframeleft (AcogcStack_ref p);
 
-/* declare a weak reference als automatic variable, asserts that the reference gets unlinked when the stackframe is left (-DEBUG_ACOGC on gcc only) */
+/* declare a weak reference als automatic variable, asserts that the reference gets unlinked when the stackframe is left */
 #define ACOGC_WEAK_REFERENCE(name) acogc_weakref name NOBUG_CLEANUP(acogc_weakref_assert_cleared) = ACOGC_WEAKREF_INITIALIZER
 #define ACOGC_WEAKREF_INITIALIZER {NULL, NULL}
 
@@ -185,7 +185,6 @@ struct acogc_root_struct
 
   AcogcStack stack;
 
-  unsigned long collection_freq_avg;    /* every how much allocations did we do a collection on average */
   unsigned long allocation_counter;     /* counts every allocation since the last collection */
 
   AcogcObject last;                     /* buffer for last-call marking*/
@@ -234,10 +233,9 @@ struct acogc_factory_struct
   llist dead;                           /* unused objects (might still be referenced by weak pointers and reinstantiated on demand) */
   llist tmp;                            /* temporary list for collection */
 
-  unsigned long objects_allocated;      /* grand number of allocated objects */
-  unsigned long objects_used;           /* number of objects in use at the last collection + freshly allocated objects */
-
-  unsigned was_free;                    /* percent of free objects at the last collection */
+  unsigned long objects_allocated;      /* grand number of objects (including free) */
+  unsigned long objects_used;           /* number of objects in use at the last collection */
+  unsigned long objects_new;            /* number of objects allocated since last collection */
 
   unsigned low_water;                   /* allocate more when less than this % of objects are unused */
   unsigned high_water;                  /* start freeing when more than this % of objects are unused */
@@ -306,9 +304,6 @@ acogc_object_from_memory (const void * const self)
   return (AcogcObject)(self - sizeof (acogc_object));
 }
 
-acogc_mark_result
-acogc_object_markreally (AcogcObject object);
-
 /*
   factories can be used to identify the type of a object
  */
@@ -319,6 +314,12 @@ acogc_object_type (const void * o)
   return acogc_object_from_memory (o)->factory;
 }
 
+/*
+  marking objects
+*/
+acogc_mark_result
+acogc_object_markreally (AcogcObject object);
+
 static inline acogc_mark_result
 acogc_object_mark (void * o)
 {
@@ -335,13 +336,14 @@ acogc_object_mark (void * o)
 
       if (object->state >= ACOGC_STATE_FIRST && object->state < object->factory->root->state)
         {
+          /* not yet marked, mark now */
           object->state = ACOGC_STATE_BUSY;
           return acogc_object_markreally (object);
         }
       else
-        return ACOGC_KEPT;
+        return ACOGC_KEPT;      /* already marked */
     }
-  return ACOGC_COLLECT;       // when o was NULL
+  return ACOGC_COLLECT;         /* when o was NULL */
 }
 
 static inline acogc_mark_result