From bcc65ac92ee7a7246bfc8d87eae85c501d8888c2 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Sat, 19 Sep 2015 16:49:58 -0600 Subject: [PATCH] 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. --- racket/src/racket/gc2/fnls.c | 115 ++++++++++++++++++++++++---------- racket/src/racket/gc2/newgc.c | 33 +++++++--- racket/src/racket/gc2/newgc.h | 3 +- 3 files changed, 109 insertions(+), 42 deletions(-) diff --git a/racket/src/racket/gc2/fnls.c b/racket/src/racket/gc2/fnls.c index c198316e9f..4a893e56b5 100644 --- a/racket/src/racket/gc2/fnls.c +++ b/racket/src/racket/gc2/fnls.c @@ -8,6 +8,7 @@ num_fnls Requires: is_finalizable_page(gc, p) + is_in_gen_half(p, gc) park */ @@ -22,6 +23,41 @@ #undef splay_insert #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 *data, void (**oldf)(void *p, void *data), void **olddata) @@ -36,8 +72,20 @@ void GC_set_finalizer(void *p, int tagged, int level, void (*f)(void *p, void *d return; } - gc->splayed_finalizers = fnl_splay((intptr_t)p, gc->splayed_finalizers); - fnl = gc->splayed_finalizers; + gc->splayed_gen0_finalizers = fnl_splay((intptr_t)p, gc->splayed_gen0_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 (oldf) *oldf = fnl->f; 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; } else { /* remove finalizer */ - if (fnl->prev) - fnl->prev->next = fnl->next; - else - gc->finalizers = fnl->next; - if (fnl->next) - fnl->next->prev = fnl->prev; - + remove_finalizer(fnl, 1, gc); --gc->num_fnls; - gc->splayed_finalizers = fnl_splay_delete((intptr_t)p, gc->splayed_finalizers); } 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[1] = NULL; - fnl->p = p; fnl->f = f; fnl->data = data; @@ -103,32 +143,43 @@ void GC_set_finalizer(void *p, int tagged, int level, void (*f)(void *p, void *d } #endif - /* push finalizer */ - 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); - + add_finalizer(fnl, 1, gc); gc->num_fnls++; } -static void reset_finalizer_tree(GCTYPE *gc) - /* After a GC, rebuild the splay tree, since object addresses - have moved. */ +static void merge_finalizer_trees(GCTYPE *gc) +/* For a full GC, move all finalizers to the gen0 list */ { - Fnl *fnl; - Fnl *prev = NULL; + Fnl *fnl, *next; - gc->splayed_finalizers = NULL; - - for (fnl = gc->finalizers; fnl; fnl = fnl->next) { - fnl->prev = prev; - gc->splayed_finalizers = fnl_splay_insert((intptr_t)fnl->p, fnl, gc->splayed_finalizers); - prev = fnl; + for (fnl = gc->finalizers; fnl; fnl = next) { + next = fnl->next; + add_finalizer(fnl, 1, gc); } + + 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); + } + +} diff --git a/racket/src/racket/gc2/newgc.c b/racket/src/racket/gc2/newgc.c index c50784dfeb..40748c32bc 100644 --- a/racket/src/racket/gc2/newgc.c +++ b/racket/src/racket/gc2/newgc.c @@ -2367,18 +2367,30 @@ static int is_finalizable_page(NewGC *gc, void *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" inline static void mark_finalizer_structs(NewGC *gc) { Fnl *fnl; - set_backtrace_source(gc, &gc->finalizers, BT_ROOT); - gcMARK2(gc->finalizers, gc); - for(fnl = gc->finalizers; fnl; fnl = fnl->next) { + set_backtrace_source(gc, &gc->gen0_finalizers, BT_ROOT); + gcMARK2(gc->gen0_finalizers, gc); + for(fnl = gc->gen0_finalizers; fnl; fnl = fnl->next) { set_backtrace_source(gc, fnl, BT_FINALIZER); 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); } @@ -2388,7 +2400,7 @@ inline static void mark_finalizer_structs(NewGC *gc) set_backtrace_source(gc, fnl, BT_FINALIZER); gcMARK2(fnl->data, 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); } } @@ -2398,10 +2410,10 @@ inline static void repair_finalizer_structs(NewGC *gc) Fnl *fnl; /* repair the base parts of the list */ - gcFIXUP2(gc->finalizers, gc); + gcFIXUP2(gc->gen0_finalizers, gc); gcFIXUP2(gc->run_queue, gc); /* 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->p, 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) { - Fnl *work = GC_resolve2(gc->finalizers, gc); + Fnl *work = GC_resolve2(gc->gen0_finalizers, gc); Fnl *prev = NULL; GCDEBUG((DEBUGOUTF, "CFNL: Checking level %i finalizers\n", level)); @@ -2432,7 +2444,7 @@ inline static void check_finalizers(NewGC *gc, int level) if (prev) prev->next = next; else - gc->finalizers = next; + gc->gen0_finalizers = next; if (next) next->prev = work->prev; 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) reset_gen1_pages_live_and_scan_boundaries(gc); + if (gc->gc_full) + merge_finalizer_trees(gc); + move_gen_half_pages_to_old(gc); init_weak_boxes(gc); diff --git a/racket/src/racket/gc2/newgc.h b/racket/src/racket/gc2/newgc.h index 36f438dbea..0e86dbc228 100644 --- a/racket/src/racket/gc2/newgc.h +++ b/racket/src/racket/gc2/newgc.h @@ -248,9 +248,10 @@ typedef struct NewGC { GC_Immobile_Box *immobile_boxes; - /* Common with CompactGC */ Fnl *finalizers; Fnl *splayed_finalizers; + Fnl *gen0_finalizers; + Fnl *splayed_gen0_finalizers; int num_fnls; void *park[2];