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

Reply via email to