From 30f3b635ca612acfd215e9283757e26f8c8f1c89 Mon Sep 17 00:00:00 2001 From: Christian Thaeter Date: Mon, 8 Jan 2007 12:45:15 +0100 Subject: [PATCH] new collection policy --- lib/acogc.c | 62 ++++++++++++++++++++++++++++--------------------------------- lib/acogc.h | 36 ++++++++++++++++++----------------- 2 files changed, 47 insertions(+), 51 deletions(-) diff --git a/lib/acogc.c b/lib/acogc.c index 58fee19..ebcc8e5 100644 --- a/lib/acogc.c +++ b/lib/acogc.c @@ -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; diff --git a/lib/acogc.h b/lib/acogc.h index fe899da..f3bb6ee 100644 --- a/lib/acogc.h +++ b/lib/acogc.h @@ -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 -- 2.11.4.GIT