GC: separate old-generation finalizers from now ones

Avoiding a traversals of old-generation finalizers can
save a couple of milliseconds for a minor GC in DrRacket.
This commit is contained in:
Matthew Flatt 2015-09-19 16:49:58 -06:00
parent 7ff1cf3619
commit bcc65ac92e
3 changed files with 109 additions and 42 deletions

View File

@ -8,6 +8,7 @@
num_fnls num_fnls
Requires: Requires:
is_finalizable_page(gc, p) is_finalizable_page(gc, p)
is_in_gen_half(p, gc)
park park
*/ */
@ -22,6 +23,41 @@
#undef splay_insert #undef splay_insert
#undef splay_delete #undef splay_delete
static void remove_finalizer(Fnl *fnl, int gen0, GCTYPE *gc)
{
if (fnl->prev)
fnl->prev->next = fnl->next;
else {
if (gen0)
gc->gen0_finalizers = fnl->next;
else
gc->finalizers = fnl->next;
}
if (fnl->next)
fnl->next->prev = fnl->prev;
if (gen0)
gc->splayed_gen0_finalizers = fnl_splay_delete((intptr_t)fnl->p, gc->splayed_gen0_finalizers);
else
gc->splayed_finalizers = fnl_splay_delete((intptr_t)fnl->p, gc->splayed_finalizers);
}
static void add_finalizer(Fnl *fnl, int gen0, GCTYPE *gc)
{
fnl->next = (gen0 ? gc->gen0_finalizers : gc->finalizers);
fnl->prev = NULL;
if (fnl->next)
fnl->next->prev = fnl;
if (gen0) {
gc->gen0_finalizers = fnl;
gc->splayed_gen0_finalizers = fnl_splay_insert((intptr_t)fnl->p, fnl, gc->splayed_gen0_finalizers);
} else {
gc->finalizers = fnl;
gc->splayed_finalizers = fnl_splay_insert((intptr_t)fnl->p, fnl, gc->splayed_finalizers);
}
}
void GC_set_finalizer(void *p, int tagged, int level, void (*f)(void *p, void *data), void GC_set_finalizer(void *p, int tagged, int level, void (*f)(void *p, void *data),
void *data, void (**oldf)(void *p, void *data), void *data, void (**oldf)(void *p, void *data),
void **olddata) void **olddata)
@ -36,8 +72,20 @@ void GC_set_finalizer(void *p, int tagged, int level, void (*f)(void *p, void *d
return; return;
} }
gc->splayed_finalizers = fnl_splay((intptr_t)p, gc->splayed_finalizers); gc->splayed_gen0_finalizers = fnl_splay((intptr_t)p, gc->splayed_gen0_finalizers);
fnl = gc->splayed_finalizers; fnl = gc->splayed_gen0_finalizers;
if (!fnl || (fnl->p != p)) {
gc->splayed_finalizers = fnl_splay((intptr_t)p, gc->splayed_finalizers);
fnl = gc->splayed_finalizers;
if (!fnl || (fnl->p != p))
fnl = NULL;
else {
/* since we're mutating this finalizer, move it to the gen0 list and tree */
remove_finalizer(fnl, 0, gc);
add_finalizer(fnl, 1, gc);
}
}
if (fnl && (fnl->p == p)) { if (fnl && (fnl->p == p)) {
if (oldf) *oldf = fnl->f; if (oldf) *oldf = fnl->f;
if (olddata) *olddata = fnl->data; if (olddata) *olddata = fnl->data;
@ -47,15 +95,8 @@ void GC_set_finalizer(void *p, int tagged, int level, void (*f)(void *p, void *d
fnl->eager_level = level; fnl->eager_level = level;
} else { } else {
/* remove finalizer */ /* remove finalizer */
if (fnl->prev) remove_finalizer(fnl, 1, gc);
fnl->prev->next = fnl->next;
else
gc->finalizers = fnl->next;
if (fnl->next)
fnl->next->prev = fnl->prev;
--gc->num_fnls; --gc->num_fnls;
gc->splayed_finalizers = fnl_splay_delete((intptr_t)p, gc->splayed_finalizers);
} }
return; return;
} }
@ -79,7 +120,6 @@ void GC_set_finalizer(void *p, int tagged, int level, void (*f)(void *p, void *d
gc->park[0] = NULL; gc->park[0] = NULL;
gc->park[1] = NULL; gc->park[1] = NULL;
fnl->p = p; fnl->p = p;
fnl->f = f; fnl->f = f;
fnl->data = data; fnl->data = data;
@ -103,32 +143,43 @@ void GC_set_finalizer(void *p, int tagged, int level, void (*f)(void *p, void *d
} }
#endif #endif
/* push finalizer */ add_finalizer(fnl, 1, gc);
fnl->next = gc->finalizers;
fnl->prev = NULL;
if (gc->finalizers) {
gc->finalizers->prev = fnl;
}
gc->finalizers = fnl;
gc->splayed_finalizers = fnl_splay_insert((intptr_t)p, fnl, gc->splayed_finalizers);
gc->num_fnls++; gc->num_fnls++;
} }
static void reset_finalizer_tree(GCTYPE *gc) static void merge_finalizer_trees(GCTYPE *gc)
/* After a GC, rebuild the splay tree, since object addresses /* For a full GC, move all finalizers to the gen0 list */
have moved. */
{ {
Fnl *fnl; Fnl *fnl, *next;
Fnl *prev = NULL;
gc->splayed_finalizers = NULL; for (fnl = gc->finalizers; fnl; fnl = next) {
next = fnl->next;
for (fnl = gc->finalizers; fnl; fnl = fnl->next) { add_finalizer(fnl, 1, gc);
fnl->prev = prev;
gc->splayed_finalizers = fnl_splay_insert((intptr_t)fnl->p, fnl, gc->splayed_finalizers);
prev = fnl;
} }
gc->finalizers = NULL;
gc->splayed_finalizers = NULL;
} }
static void reset_finalizer_tree(GCTYPE *gc)
/* After a GC, move gen0 finalizers to the old finalizer list. Note
that the old gen0 splay tree is otherwise broken, since object
addresses have moved. */
{
Fnl *fnl, *next;
fnl = gc->gen0_finalizers;
gc->gen0_finalizers = NULL;
gc->splayed_gen0_finalizers = NULL;
for (; fnl; fnl = next) {
next = fnl->next;
if (is_in_gen_half(fnl, gc)
|| is_in_gen_half(fnl->f, gc)
|| is_in_gen_half(fnl->data, gc))
add_finalizer(fnl, 1, gc);
else
add_finalizer(fnl, 0, gc);
}
}

View File

@ -2367,18 +2367,30 @@ static int is_finalizable_page(NewGC *gc, void *p)
return !!pagemap_find_page(gc->page_maps, p); return !!pagemap_find_page(gc->page_maps, p);
} }
static int is_in_gen_half(void *p, NewGC *gc)
{
mpage *page;
if (gc->gc_full)
return 0;
page = pagemap_find_page(gc->page_maps, p);
return (page && (page->generation == AGE_GEN_HALF));
}
#include "fnls.c" #include "fnls.c"
inline static void mark_finalizer_structs(NewGC *gc) inline static void mark_finalizer_structs(NewGC *gc)
{ {
Fnl *fnl; Fnl *fnl;
set_backtrace_source(gc, &gc->finalizers, BT_ROOT); set_backtrace_source(gc, &gc->gen0_finalizers, BT_ROOT);
gcMARK2(gc->finalizers, gc); gcMARK2(gc->gen0_finalizers, gc);
for(fnl = gc->finalizers; fnl; fnl = fnl->next) { for(fnl = gc->gen0_finalizers; fnl; fnl = fnl->next) {
set_backtrace_source(gc, fnl, BT_FINALIZER); set_backtrace_source(gc, fnl, BT_FINALIZER);
gcMARK2(fnl->data, gc); gcMARK2(fnl->data, gc);
set_backtrace_source(gc, &gc->finalizers, BT_ROOT); set_backtrace_source(gc, &gc->gen0_finalizers, BT_ROOT);
gcMARK2(fnl->next, gc); gcMARK2(fnl->next, gc);
} }
@ -2388,7 +2400,7 @@ inline static void mark_finalizer_structs(NewGC *gc)
set_backtrace_source(gc, fnl, BT_FINALIZER); set_backtrace_source(gc, fnl, BT_FINALIZER);
gcMARK2(fnl->data, gc); gcMARK2(fnl->data, gc);
gcMARK2(fnl->p, gc); gcMARK2(fnl->p, gc);
set_backtrace_source(gc, &gc->finalizers, BT_ROOT); set_backtrace_source(gc, &gc->gen0_finalizers, BT_ROOT);
gcMARK2(fnl->next, gc); gcMARK2(fnl->next, gc);
} }
} }
@ -2398,10 +2410,10 @@ inline static void repair_finalizer_structs(NewGC *gc)
Fnl *fnl; Fnl *fnl;
/* repair the base parts of the list */ /* repair the base parts of the list */
gcFIXUP2(gc->finalizers, gc); gcFIXUP2(gc->gen0_finalizers, gc);
gcFIXUP2(gc->run_queue, gc); gcFIXUP2(gc->run_queue, gc);
/* then repair the stuff inside them */ /* then repair the stuff inside them */
for(fnl = gc->finalizers; fnl; fnl = fnl->next) { for(fnl = gc->gen0_finalizers; fnl; fnl = fnl->next) {
gcFIXUP2(fnl->data, gc); gcFIXUP2(fnl->data, gc);
gcFIXUP2(fnl->p, gc); gcFIXUP2(fnl->p, gc);
gcFIXUP2(fnl->next, gc); gcFIXUP2(fnl->next, gc);
@ -2416,7 +2428,7 @@ inline static void repair_finalizer_structs(NewGC *gc)
inline static void check_finalizers(NewGC *gc, int level) inline static void check_finalizers(NewGC *gc, int level)
{ {
Fnl *work = GC_resolve2(gc->finalizers, gc); Fnl *work = GC_resolve2(gc->gen0_finalizers, gc);
Fnl *prev = NULL; Fnl *prev = NULL;
GCDEBUG((DEBUGOUTF, "CFNL: Checking level %i finalizers\n", level)); GCDEBUG((DEBUGOUTF, "CFNL: Checking level %i finalizers\n", level));
@ -2432,7 +2444,7 @@ inline static void check_finalizers(NewGC *gc, int level)
if (prev) if (prev)
prev->next = next; prev->next = next;
else else
gc->finalizers = next; gc->gen0_finalizers = next;
if (next) if (next)
next->prev = work->prev; next->prev = work->prev;
work->prev = NULL; /* queue is singly-linked */ work->prev = NULL; /* queue is singly-linked */
@ -5034,6 +5046,9 @@ static void garbage_collect(NewGC *gc, int force_full, int no_full, int switchin
if (gc->gc_full) if (gc->gc_full)
reset_gen1_pages_live_and_scan_boundaries(gc); reset_gen1_pages_live_and_scan_boundaries(gc);
if (gc->gc_full)
merge_finalizer_trees(gc);
move_gen_half_pages_to_old(gc); move_gen_half_pages_to_old(gc);
init_weak_boxes(gc); init_weak_boxes(gc);

View File

@ -248,9 +248,10 @@ typedef struct NewGC {
GC_Immobile_Box *immobile_boxes; GC_Immobile_Box *immobile_boxes;
/* Common with CompactGC */
Fnl *finalizers; Fnl *finalizers;
Fnl *splayed_finalizers; Fnl *splayed_finalizers;
Fnl *gen0_finalizers;
Fnl *splayed_gen0_finalizers;
int num_fnls; int num_fnls;
void *park[2]; void *park[2];