From d4aaa9cf6fe8a4b85ff077eb44d55fc778036431 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Thu, 10 Dec 2009 02:25:46 +0000 Subject: [PATCH] adaptive future-nursery size svn: r17252 --- src/mzscheme/gc2/gc2.h | 11 ++++++-- src/mzscheme/gc2/newgc.c | 14 ++++++----- src/mzscheme/gc2/newgc.h | 4 +-- src/mzscheme/src/future.c | 53 ++++++++++++++++++++++++++++++++------- src/mzscheme/src/future.h | 9 +++---- src/mzscheme/src/jit.c | 3 +-- 6 files changed, 68 insertions(+), 26 deletions(-) diff --git a/src/mzscheme/gc2/gc2.h b/src/mzscheme/gc2/gc2.h index 6df25495b4..6ea5176d23 100644 --- a/src/mzscheme/gc2/gc2.h +++ b/src/mzscheme/gc2/gc2.h @@ -410,9 +410,16 @@ GC2_EXTERN void GC_switch_back_from_master(void *gc); Switches to back to gc from the master GC */ -GC2_EXTERN unsigned long GC_make_jit_nursery_page(); +GC2_EXTERN long GC_alloc_alignment(); /* - Obtains a nursery page from the GC for thread local allocation. + Guaranteeed alignment for nusery pages. Returns a constant, and + can be called from any thread. +*/ + +GC2_EXTERN unsigned long GC_make_jit_nursery_page(int count); +/* + Obtains nursery pages from the GC for thread local allocation; + resulting space is count times the allocation alignment. The result is an unsigned long because it's not a valid pointer to a GCable object. The result becomes invalid (i.e. it's collected) with the next GC. diff --git a/src/mzscheme/gc2/newgc.c b/src/mzscheme/gc2/newgc.c index 1999ea4e97..7e1485a40a 100644 --- a/src/mzscheme/gc2/newgc.c +++ b/src/mzscheme/gc2/newgc.c @@ -814,6 +814,7 @@ inline static mpage *gen0_create_new_nursery_mpage(NewGC *gc, const size_t page_ newmpage->addr = malloc_dirty_pages(gc, page_size, APAGE_SIZE); newmpage->size_class = 0; newmpage->size = PREFIX_SIZE; + newmpage->previous_size = page_size; pagemap_add_with_size(gc->page_maps, newmpage, page_size); GCVERBOSEPAGE("NEW gen0", newmpage); @@ -829,18 +830,19 @@ inline static void gen0_free_nursery_mpage(NewGC *gc, mpage *page, size_t page_s /* Needs to be consistent with GC_alloc_alignment(): */ #define THREAD_LOCAL_PAGE_SIZE APAGE_SIZE -unsigned long GC_make_jit_nursery_page() { +unsigned long GC_make_jit_nursery_page(int count) { NewGC *gc = GC_get_GC(); mpage *new_mpage; + long size = count * THREAD_LOCAL_PAGE_SIZE; - if((gc->gen0.current_size + THREAD_LOCAL_PAGE_SIZE) >= gc->gen0.max_size) { + if((gc->gen0.current_size + size) >= gc->gen0.max_size) { if (!gc->dumping_avoid_collection) garbage_collect(gc, 0); } - gc->gen0.current_size += THREAD_LOCAL_PAGE_SIZE; + gc->gen0.current_size += size; { - new_mpage = gen0_create_new_nursery_mpage(gc, THREAD_LOCAL_PAGE_SIZE); + new_mpage = gen0_create_new_nursery_mpage(gc, size); /* push page */ new_mpage->next = gc->thread_local_pages; @@ -865,7 +867,7 @@ unsigned long GC_make_jit_nursery_page() { } inline static void gen0_free_jit_nursery_page(NewGC *gc, mpage *page) { - gen0_free_nursery_mpage(gc, page, THREAD_LOCAL_PAGE_SIZE); + gen0_free_nursery_mpage(gc, page, page->previous_size); } inline static mpage *gen0_create_new_mpage(NewGC *gc) { @@ -1211,7 +1213,7 @@ inline static int marked(NewGC *gc, void *p) if (page->size_class > 1) { return (page->size_class > 2); } - } else { + } else if (page->generation) { if((NUM(page->addr) + page->previous_size) > NUM(p)) return 1; } diff --git a/src/mzscheme/gc2/newgc.h b/src/mzscheme/gc2/newgc.h index cfb3acca3c..3724703576 100644 --- a/src/mzscheme/gc2/newgc.h +++ b/src/mzscheme/gc2/newgc.h @@ -5,8 +5,8 @@ typedef struct mpage { struct mpage *next; struct mpage *prev; void *addr; - unsigned long previous_size; /* for med page, points to place to search for available block */ - unsigned long size; /* big page size or med page element size */ + unsigned long previous_size; /* for med page, place to search for available block; for jit nursery, allocated size */ + unsigned long size; /* big page size, med page element size, or nursery starting point */ unsigned char generation; /* unsigned char back_pointers :1; diff --git a/src/mzscheme/src/future.c b/src/mzscheme/src/future.c index bdf43c12d3..bb5f0bb4ea 100644 --- a/src/mzscheme/src/future.c +++ b/src/mzscheme/src/future.c @@ -199,6 +199,10 @@ typedef struct Scheme_Future_Thread_State { volatile int *fuel_pointer; volatile unsigned long *stack_boundary_pointer; volatile int *need_gc_pointer; + + unsigned long gen0_start; + unsigned long gen0_size; + unsigned long gen0_initial_offset; } Scheme_Future_Thread_State; THREAD_LOCAL_DECL(static Scheme_Future_State *scheme_future_state); @@ -411,6 +415,8 @@ static void init_future_thread(Scheme_Future_State *fs, int i) sema_destroy(¶ms.ready_sema); fts->threadid = threadid; + + fts->gen0_size = 1; scheme_register_static(&fts->current_ft, sizeof(void*)); scheme_register_static(params.scheme_current_runstack_ptr, sizeof(void*)); @@ -434,6 +440,9 @@ static void start_gc_not_ok(Scheme_Future_State *fs) Scheme_Future_Thread_State *fts = scheme_future_thread_state; if (fts->worker_gc_counter != *fs->gc_counter_ptr) { GC_gen0_alloc_page_ptr = 0; /* forces future to ask for memory */ + fts->gen0_start = 0; + if (fts->gen0_size > 1) + fts->gen0_size >>= 1; fts->worker_gc_counter = *fs->gc_counter_ptr; } } @@ -959,9 +968,8 @@ static void future_do_runtimecall(Scheme_Future_Thread_State *fts, } } - /**********************************************************************/ -/* Functions for primitive invocation */ +/* Functions for primitive invocation */ /**********************************************************************/ void scheme_rtcall_void_void_3args(const char *who, int src_type, prim_void_void_3args_t f) XFORM_SKIP_PROC @@ -983,7 +991,9 @@ void scheme_rtcall_void_void_3args(const char *who, int src_type, prim_void_void future->arg_S0 = NULL; } -unsigned long scheme_rtcall_alloc_void_pvoid(const char *who, int src_type, prim_alloc_void_pvoid_t f) +#ifdef MZ_PRECISE_GC + +unsigned long scheme_rtcall_alloc(const char *who, int src_type) XFORM_SKIP_PROC /* Called in future thread */ { @@ -991,21 +1001,43 @@ unsigned long scheme_rtcall_alloc_void_pvoid(const char *who, int src_type, prim unsigned long retval; Scheme_Future_Thread_State *fts = scheme_future_thread_state; Scheme_Future_State *fs = scheme_future_state; + long align; + + align = GC_alloc_alignment(); + + /* Do we actually still have space? */ + if (fts->gen0_start) { + long cur; + cur = GC_gen0_alloc_page_ptr; + if (cur < (fts->gen0_start + (fts->gen0_size - 1) * align)) { + cur &= ~(align - 1); + cur += align + fts->gen0_initial_offset; + return cur; + } + } + + /* Grow nursery size as long as we don't trigger a GC */ + if (fts->gen0_size < 16) + fts->gen0_size <<= 1; while (1) { future = fts->current_ft; - future->time_of_request = 0; /* takes too long?: scheme_get_inexact_milliseconds(); */ + future->time_of_request = scheme_get_inexact_milliseconds(); future->source_of_request = who; future->source_type = src_type; - future->prim_protocol = SIG_ALLOC_VOID_PVOID; + future->prim_protocol = SIG_ALLOC; + future->arg_i0 = fts->gen0_size; - future_do_runtimecall(fts, (void*)f, 1); + future_do_runtimecall(fts, (void*)GC_make_jit_nursery_page, 1); future = fts->current_ft; retval = future->alloc_retval; future->alloc_retval = 0; + fts->gen0_start = retval; + fts->gen0_initial_offset = retval & (align - 1); + if (*fs->gc_counter_ptr == future->alloc_retval_counter) break; } @@ -1013,6 +1045,8 @@ unsigned long scheme_rtcall_alloc_void_pvoid(const char *who, int src_type, prim return retval; } +#endif + static void receive_special_result(future_t *f, Scheme_Object *retval, int clear) XFORM_SKIP_PROC /* Called in future or runtime thread */ @@ -1108,15 +1142,16 @@ static void do_invoke_rtcall(Scheme_Future_State *fs, future_t *future) break; } - case SIG_ALLOC_VOID_PVOID: +#ifdef MZ_PRECISE_GC + case SIG_ALLOC: { unsigned long ret; - prim_alloc_void_pvoid_t func = (prim_alloc_void_pvoid_t)future->prim_func; - ret = func(); + ret = GC_make_jit_nursery_page(future->arg_i0); future->alloc_retval = ret; future->alloc_retval_counter = scheme_did_gc_count; break; } +#endif # include "jit_ts_runtime_glue.c" default: scheme_signal_error("unknown protocol %d", future->prim_protocol); diff --git a/src/mzscheme/src/future.h b/src/mzscheme/src/future.h index e1bad68ffe..321177c60c 100644 --- a/src/mzscheme/src/future.h +++ b/src/mzscheme/src/future.h @@ -24,7 +24,6 @@ int scheme_make_prim_w_arity(prim_t func, char *name, int arg1, int arg2); #include typedef void (*prim_void_void_3args_t)(Scheme_Object **); -typedef unsigned long (*prim_alloc_void_pvoid_t)(); typedef Scheme_Object* (*prim_obj_int_pobj_obj_t)(Scheme_Object*, int, Scheme_Object**); typedef Scheme_Object* (*prim_int_pobj_obj_t)(int, Scheme_Object**); typedef Scheme_Object* (*prim_int_pobj_obj_obj_t)(int, Scheme_Object**, Scheme_Object*); @@ -105,7 +104,7 @@ typedef struct future_t { //Signature flags for primitive invocations //Here the convention is SIG_[arg1type]_[arg2type]..._[return type] #define SIG_VOID_VOID_3ARGS 1 //void -> void, copy 3 args from runstack -#define SIG_ALLOC_VOID_PVOID 2 //void -> void* +#define SIG_ALLOC 2 //void -> void* # include "jit_ts_protos.h" @@ -122,7 +121,7 @@ extern Scheme_Object *scheme_ts_scheme_force_value_same_mark(Scheme_Object *v); } extern void scheme_rtcall_void_void_3args(const char *who, int src_type, prim_void_void_3args_t f); -extern unsigned long scheme_rtcall_alloc_void_pvoid(const char *who, int src_type, prim_alloc_void_pvoid_t f); +extern unsigned long scheme_rtcall_alloc(const char *who, int src_type); #else @@ -136,7 +135,7 @@ extern unsigned long scheme_rtcall_alloc_void_pvoid(const char *who, int src_typ #define LOG_THISCALL LOG(__FUNCTION__) #define LOG_RTCALL_VOID_VOID_3ARGS(f) LOG("(function=%p)", f) -#define LOG_RTCALL_ALLOC_VOID_PVOID(f) LOG("(function=%p)", f) +#define LOG_RTCALL_ALLOC(f) LOG("(function=%p)", f) #define LOG_RTCALL_OBJ_INT_POBJ_OBJ(f,a,b,c) LOG("(function = %p, a=%p, b=%d, c=%p)", f, a, b, c) #define LOG_RTCALL_OBJ_INT_POBJ_VOID(a,b,c) LOG("(%p, %d, %p)", a, b,c) #define LOG_RTCALL_INT_OBJARR_OBJ(a,b) LOG("(%d, %p)", a, b) @@ -159,7 +158,7 @@ extern unsigned long scheme_rtcall_alloc_void_pvoid(const char *who, int src_typ #define LOG_THISCALL #define LOG_RTCALL_VOID_VOID_3ARGS(f) -#define LOG_RTCALL_ALLOC_VOID_PVOID(f) +#define LOG_RTCALL_ALLOC(f) #define LOG_RTCALL_OBJ_INT_POBJ_OBJ(f,a,b,c) #define LOG_RTCALL_OBJ_INT_POBJ_VOID(a,b,c) #define LOG_RTCALL_INT_OBJARR_OBJ(a,b) diff --git a/src/mzscheme/src/jit.c b/src/mzscheme/src/jit.c index a845e2b62b..dbe1c4d715 100644 --- a/src/mzscheme/src/jit.c +++ b/src/mzscheme/src/jit.c @@ -1394,7 +1394,6 @@ THREAD_LOCAL_DECL(extern unsigned long GC_gen0_alloc_page_ptr); long GC_initial_word(int sizeb); void GC_initial_words(char *buffer, int sizeb); long GC_compute_alloc_size(long sizeb); -long GC_alloc_alignment(void); static void *retry_alloc_code; static void *retry_alloc_code_keep_r0_r1; @@ -2257,7 +2256,7 @@ static void *ts_prepare_retry_alloc(void *p, void *p2) XFORM_SKIP_PROC if (scheme_use_rtcall) { jit_future_storage[0] = p; jit_future_storage[1] = p2; - ret = scheme_rtcall_alloc_void_pvoid("[acquire_gc_page]", FSRC_OTHER, GC_make_jit_nursery_page); + ret = scheme_rtcall_alloc("[acquire_gc_page]", FSRC_OTHER); GC_gen0_alloc_page_ptr = ret; retry_alloc_r1 = jit_future_storage[1]; p = jit_future_storage[0];