Author: Armin Rigo <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit