[pypy-commit] stmgc c7-more-segments: Refactor after discussion with Remi: don't use a tree to record page

arigo noreply at buildbot.pypy.org
Sun Mar 16 14:34:18 CET 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: c7-more-segments
Changeset: r1049:9eed4e26972b
Date: 2014-03-16 14:34 +0100
http://bitbucket.org/pypy/stmgc/changeset/9eed4e26972b/

Log:	Refactor after discussion with Remi: don't use a tree to record page
	remappings, and only do trivial remappings (page N is mapped to
	either to segment 0's page N, or to itself). Use a simple array of
	bits.

diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -8,6 +8,28 @@
     memset(write_locks, 0, sizeof(write_locks));
 }
 
+static void check_flag_write_barrier(object_t *obj)
+{
+    /* check that all copies of the object, apart from mine, have the
+       GCFLAG_WRITE_BARRIER.  (a bit messy because it's possible that we
+       read a page in the middle of privatization by another thread)
+    */
+#ifndef NDEBUG
+    long i;
+    struct object_s *o1;
+    for (i = 0; i <= NB_SEGMENTS; i++) {
+        if (i == STM_SEGMENT->segment_num)
+            continue;
+        o1 = (struct object_s *)REAL_ADDRESS(get_segment_base(i), obj);
+        if (!(o1->stm_flags & GCFLAG_WRITE_BARRIER)) {
+            mutex_pages_lock();  /* try again... */
+            if (!(o1->stm_flags & GCFLAG_WRITE_BARRIER))
+                stm_fatalerror("missing GCFLAG_WRITE_BARRIER");
+            mutex_pages_unlock();
+        }
+    }
+#endif
+}
 
 void _stm_write_slowpath(object_t *obj)
 {
@@ -106,37 +128,20 @@
     }
 
     /* check that we really have a private page */
-    assert(tree_contains(STM_PSEGMENT->private_page_mapping,
-                         ((uintptr_t)obj) / 4096));
+    assert(is_private_page(STM_SEGMENT->segment_num,
+                           ((uintptr_t)obj) / 4096));
 
-    /* check that so far all copies of the object have the flag
-       (a bit messy because it's possible that we read a page in
-       the middle of privatization by another thread) */
-    long i;
-#ifndef NDEBUG
-    long busy_loop = 1000000000;
-    for (i = 0; i <= NB_SEGMENTS; i++) {
-        while (!(((struct object_s *)REAL_ADDRESS(get_segment_base(i), obj))
-                 ->stm_flags & GCFLAG_WRITE_BARRIER)) {
-            spin_loop();
-            if (!--busy_loop)
-                stm_fatalerror("missing GCFLAG_WRITE_BARRIER");
-        }
-    }
-#endif
+    /* check that so far all copies of the object have the flag */
+    check_flag_write_barrier(obj);
 
     /* remove GCFLAG_WRITE_BARRIER, but only if we succeeded in
        getting the write-lock */
     assert(obj->stm_flags & GCFLAG_WRITE_BARRIER);
     obj->stm_flags &= ~GCFLAG_WRITE_BARRIER;
 
-    /* for sanity, check that all other segment copies of this object
-       still have the flag (including the shared copy) */
-    for (i = 0; i <= NB_SEGMENTS; i++) {
-        if (i != STM_SEGMENT->segment_num)
-            assert(((struct object_s *)REAL_ADDRESS(get_segment_base(i), obj))
-                   ->stm_flags & GCFLAG_WRITE_BARRIER);
-    }
+    /* for sanity, check again that all other segment copies of this
+       object still have the flag (so privatization worked) */
+    check_flag_write_barrier(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
@@ -75,13 +75,6 @@
 struct stm_priv_segment_info_s {
     struct stm_segment_info_s pub;
 
-    /* Dict whose keys are shared page numbers, and whose values are
-       the corresponding private page number. */
-    struct tree_s *private_page_mapping;
-
-    /* Head of a free list of private pages. */
-    uintptr_t private_free_page_num;
-
     /* List of old objects (older than the current transaction) that the
        current transaction attempts to modify.  This is used to track
        the STM status: they are old objects that where written to and
diff --git a/c7/stm/misc.c b/c7/stm/misc.c
--- a/c7/stm/misc.c
+++ b/c7/stm/misc.c
@@ -43,9 +43,8 @@
 #ifdef STM_TESTS
 uintptr_t _stm_get_private_page(uintptr_t pagenum)
 {
-    wlog_t *item;
-    TREE_FIND(*STM_PSEGMENT->private_page_mapping, pagenum, item, return 0);
-    return item->val;
+    /* xxx returns 0 or 1 now */
+    return is_private_page(STM_SEGMENT->segment_num, pagenum);
 }
 
 long _stm_count_modified_old_objects(void)
diff --git a/c7/stm/pages.c b/c7/stm/pages.c
--- a/c7/stm/pages.c
+++ b/c7/stm/pages.c
@@ -25,6 +25,7 @@
 static void teardown_pages(void)
 {
     memset(&pages_ctl, 0, sizeof(pages_ctl));
+    memset(pages_privatized, 0, sizeof(pages_privatized));
 }
 
 static void mutex_pages_lock(void)
@@ -111,41 +112,30 @@
 
 static void page_privatize(uintptr_t pagenum)
 {
-    wlog_t *item;
-    TREE_FIND(*STM_PSEGMENT->private_page_mapping, pagenum, item,
-              goto not_found);
+    if (is_private_page(STM_SEGMENT->segment_num, pagenum)) {
+        /* the page is already privatized */
+        return;
+    }
 
-    /* the page is already privatized */
-    return;
-
- not_found:;
-    /* lock, to prevent concurrent threads from looking up my own
-       'private_page_mapping' in parallel */
+    /* lock, to prevent concurrent threads from looking up this thread's
+       'pages_privatized' bits in parallel */
     mutex_pages_lock();
 
-    /* look up the next free page */
-    uintptr_t free_page_num = STM_PSEGMENT->private_free_page_num;
-
-    /* "mount" it in the segment
-       (XXX later we should again attempt to group together many calls to
-       d_remap_file_pages() in succession) */
-    char *new_page = STM_SEGMENT->segment_base + pagenum * 4096UL;
-    d_remap_file_pages(new_page, 4096,
-                       NB_PAGES * STM_SEGMENT->segment_num + free_page_num);
+    /* "unmaps" the page to make the address space location correspond
+       again to its underlying file offset (XXX later we should again
+       attempt to group together many calls to d_remap_file_pages() in
+       succession) */
+    uintptr_t pagenum_in_file = NB_PAGES * STM_SEGMENT->segment_num + pagenum;
+    char *new_page = stm_object_pages + pagenum_in_file * 4096UL;
+    d_remap_file_pages(new_page, 4096, pagenum_in_file);
     increment_total_allocated(4096);
 
-    /* update private_free_page_num */
-    uintptr_t future_page = *(uintptr_t *)new_page;
-    if (future_page == 0) {
-        future_page = free_page_num + 1;
-    }
-    STM_PSEGMENT->private_free_page_num = future_page;
-
     /* copy the content from the shared (segment 0) source */
     pagecopy(new_page, stm_object_pages + pagenum * 4096UL);
 
-    /* update private_page_mapping */
-    tree_insert(STM_PSEGMENT->private_page_mapping, pagenum, free_page_num);
+    /* add this thread's 'pages_privatized' bit */
+    uint64_t bitmask = 1UL << (STM_SEGMENT->segment_num - 1);
+    pages_privatized[pagenum - PAGE_FLAG_START].by_segment |= bitmask;
 
     mutex_pages_unlock();
 }
diff --git a/c7/stm/pages.h b/c7/stm/pages.h
--- a/c7/stm/pages.h
+++ b/c7/stm/pages.h
@@ -3,17 +3,11 @@
    has a "shared copy" and zero or more "private copies".
 
    The shared copy of a page is stored in the mmap at the file offset
-   corresponding to the segment 0 offset (with all other segments
-   remapping to the segment 0 offset).  Private copies for segment N are
-   made in the offset from segment N (for 1 <= N <= NB_SEGMENTS),
-   picking file offsets that are simply the next free ones.  Each
-   segment maintains a tree 'private_page_mapping', which maps shared
-   pages to private copies.
-
-   A major collection looks for pages that are no-longer-used private
-   copies, and discard them, remapping the address to the shared page.
-   The pages thus freed are recorded into a free list, and can be reused
-   as the private copies of the following (unrelated) pages.
+   corresponding to the segment 0 offset.  Initially, accessing a page
+   from segment N remaps to segment 0.  If the page is turned private,
+   then we "un-remap" it to its initial location.  The 'pages_privatized'
+   global array records if a page is currently mapped to segment 0
+   (shared page) or to its natural location (private page).
 
    Note that this page manipulation logic uses remap_file_pages() to
    fully hide its execution cost behind the CPU's memory management unit.
@@ -22,6 +16,25 @@
    (which works at the object granularity, not the page granularity).
 */
 
+#define PAGE_FLAG_START   END_NURSERY_PAGE
+#define PAGE_FLAG_END     NB_PAGES
+
+struct page_shared_s {
+#if NB_SEGMENTS <= 8
+    uint8_t by_segment;
+#elif NB_SEGMENTS <= 16
+    uint16_t by_segment;
+#elif NB_SEGMENTS <= 32
+    uint32_t by_segment;
+#elif NB_SEGMENTS <= 64
+    uint64_t by_segment;
+#else
+#   error "NB_SEGMENTS > 64 not supported right now"
+#endif
+};
+
+static struct page_shared_s pages_privatized[PAGE_FLAG_END - PAGE_FLAG_START];
+
 static void page_privatize(uintptr_t pagenum);
 static void pages_initialize_shared(uintptr_t pagenum, uintptr_t count);
 
@@ -35,6 +48,7 @@
 
 static inline bool is_private_page(long segnum, uintptr_t pagenum)
 {
-    return tree_contains(get_priv_segment(segnum)->private_page_mapping,
-                         pagenum);
+    assert(pagenum >= PAGE_FLAG_START);
+    uint64_t bitmask = 1UL << (segnum - 1);
+    return (pages_privatized[pagenum - PAGE_FLAG_START].by_segment & bitmask);
 }
diff --git a/c7/stm/setup.c b/c7/stm/setup.c
--- a/c7/stm/setup.c
+++ b/c7/stm/setup.c
@@ -58,8 +58,6 @@
         pr->write_lock_num = i;
         pr->pub.segment_num = i;
         pr->pub.segment_base = segment_base;
-        pr->private_page_mapping = tree_create();
-        pr->private_free_page_num = END_NURSERY_PAGE;
         pr->objects_pointing_to_nursery = NULL;
         pr->large_overflow_objects = NULL;
         pr->modified_old_objects = list_create();


More information about the pypy-commit mailing list