Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r910:6f5c7ae1e5eb
Date: 2014-03-01 18:57 +0100
http://bitbucket.org/pypy/stmgc/changeset/6f5c7ae1e5eb/

Log:    Test that largemalloc_sweep() works as expected; start to work on
        recording modified objects

diff --git a/c7/stm/gcpage.c b/c7/stm/gcpage.c
--- a/c7/stm/gcpage.c
+++ b/c7/stm/gcpage.c
@@ -136,24 +136,84 @@
 
 static struct list_s *mark_objects_to_trace;
 
+#define WL_VISITED   42
 
-static inline struct object_s *mark_first_seg(object_t *obj)
+
+static inline uintptr_t mark_loc(object_t *obj)
 {
-    return (struct object_s *)REAL_ADDRESS(stm_object_pages, obj);
+    uintptr_t lock_idx = (((uintptr_t)obj) >> 4) - WRITELOCK_START;
+    assert(lock_idx >= 0);
+    assert(lock_idx < sizeof(write_locks));
+    return lock_idx;
 }
 
 static inline bool mark_is_visited(object_t *obj)
 {
-    uintptr_t lock_idx = (((uintptr_t)obj) >> 4) - WRITELOCK_START;
-    assert(lock_idx >= 0);
-    assert(lock_idx < sizeof(write_locks));
+    uintptr_t lock_idx = mark_loc(obj);
+    assert(write_locks[lock_idx] == 0 || write_locks[lock_idx] == WL_VISITED);
     return write_locks[lock_idx] != 0;
 }
 
 static inline void mark_set_visited(object_t *obj)
 {
-    uintptr_t lock_idx = (((uintptr_t)obj) >> 4) - WRITELOCK_START;
-    write_locks[lock_idx] = 0xff;
+    uintptr_t lock_idx = mark_loc(obj);
+    write_locks[lock_idx] = WL_VISITED;
+}
+
+static void mark_record_modified_objects(void)
+{
+    /* The modified objects are the ones that may exist in two different
+       versions: one in the segment that modified it, and another in
+       all other segments. */
+    long i;
+    for (i = 0; i < NB_SEGMENTS; i++) {
+        struct stm_priv_segment_info_s *pseg = get_priv_segment(i);
+        char *base1 = get_segment_base(i);   /* two different segments */
+        char *base2 = get_segment_base(!i);
+
+        LIST_FOREACH_R(
+            pseg->modified_old_objects,
+            object_t * /*item*/,
+            ({
+                assert(item != NULL);
+
+                uintptr_t lock_idx = mark_loc(item);
+                assert(write_locks[lock_idx] == pseg->write_lock_num);
+
+                write_locks[lock_idx] = WL_VISITED;
+                LIST_APPEND(mark_objects_to_trace, REAL_ADDRESS(base1, item));
+                LIST_APPEND(mark_objects_to_trace, REAL_ADDRESS(base2, item));
+            }));
+    }
+}
+
+static void reset_write_locks(void)
+{
+    /* the write_locks array, containing the visit marker during
+       major collection, is cleared now, with two memsets (to avoid
+       clearing the never-used range in the middle corresponding to
+       uninitialized pages) */
+    object_t *loc1 = (object_t *)(uninitialized_page_start - stm_object_pages);
+    object_t *loc2 = (object_t *)(uninitialized_page_stop  - stm_object_pages);
+    uintptr_t lock1_idx = mark_loc(loc1);
+    uintptr_t lock2_idx = mark_loc(loc2 - 1) + 1;
+
+    memset(write_locks, 0, lock1_idx);
+    memset(write_locks + lock2_idx, 0, sizeof(write_locks) - lock2_idx);
+
+    /* restore the write locks on the modified objects */
+    long i;
+    for (i = 0; i < NB_SEGMENTS; i++) {
+        struct stm_priv_segment_info_s *pseg = get_priv_segment(i);
+
+        LIST_FOREACH_R(
+            pseg->modified_old_objects,
+            object_t * /*item*/,
+            ({
+                uintptr_t lock_idx = mark_loc(item);
+                write_locks[lock_idx] = pseg->write_lock_num;
+            }));
+    }
 }
 
 static inline void mark_record_trace(object_t **pobj)
@@ -167,12 +227,7 @@
         return;    /* already visited this object */
 
     mark_set_visited(obj);
-    LIST_APPEND(mark_objects_to_trace, obj);
-}
-
-static void mark_collect_modified_objects(void)
-{
-    //...
+    LIST_APPEND(mark_objects_to_trace, REAL_ADDRESS(stm_object_pages, obj));
 }
 
 static void mark_collect_roots(void)
@@ -194,25 +249,21 @@
 static void mark_visit_all_objects(void)
 {
     while (!list_is_empty(mark_objects_to_trace)) {
-        object_t *obj = (object_t *)list_pop_item(mark_objects_to_trace);
-
-        stmcb_trace(mark_first_seg(obj), &mark_record_trace);
-
-        if (!is_fully_in_shared_pages(obj)) {
-            abort();//xxx;
-        }
+        struct object_s *obj =
+            (struct object_s *)list_pop_item(mark_objects_to_trace);
+        stmcb_trace(obj, &mark_record_trace);
     }
 }
 
 static inline bool largemalloc_keep_object_at(char *data)
 {
-    /* this is called by largemalloc_sweep() */
+    /* this is called by _stm_largemalloc_sweep() */
     return mark_is_visited((object_t *)(data - stm_object_pages));
 }
 
 static void sweep_large_objects(void)
 {
-    largemalloc_sweep();
+    _stm_largemalloc_sweep();
 }
 
 static void major_collection_now_at_safe_point(void)
@@ -229,7 +280,7 @@
 
     /* marking */
     mark_objects_to_trace = list_create();
-    mark_collect_modified_objects();
+    mark_record_modified_objects();
     mark_collect_roots();
     mark_visit_all_objects();
     list_free(mark_objects_to_trace);
@@ -241,6 +292,8 @@
     //sweep_uniform_pages();
     mutex_pages_unlock();
 
+    reset_write_locks();
+
     dprintf((" | used after collection:  %ld\n",
              (long)pages_ctl.total_allocated));
     dprintf((" `----------------------------------------------\n"));
diff --git a/c7/stm/largemalloc.c b/c7/stm/largemalloc.c
--- a/c7/stm/largemalloc.c
+++ b/c7/stm/largemalloc.c
@@ -348,6 +348,10 @@
     return (char *)first_chunk;
 }
 
+#ifdef STM_TESTS
+bool (*_stm_largemalloc_keep)(char *data);   /* a hook for tests */
+#endif
+
 void _stm_largemalloc_init_arena(char *data_start, size_t data_size)
 {
     int i;
@@ -367,6 +371,10 @@
     assert(last_chunk == next_chunk_u(first_chunk));
 
     insert_unsorted(first_chunk);
+
+#ifdef STM_TESTS
+    _stm_largemalloc_keep = NULL;
+#endif
 }
 
 int _stm_largemalloc_resize_arena(size_t new_size)
@@ -426,10 +434,6 @@
 }
 
 
-#ifdef STM_TESTS
-bool (*_stm_largemalloc_keep)(char *data) = NULL;
-#endif
-
 static inline bool _largemalloc_sweep_keep(mchunk_t *chunk)
 {
 #ifdef STM_TESTS
@@ -439,7 +443,7 @@
     return largemalloc_keep_object_at((char *)&chunk->d);
 }
 
-static void largemalloc_sweep(void)
+void _stm_largemalloc_sweep(void)
 {
     /* This may be slightly optimized by inlining _stm_large_free() and
        making cases, e.g. we might know already if the previous block
diff --git a/c7/stm/largemalloc.h b/c7/stm/largemalloc.h
--- a/c7/stm/largemalloc.h
+++ b/c7/stm/largemalloc.h
@@ -10,10 +10,9 @@
    major collections, which have their own synchronization mecanisms. */
 char *_stm_large_malloc(size_t request_size);
 void _stm_large_free(char *data);
+void _stm_largemalloc_sweep(void);
 
 void _stm_large_dump(void);
 
-static void largemalloc_sweep(void);
-
 
 #define LARGE_MALLOC_OVERHEAD   (2 * sizeof(size_t))   /* estimate */
diff --git a/c7/stm/pages.c b/c7/stm/pages.c
--- a/c7/stm/pages.c
+++ b/c7/stm/pages.c
@@ -47,7 +47,6 @@
 
 static uint64_t increment_total_allocated(ssize_t add_or_remove)
 {
-    assert(_has_mutex_pages());
     pages_ctl.total_allocated += add_or_remove;
 
     if (pages_ctl.total_allocated >= pages_ctl.total_allocated_bound)
@@ -197,6 +196,7 @@
     mutex_pages_unlock();
 }
 
+#if 0
 static bool is_fully_in_shared_pages(object_t *obj)
 {
     uintptr_t first_page = ((uintptr_t)obj) / 4096UL;
@@ -216,3 +216,4 @@
 
     return true;
 }
+#endif
diff --git a/c7/stm/pages.h b/c7/stm/pages.h
--- a/c7/stm/pages.h
+++ b/c7/stm/pages.h
@@ -41,4 +41,4 @@
     _pages_privatize(pagenum, count, full);
 }
 
-static bool is_fully_in_shared_pages(object_t *obj);
+/* static bool is_fully_in_shared_pages(object_t *obj); */
diff --git a/c7/stm/setup.c b/c7/stm/setup.c
--- a/c7/stm/setup.c
+++ b/c7/stm/setup.c
@@ -49,7 +49,7 @@
                      PROT_NONE);
 
         struct stm_priv_segment_info_s *pr = get_priv_segment(i);
-        assert(i + 1 < 0xff);   /* 0xff (255) is used by major collections */
+        assert(i + 1 <= 255);
         pr->write_lock_num = i + 1;
         pr->pub.segment_num = i;
         pr->pub.segment_base = segment_base;
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -85,6 +85,8 @@
 char *_stm_large_malloc(size_t request_size);
 void _stm_large_free(char *data);
 void _stm_large_dump(void);
+bool (*_stm_largemalloc_keep)(char *data);
+void _stm_largemalloc_sweep(void);
 void _stm_start_safe_point(void);
 void _stm_stop_safe_point(void);
 void _stm_set_nursery_free_count(uint64_t free_count);
diff --git a/c7/test/support.py b/c7/test/support.py
--- a/c7/test/support.py
+++ b/c7/test/support.py
@@ -61,6 +61,8 @@
 void _stm_large_free(char *data);
 void _stm_large_dump(void);
 void *memset(void *s, int c, size_t n);
+bool (*_stm_largemalloc_keep)(char *data);
+void _stm_largemalloc_sweep(void);
 
 ssize_t stmcb_size_rounded_up(struct object_s *obj);
 
diff --git a/c7/test/test_gcpage.py b/c7/test/test_gcpage.py
--- a/c7/test/test_gcpage.py
+++ b/c7/test/test_gcpage.py
@@ -115,7 +115,7 @@
                 prev = self.pop_root()
                 stm_set_ref(new, 42, prev)
                 prev = new
-            return new
+            return prev
 
         self.start_transaction()
         self.push_root(make_chain(5000))
@@ -123,3 +123,15 @@
         stm_minor_collect()
         assert lib._stm_total_allocated() == (10 * (5000 + LMO) +
                                               10 * (4312 + LMO))
+        stm_major_collect()
+        assert lib._stm_total_allocated() == (10 * (5000 + LMO) +
+                                              10 * (4312 + LMO))
+        stm_major_collect()
+        assert lib._stm_total_allocated() == (10 * (5000 + LMO) +
+                                              10 * (4312 + LMO))
+        self.pop_root()
+        stm_major_collect()
+        assert lib._stm_total_allocated() == 10 * (5000 + LMO)
+
+    def test_trace_all_versions(self):
+        pass #xxx in-progress
diff --git a/c7/test/test_largemalloc.py b/c7/test/test_largemalloc.py
--- a/c7/test/test_largemalloc.py
+++ b/c7/test/test_largemalloc.py
@@ -118,3 +118,44 @@
                 ra(d)[sz - 1] = content2
                 p.append((d, sz, content1, content2))
         lib._stm_large_dump()
+
+    def test_random_largemalloc_sweep(self):
+        @ffi.callback("bool(char *)")
+        def keep(data):
+            try:
+                if data in from_before:
+                    return False
+                index = all.index(data)
+                seen_for.add(index)
+                return index in keep_me
+            except Exception, e:
+                errors.append(e)
+                raise
+        lib._stm_largemalloc_keep = keep
+        errors = []
+        from_before = set()
+
+        r = random.Random(1000)
+        for j in range(50):
+            sizes = [random.choice(range(104, 500, 8)) for i in range(20)]
+            all = [lib._stm_large_malloc(size) for size in sizes]
+            print all
+
+            keep_me = set()
+            for i in range(len(all)):
+                if r.random() < 0.5:
+                    print 'free:', all[i]
+                    lib._stm_large_free(all[i])
+                    all[i] = None
+                elif r.random() < 0.5:
+                    keep_me.add(i)
+
+            seen_for = set()
+            lib._stm_largemalloc_sweep()
+            assert seen_for == set([i for i in range(len(all))
+                                      if all[i] is not None])
+            lib._stm_large_dump()
+            from_before = [all[i] for i in keep_me]
+
+            if errors:
+                raise errors[0]
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to