diff --git a/pkgs/racket-doc/scribblings/reference/memory.scrbl b/pkgs/racket-doc/scribblings/reference/memory.scrbl index 740124e485..b91df7dc20 100644 --- a/pkgs/racket-doc/scribblings/reference/memory.scrbl +++ b/pkgs/racket-doc/scribblings/reference/memory.scrbl @@ -199,7 +199,11 @@ execution. Otherwise, @racket[#f] is returned.} @section[#:tag "garbagecollection"]{Garbage Collection} Set the @as-index{@envvar{PLTDISABLEGC}} environment variable (to any -value) before Racket starts to disable @tech{garbage collection}. +value) before Racket starts to disable @tech{garbage collection}. Set +the @as-index{@envvar{PLT_INCREMENTAL_GC}} environment variable to +request incremental mode at all times, but calling +@racket[(collect-garbage 'incremental)] in a program with a periodic +task is generally a better mechanism for requesting incremental mode. In Racket 3m (the main variant of Racket), each garbage collection logs a message (see @secref["logging"]) at the @racket['debug] level with topic @racket['GC]. @@ -209,18 +213,28 @@ versions of Racket may use a @racket[gc-info] @tech{prefab} structure with additional fields: @racketblock[ -(struct gc-info (major? pre-amount pre-admin-amount code-amount - post-amount post-admin-amount - start-process-time end-process-time - start-time end-time) +(struct gc-info (mode pre-amount pre-admin-amount code-amount + post-amount post-admin-amount + start-process-time end-process-time + start-time end-time) #:prefab) ] @itemlist[ - @item{The @racket[major?] field indicates whether the collection was - a ``major'' collection that inspects all memory or a ``minor'' - collection that mostly inspects just recent allocations.} + @item{The @racket[mode] field is a symbol @racket['major], + @racket['minor], or @racket['incremental]; @racket['major] + indicates a collection that inspects all memory, + @racket['minor] indicates collection that mostly inspects just + recent allocations, and @racket['incremental] indicates a minor + collection that performs extra work toward the next major + collection. + + @history[#:changed "6.3.0.7" @elem{Changed first field from a + boolean (@racket[#t] for + @racket['major], @racket[#f] + for @racket['minor]) to a + mode symbol.}]} @item{The @racket[pre-amount] field reports place-local memory use (i.e., not counting the memory use of child places) in bytes at @@ -286,6 +300,7 @@ collection mode, the text has the format @elem{Processor time since startup of garbage collection's start})) ]} +@history[#:changed "6.3.0.7" @elem{Added @envvar{PLT_INCREMENTAL_GC}.}] @defproc[(collect-garbage [request (or/c 'major 'minor 'incremental) 'major]) void?]{ @@ -314,7 +329,8 @@ garbage-collection mode, depending on @racket[request]: major collections any sooner than they would occur otherwise.} @item{@racket['incremental] --- Requests that each minor - collection performs incremental work toward a major collection. + collection performs incremental work toward a major collection + (but does not request an immediate minor collection). This incremental-mode request expires at the next major collection. diff --git a/racket/src/racket/cmdline.inc b/racket/src/racket/cmdline.inc index ba53a222b3..4e0a5914ef 100644 --- a/racket/src/racket/cmdline.inc +++ b/racket/src/racket/cmdline.inc @@ -1542,6 +1542,9 @@ static int run_from_cmd_line(int argc, char *_argv[], if (getenv("PLTDISABLEGC")) { scheme_enable_garbage_collection(0); } + if (getenv("PLT_INCREMENTAL_GC")) { + scheme_incremental_garbage_collection(1); + } #endif scheme_set_logging_spec(syslog_level, stderr_level); diff --git a/racket/src/racket/gc2/gc2.h b/racket/src/racket/gc2/gc2.h index 19d46c00e1..f5e6d68bdc 100644 --- a/racket/src/racket/gc2/gc2.h +++ b/racket/src/racket/gc2/gc2.h @@ -31,7 +31,7 @@ typedef int (*Fixup_Proc)(void *obj); typedef int (*Fixup2_Proc)(void *obj, struct NewGC *); typedef void (*GC_collect_start_callback_Proc)(void); typedef void (*GC_collect_end_callback_Proc)(void); -typedef void (*GC_collect_inform_callback_Proc)(int master_gc, int major_gc, +typedef void (*GC_collect_inform_callback_Proc)(int master_gc, int major_gc, int inc_gc, intptr_t pre_used, intptr_t post_used, intptr_t pre_admin, intptr_t post_admin, intptr_t post_child_places_used); @@ -174,6 +174,10 @@ GC2_EXTERN void GC_request_incremental_mode(void); /* Requests incremental mode; lasts until the next major collection. */ +GC2_EXTERN void GC_set_incremental_mode(int on); +/* + Sets whether incremental mode is the default. */ + GC2_EXTERN void GC_free_all(void); /* Releases all memory, removes all signal handlers, etc. diff --git a/racket/src/racket/gc2/newgc.c b/racket/src/racket/gc2/newgc.c index f46ec13c8f..45cb73cf02 100644 --- a/racket/src/racket/gc2/newgc.c +++ b/racket/src/racket/gc2/newgc.c @@ -252,7 +252,7 @@ MAYBE_UNUSED static void GCVERBOSEprintf(NewGC *gc, const char *fmt, ...) { #define AGE_GEN_0_TO_GEN_HALF(gc) ((gc)->memory_in_use > (GEN0_MAX_SIZE * 8)) /* Incremental mode */ -#define ALWAYS_COLLECT_INCREMENTAL_ON_MINOR 0 +static int always_collect_incremental_on_minor = 0; #define INCREMENTAL_COLLECT_FUEL_PER_100M (24 * 1024) #define INCREMENTAL_REPAIR_FUEL_PER_100M 512 @@ -3558,6 +3558,11 @@ void GC_request_incremental_mode(void) gc->incremental_requested = 1; } +void GC_set_incremental_mode(int on) +{ + always_collect_incremental_on_minor = 1; +} + void GC_enable_collection(int on) { NewGC *gc = GC_get_GC(); @@ -5847,7 +5852,7 @@ static void garbage_collect(NewGC *gc, int force_full, int no_full, int switchin gc->need_fixup = 0; do_incremental = (!gc->gc_full && (gc->incremental_requested - || ALWAYS_COLLECT_INCREMENTAL_ON_MINOR)); + || always_collect_incremental_on_minor)); if (!postmaster_and_place_gc(gc)) do_incremental = 0; @@ -6053,7 +6058,7 @@ static void garbage_collect(NewGC *gc, int force_full, int no_full, int switchin is_master = (gc == MASTERGC); #endif park_for_inform_callback(gc); - gc->GC_collect_inform_callback(is_master, gc->gc_full, + gc->GC_collect_inform_callback(is_master, gc->gc_full, do_incremental, old_mem_use + old_gen0, gc->memory_in_use, old_mem_allocated, mmu_memory_allocated(gc->mmu)+gc->phantom_count, gc->child_gc_total); @@ -6135,7 +6140,7 @@ static void garbage_collect(NewGC *gc, int force_full, int no_full, int switchin if (sub_lmi.ran) { if (gc->GC_collect_inform_callback) { park_for_inform_callback(gc); - gc->GC_collect_inform_callback(1, sub_lmi.full, + gc->GC_collect_inform_callback(1, sub_lmi.full, 0, sub_lmi.pre_used, sub_lmi.post_used, sub_lmi.pre_admin, sub_lmi.post_admin, 0); diff --git a/racket/src/racket/include/mzwin.def b/racket/src/racket/include/mzwin.def index f76f16ac0f..ede22b69ab 100644 --- a/racket/src/racket/include/mzwin.def +++ b/racket/src/racket/include/mzwin.def @@ -226,6 +226,7 @@ EXPORTS scheme_collect_garbage scheme_collect_garbage_minor scheme_enable_garbage_collection + scheme_incremental_garbage_collection scheme_malloc_immobile_box scheme_free_immobile_box scheme_add_gc_callback diff --git a/racket/src/racket/include/mzwin3m.def b/racket/src/racket/include/mzwin3m.def index 844b694200..8cada188d5 100644 --- a/racket/src/racket/include/mzwin3m.def +++ b/racket/src/racket/include/mzwin3m.def @@ -234,6 +234,7 @@ EXPORTS scheme_collect_garbage scheme_collect_garbage_minor scheme_enable_garbage_collection + scheme_incremental_garbage_collection GC_variable_stack GC_register_traversers GC_resolve diff --git a/racket/src/racket/include/racket.exp b/racket/src/racket/include/racket.exp index 831814d7b4..3cf3a31ea3 100644 --- a/racket/src/racket/include/racket.exp +++ b/racket/src/racket/include/racket.exp @@ -237,6 +237,7 @@ scheme_gc_ptr_ok scheme_collect_garbage scheme_collect_garbage_minor scheme_enable_garbage_collection +scheme_incremental_garbage_collection GC_register_traversers GC_resolve GC_mark diff --git a/racket/src/racket/include/racket3m.exp b/racket/src/racket/include/racket3m.exp index 84d9b9c58f..b20a398a31 100644 --- a/racket/src/racket/include/racket3m.exp +++ b/racket/src/racket/include/racket3m.exp @@ -241,6 +241,7 @@ scheme_gc_ptr_ok scheme_collect_garbage scheme_collect_garbage_minor scheme_enable_garbage_collection +scheme_incremental_garbage_collection GC_variable_stack GC_register_traversers GC_resolve diff --git a/racket/src/racket/src/salloc.c b/racket/src/racket/src/salloc.c index 2c449cba8a..5ecfc0377b 100644 --- a/racket/src/racket/src/salloc.c +++ b/racket/src/racket/src/salloc.c @@ -1658,6 +1658,13 @@ void scheme_enable_garbage_collection(int on) #endif } +void scheme_incremental_garbage_collection(int on) +{ +#ifdef MZ_PRECISE_GC + GC_set_incremental_mode(on); +#endif +} + MZ_DO_NOT_INLINE(uintptr_t scheme_get_deeper_address(void)); uintptr_t scheme_get_deeper_address(void) diff --git a/racket/src/racket/src/schemef.h b/racket/src/racket/src/schemef.h index ba990ea7cb..c315a9ec2a 100644 --- a/racket/src/racket/src/schemef.h +++ b/racket/src/racket/src/schemef.h @@ -464,6 +464,7 @@ MZ_EXTERN void scheme_gc_ptr_ok(void *p); MZ_EXTERN void scheme_collect_garbage(void); MZ_EXTERN void scheme_collect_garbage_minor(void); MZ_EXTERN void scheme_enable_garbage_collection(int on); +MZ_EXTERN void scheme_incremental_garbage_collection(int on); #ifdef MZ_PRECISE_GC # ifndef USE_THREAD_LOCAL diff --git a/racket/src/racket/src/schemex.h b/racket/src/racket/src/schemex.h index 4d95b96eb5..f7553b13d0 100644 --- a/racket/src/racket/src/schemex.h +++ b/racket/src/racket/src/schemex.h @@ -363,6 +363,7 @@ void (*scheme_gc_ptr_ok)(void *p); void (*scheme_collect_garbage)(void); void (*scheme_collect_garbage_minor)(void); void (*scheme_enable_garbage_collection)(int on); +void (*scheme_incremental_garbage_collection)(int on); #ifdef MZ_PRECISE_GC # ifndef USE_THREAD_LOCAL void **GC_variable_stack; diff --git a/racket/src/racket/src/schemex.inc b/racket/src/racket/src/schemex.inc index 741ff989cc..498a16334c 100644 --- a/racket/src/racket/src/schemex.inc +++ b/racket/src/racket/src/schemex.inc @@ -263,6 +263,7 @@ scheme_extension_table->scheme_collect_garbage = scheme_collect_garbage; scheme_extension_table->scheme_collect_garbage_minor = scheme_collect_garbage_minor; scheme_extension_table->scheme_enable_garbage_collection = scheme_enable_garbage_collection; + scheme_extension_table->scheme_incremental_garbage_collection = scheme_incremental_garbage_collection; #ifdef MZ_PRECISE_GC # ifndef USE_THREAD_LOCAL scheme_extension_table->GC_variable_stack = GC_variable_stack; diff --git a/racket/src/racket/src/schemexm.h b/racket/src/racket/src/schemexm.h index 318cad8505..cfd3512112 100644 --- a/racket/src/racket/src/schemexm.h +++ b/racket/src/racket/src/schemexm.h @@ -263,6 +263,7 @@ #define scheme_collect_garbage (scheme_extension_table->scheme_collect_garbage) #define scheme_collect_garbage_minor (scheme_extension_table->scheme_collect_garbage_minor) #define scheme_enable_garbage_collection (scheme_extension_table->scheme_enable_garbage_collection) +#define scheme_incremental_garbage_collection (scheme_extension_table->scheme_incremental_garbage_collection) #ifdef MZ_PRECISE_GC # ifndef USE_THREAD_LOCAL #define GC_variable_stack (scheme_extension_table->GC_variable_stack) diff --git a/racket/src/racket/src/thread.c b/racket/src/racket/src/thread.c index 80c0c8b4c6..08a6d60104 100644 --- a/racket/src/racket/src/thread.c +++ b/racket/src/racket/src/thread.c @@ -223,7 +223,7 @@ THREAD_LOCAL_DECL(static double end_this_gc_real_time); static void get_ready_for_GC(void); static void done_with_GC(void); #ifdef MZ_PRECISE_GC -static void inform_GC(int master_gc, int major_gc, intptr_t pre_used, intptr_t post_used, +static void inform_GC(int master_gc, int major_gc, int inc_gc, intptr_t pre_used, intptr_t post_used, intptr_t pre_admin, intptr_t post_admin, intptr_t post_child_places_used); #endif @@ -9252,7 +9252,7 @@ static char *gc_num(char *nums, intptr_t v) END_XFORM_SKIP; #endif -static void inform_GC(int master_gc, int major_gc, +static void inform_GC(int master_gc, int major_gc, int inc_gc, intptr_t pre_used, intptr_t post_used, intptr_t pre_admin, intptr_t post_admin, intptr_t post_child_places_used) @@ -9282,7 +9282,9 @@ static void inform_GC(int master_gc, int major_gc, vec = scheme_false; if (!master_gc && gc_info_prefab) { vec = scheme_make_vector(11, scheme_false); - SCHEME_VEC_ELS(vec)[1] = (major_gc ? scheme_true : scheme_false); + SCHEME_VEC_ELS(vec)[1] = (major_gc + ? major_symbol + : (inc_gc ? incremental_symbol : minor_symbol)); SCHEME_VEC_ELS(vec)[2] = scheme_make_integer(pre_used); SCHEME_VEC_ELS(vec)[3] = scheme_make_integer(pre_admin); SCHEME_VEC_ELS(vec)[4] = scheme_make_integer(scheme_code_page_total); @@ -9311,7 +9313,7 @@ static void inform_GC(int master_gc, int major_gc, #ifdef MZ_USE_PLACES scheme_current_place_id, #endif - (master_gc ? "MST" : (major_gc ? "MAJ" : "min")), + (master_gc ? "MST" : (major_gc ? "MAJ" : (inc_gc ? "mIn" : "min"))), gc_num(nums, pre_used), gc_num(nums, pre_admin - pre_used), gc_num(nums, scheme_code_page_total), gc_num(nums, delta), ((admin_delta < 0) ? "" : "+"), gc_num(nums, admin_delta),