[pypy-commit] stmgc c7-refactor: in-progress

arigo noreply at buildbot.pypy.org
Fri Feb 14 18:30:32 CET 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: c7-refactor
Changeset: r735:35cc44d7afab
Date: 2014-02-14 18:16 +0100
http://bitbucket.org/pypy/stmgc/changeset/35cc44d7afab/

Log:	in-progress

diff --git a/c7/stm/atomic.h b/c7/stm/atomic.h
new file mode 100644
--- /dev/null
+++ b/c7/stm/atomic.h
@@ -0,0 +1,12 @@
+
+#if defined(__i386__) || defined(__x86_64__)
+
+# define HAVE_FULL_EXCHANGE_INSN
+  static inline void spin_loop(void) { asm("pause" : : : "memory"); }
+
+#else
+
+# warn "Add a correct definition of spin_loop() for this platform?"
+  static inline void spin_loop(void) { asm("" : : : "memory"); }
+
+#endif
diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -3,16 +3,33 @@
 #endif
 
 
+static uint8_t write_locks[READMARKER_END - READMARKER_START];
+
+
 void _stm_write_slowpath(object_t *obj)
 {
     assert(_running_transaction());
 
     LIST_APPEND(STM_PSEGMENT->old_objects_to_trace, obj);
+    obj->stm_flags |= GCFLAG_WRITE_BARRIER_CALLED;
 
-    obj->stm_flags |= GCFLAG_WRITE_BARRIER_CALLED;
+    /* for old objects from the same transaction, we are done now */
+    if (obj_from_same_transaction(obj))
+        return;
+
+    /* otherwise, we need to privatize the pages containing the object,
+       if they are still SHARED_PAGE.  The common case is that there is
+       only one page in total. */
+    if (UNLIKELY((obj->stm_flags & GCFLAG_CROSS_PAGE) != 0)) {
+        abort();
+        //...
+    }
+    else {
+        pages_privatize(((uintptr_t)obj) / 4096UL, 1);
+    }
+
+    //... write_locks
     stm_read(obj);
-
-    //...
 }
 
 static void reset_transaction_read_version(void)
diff --git a/c7/stm/core.h b/c7/stm/core.h
--- a/c7/stm/core.h
+++ b/c7/stm/core.h
@@ -6,6 +6,8 @@
 #include <sys/mman.h>
 #include <errno.h>
 
+/************************************************************/
+
 
 #define NB_PAGES            (1500*256)    // 1500MB
 #define NB_SEGMENTS         2
@@ -33,17 +35,17 @@
        _stm_write_slowpath() is called, and then the flag is set to
        say "called once already, no need to call again". */
     GCFLAG_WRITE_BARRIER_CALLED = _STM_GCFLAG_WRITE_BARRIER_CALLED,
-    /* set if the object can be seen by all threads.  If unset, we know
-       it is only visible from the current thread. */
-    //GCFLAG_ALL_THREADS = 0x04,
-    /* only used during collections to mark an obj as moved out of the
-       generation it was in */
-    //GCFLAG_MOVED = 0x01,
-    /* objects smaller than one page and even smaller than
-       LARGE_OBJECT_WORDS * 8 bytes */
-    //GCFLAG_SMALL = 0x02,
+    /* objects that are allocated crossing a page boundary have this
+       flag set */
+    GCFLAG_CROSS_PAGE = 0x02,
 };
 
+#define CROSS_PAGE_BOUNDARY(start, stop)                                \
+    (((uintptr_t)(start)) / 4096UL != ((uintptr_t)(stop)) / 4096UL)
+
+
+/************************************************************/
+
 
 #define STM_PSEGMENT          ((stm_priv_segment_info_t *)STM_SEGMENT)
 
@@ -82,3 +84,7 @@
 
 static bool _is_tl_registered(stm_thread_local_t *tl);
 static bool _running_transaction(void);
+
+static inline bool obj_from_same_transaction(object_t *obj) {
+    return ((stm_creation_marker_t *)(((uintptr_t)obj) >> 8))->cm != 0;
+}
diff --git a/c7/stm/gcpage.c b/c7/stm/gcpage.c
--- a/c7/stm/gcpage.c
+++ b/c7/stm/gcpage.c
@@ -5,17 +5,38 @@
 
 static void setup_gcpage(void)
 {
-    largemalloc_init_arena(stm_object_pages + END_NURSERY_PAGE * 4096UL,
-                           (NB_PAGES - END_NURSERY_PAGE) * 4096UL);
+    char *base = stm_object_pages + END_NURSERY_PAGE * 4096UL;
+    uintptr_t length = (NB_PAGES - END_NURSERY_PAGE) * 4096UL;
+    largemalloc_init_arena(base, length);
+
+    uninitialized_page_start = (stm_char *)(END_NURSERY_PAGE * 4096UL);
+    uninitialized_page_stop = (stm_char *)(NB_PAGES * 4096UL);
 }
 
 object_t *_stm_allocate_old(ssize_t size_rounded_up)
 {
+    /* XXX not thread-safe! */
     char *addr = large_malloc(size_rounded_up);
-    object_t* o = (object_t *)(addr - stm_object_pages);
+    stm_char* o = (stm_char *)(addr - stm_object_pages);
 
-    long i;
-    for (i = 0; i < NB_SEGMENTS; i++)
-        memset(REAL_ADDRESS(get_segment_base(i), o), 0, size_rounded_up);
-    return o;
+    if (o + size_rounded_up > uninitialized_page_start) {
+        uintptr_t pagenum =
+            ((uint64_t)uninitialized_page_start) / 4096UL;
+        uintptr_t pagecount =
+            (o + size_rounded_up - uninitialized_page_start) / 4096UL + 20;
+        uintptr_t pagemax =
+            (uninitialized_page_stop - uninitialized_page_start) / 4096UL;
+        if (pagecount > pagemax)
+            pagecount = pagemax;
+        pages_initialize_shared(pagenum, pagecount);
+
+        uninitialized_page_start += pagecount * 4096UL;
+    }
+
+    memset(addr, 0, size_rounded_up);
+
+    if (CROSS_PAGE_BOUNDARY(o, o + size_rounded_up))
+        ((object_t *)o)->stm_flags = GCFLAG_CROSS_PAGE;
+
+    return (object_t *)o;
 }
diff --git a/c7/stm/gcpage.h b/c7/stm/gcpage.h
new file mode 100644
--- /dev/null
+++ b/c7/stm/gcpage.h
@@ -0,0 +1,3 @@
+
+static stm_char *uninitialized_page_start;
+static stm_char *uninitialized_page_stop;
diff --git a/c7/stm/pages.c b/c7/stm/pages.c
--- a/c7/stm/pages.c
+++ b/c7/stm/pages.c
@@ -19,11 +19,61 @@
             abort();
         }
     }
-    for (i = 0; i < count; i++)
+    for (i = 0; i < count; i++) {
+        assert(flag_page_private[pagenum + i] == FREE_PAGE);
         flag_page_private[pagenum + i] = SHARED_PAGE;
+    }
 }
 
 static void _pages_privatize(uintptr_t pagenum, uintptr_t count)
 {
-    abort();
+    assert(count == 1);   /* XXX */
+
+#ifdef HAVE_FULL_EXCHANGE_INSN
+    /* use __sync_lock_test_and_set() as a cheaper alternative to
+       __sync_bool_compare_and_swap(). */
+    int previous = __sync_lock_test_and_set(&flag_page_private[pagenum],
+                                            REMAPPING_PAGE);
+    assert(previous != FREE_PAGE);
+    if (previous == PRIVATE_PAGE) {
+        flag_page_private[pagenum] = PRIVATE_PAGE;
+        return;
+    }
+    bool was_shared = (previous == SHARED_PAGE);
+#else
+    bool was_shared = __sync_bool_compare_and_swap(&flag_page_private[pagenum],
+                                                  SHARED_PAGE, REMAPPING_PAGE);
+#endif
+    if (!was_shared) {
+        while (1) {
+            uint8_t state = ((uint8_t volatile *)flag_page_private)[pagenum];
+            if (state != REMAPPING_PAGE) {
+                assert(state == PRIVATE_PAGE);
+                break;
+            }
+            spin_loop();
+        }
+        return;
+    }
+
+    ssize_t pgoff1 = pagenum;
+    ssize_t pgoff2 = pagenum + NB_PAGES;
+    ssize_t localpgoff = pgoff1 + NB_PAGES * _STM_TL->thread_num;
+    ssize_t otherpgoff = pgoff1 + NB_PAGES * (1 - _STM_TL->thread_num);
+
+    void *localpg = object_pages + localpgoff * 4096UL;
+    void *otherpg = object_pages + otherpgoff * 4096UL;
+
+    // XXX should not use pgoff2, but instead the next unused page in
+    // thread 2, so that after major GCs the next dirty pages are the
+    // same as the old ones
+    int res = remap_file_pages(localpg, 4096, 0, pgoff2, 0);
+    if (res < 0) {
+        perror("remap_file_pages");
+        abort();
+    }
+    pagecopy(localpg, otherpg);
+    write_fence();
+    assert(flag_page_private[pagenum] == REMAPPING_PAGE);
+    flag_page_private[pagenum] = PRIVATE_PAGE;
 }
diff --git a/c7/stm/pages.h b/c7/stm/pages.h
--- a/c7/stm/pages.h
+++ b/c7/stm/pages.h
@@ -3,14 +3,14 @@
     /* The page is not in use.  Assume that each segment sees its own copy. */
     FREE_PAGE=0,
 
-    /* The page is shared by all threads.  Each segment sees the same
+    /* The page is shared by all segments.  Each segment sees the same
        physical page (the one that is within the segment 0 mmap address). */
     SHARED_PAGE,
 
     /* Page being in the process of privatization */
     REMAPPING_PAGE,
 
-    /* Page private for each thread */
+    /* Page is private for each segment. */
     PRIVATE_PAGE,
 
 };      /* used for flag_page_private */
@@ -18,7 +18,6 @@
 
 static uint8_t flag_page_private[NB_PAGES];
 
-
 static void _pages_privatize(uintptr_t pagenum, uintptr_t count);
 static void pages_initialize_shared(uintptr_t pagenum, uintptr_t count);
 
diff --git a/c7/stm/prebuilt.c b/c7/stm/prebuilt.c
--- a/c7/stm/prebuilt.c
+++ b/c7/stm/prebuilt.c
@@ -8,6 +8,8 @@
 static uint64_t prebuilt_objects_start     = 0;
 
 
+/* XXX NOT TESTED, AND NOT WORKING RIGHT NOW */
+
 void stm_copy_prebuilt_objects(object_t *target, char *source, ssize_t size)
 {
     /* Initialize a region of 'size' bytes at the 'target' address,
diff --git a/c7/stmgc.c b/c7/stmgc.c
--- a/c7/stmgc.c
+++ b/c7/stmgc.c
@@ -1,8 +1,10 @@
 #define _GNU_SOURCE
 #include "stmgc.h"
+#include "stm/atomic.h"
 #include "stm/list.h"
 #include "stm/core.h"
 #include "stm/pages.h"
+#include "stm/gcpage.h"
 #include "stm/sync.h"
 #include "stm/largemalloc.h"
 


More information about the pypy-commit mailing list