Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r898:8a0cf5b15157 Date: 2014-02-27 19:45 +0100 http://bitbucket.org/pypy/stmgc/changeset/8a0cf5b15157/
Log: Start laying out the logic invoking major collections at the right time. diff --git a/c7/stm/core.c b/c7/stm/core.c --- a/c7/stm/core.c +++ b/c7/stm/core.c @@ -370,6 +370,10 @@ assert(STM_PSEGMENT->transaction_state != TS_MUST_ABORT); STM_SEGMENT->jmpbuf_ptr = NULL; + /* if a major collection is required, do it here */ + if (is_major_collection_requested()) + major_collection_now_at_safe_point(); + /* synchronize overflow objects living in privatized pages */ push_overflow_objects_from_privatized_pages(); diff --git a/c7/stm/gcpage.c b/c7/stm/gcpage.c --- a/c7/stm/gcpage.c +++ b/c7/stm/gcpage.c @@ -105,3 +105,42 @@ o->stm_flags = STM_FLAGS_PREBUILT; return o; } + + +/************************************************************/ + + +static void major_collection(bool forced) +{ + assert(!_has_mutex()); + if (!forced && !is_major_collection_requested()) + return; + + mutex_lock(); + + assert(STM_PSEGMENT->safe_point == SP_RUNNING); + STM_PSEGMENT->safe_point = SP_SAFE_POINT; + + while (forced || is_major_collection_requested()) { + /* wait until the other thread is at a safe-point */ + if (try_wait_for_other_safe_points()) { + /* ok */ + major_collection_now_at_safe_point(); + break; + } + } + + assert(STM_PSEGMENT->safe_point == SP_SAFE_POINT); + STM_PSEGMENT->safe_point = SP_RUNNING; + + mutex_unlock(); +} + +static void major_collection_now_at_safe_point(void) +{ + assert(_has_mutex()); + + fprintf(stderr, "hi, I should be doing a major GC here\n"); + + reset_major_collection_requested(); +} diff --git a/c7/stm/gcpage.h b/c7/stm/gcpage.h --- a/c7/stm/gcpage.h +++ b/c7/stm/gcpage.h @@ -9,6 +9,11 @@ #define GC_N_SMALL_REQUESTS 36 +/* More parameters fished directly from PyPy's default GC + XXX document me */ +#define GC_MIN (NB_NURSERY_PAGES * 4096 * 8) +#define GC_MAJOR_COLLECT 1.82 + static char *uninitialized_page_start; /* within segment 0 */ static char *uninitialized_page_stop; @@ -28,6 +33,9 @@ static void teardown_gcpage(void); static char *allocate_outside_nursery_large(uint64_t size); +static void major_collection(bool forced); +static void major_collection_now_at_safe_point(void); + static char *_allocate_small_slowpath(uint64_t size); diff --git a/c7/stm/nursery.c b/c7/stm/nursery.c --- a/c7/stm/nursery.c +++ b/c7/stm/nursery.c @@ -282,8 +282,8 @@ void stm_collect(long level) { - assert(level == 0); minor_collection(/*commit=*/ false); + major_collection(/*forced=*/ level > 0); } @@ -309,13 +309,19 @@ return (object_t *)p; } - minor_collection(/*commit=*/ false); + stm_collect(0); goto restart; } object_t *_stm_allocate_external(ssize_t size_rounded_up) { - /* XXX force a minor/major collection if needed */ + /* first, force a collection if needed */ + if (is_major_collection_requested()) { + /* use stm_collect() with level 0: if another thread does a major GC + in-between, is_major_collection_requested() will become false + again, and we'll avoid doing yet another one afterwards. */ + stm_collect(0); + } char *result = allocate_outside_nursery_large(size_rounded_up); object_t *o = (object_t *)(result - stm_object_pages); diff --git a/c7/stm/pages.c b/c7/stm/pages.c --- a/c7/stm/pages.c +++ b/c7/stm/pages.c @@ -8,12 +8,20 @@ static union { struct { uint8_t mutex_pages; + bool major_collection_requested; uint64_t total_allocated; /* keep track of how much memory we're using, ignoring nurseries */ + uint64_t total_allocated_bound; }; char reserved[64]; } pages_ctl __attribute__((aligned(64))); + +static void setup_pages(void) +{ + pages_ctl.total_allocated_bound = GC_MIN; +} + static void teardown_pages(void) { memset(&pages_ctl, 0, sizeof(pages_ctl)); @@ -41,9 +49,31 @@ { assert(_has_mutex_pages()); pages_ctl.total_allocated += add_or_remove; + + if (pages_ctl.total_allocated >= pages_ctl.total_allocated_bound) + pages_ctl.major_collection_requested = true; + return pages_ctl.total_allocated; } +static bool is_major_collection_requested(void) +{ + return pages_ctl.major_collection_requested; +} + +static void reset_major_collection_requested(void) +{ + assert(_has_mutex()); + + uint64_t next_bound = (uint64_t)((double)pages_ctl.total_allocated * + GC_MAJOR_COLLECT); + if (next_bound < GC_MIN) + next_bound = GC_MIN; + + pages_ctl.total_allocated_bound = next_bound; + pages_ctl.major_collection_requested = false; +} + /************************************************************/ diff --git a/c7/stm/pages.h b/c7/stm/pages.h --- a/c7/stm/pages.h +++ b/c7/stm/pages.h @@ -24,6 +24,8 @@ static void mutex_pages_lock(void); static void mutex_pages_unlock(void); static uint64_t increment_total_allocated(ssize_t add_or_remove); +static bool is_major_collection_requested(void); +static void reset_major_collection_requested(void); inline static void pages_privatize(uintptr_t pagenum, uintptr_t count, bool full) { diff --git a/c7/stm/setup.c b/c7/stm/setup.c --- a/c7/stm/setup.c +++ b/c7/stm/setup.c @@ -77,6 +77,7 @@ setup_sync(); setup_nursery(); setup_gcpage(); + setup_pages(); } void stm_teardown(void) diff --git a/c7/stm/sync.c b/c7/stm/sync.c --- a/c7/stm/sync.c +++ b/c7/stm/sync.c @@ -240,7 +240,7 @@ #endif -static void wait_for_other_safe_points(void) +static bool try_wait_for_other_safe_points(void) { /* Must be called with the mutex. When all other threads are in a safe point of at least the requested kind, returns. Otherwise, @@ -257,11 +257,10 @@ This function requires that the calling thread is in a safe-point right now, so there is no deadlock if one thread calls - wait_for_other_safe_points() while another is currently blocked + try_wait_for_other_safe_points() while another is currently blocked in the cond_wait() in this same function. */ - restart: assert(_has_mutex()); assert(STM_PSEGMENT->safe_point == SP_SAFE_POINT); @@ -290,12 +289,20 @@ if (wait) { cond_wait(C_SAFE_POINT); - goto restart; + return false; } /* all threads are at a safe-point now. Broadcast C_RESUME, which will allow them to resume --- but only when we release the mutex. */ cond_broadcast(C_RESUME); + return true; +} + +static void wait_for_other_safe_points(void) +{ + while (!try_wait_for_other_safe_points()) { + /* loop */ + } } void _stm_collectable_safe_point(void) diff --git a/c7/stm/sync.h b/c7/stm/sync.h --- a/c7/stm/sync.h +++ b/c7/stm/sync.h @@ -28,4 +28,5 @@ /* see the source for an exact description */ static void wait_for_other_safe_points(void); +static bool try_wait_for_other_safe_points(void); static void collectable_safe_point(void); _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit