Author: Remi Meier <[email protected]>
Branch: c8-card-marking
Changeset: r1668:8a75e2be64ac
Date: 2015-02-26 14:41 +0100
http://bitbucket.org/pypy/stmgc/changeset/8a75e2be64ac/

Log:    WIP

diff --git a/c8/stmgc.h b/c8/stmgc.h
--- a/c8/stmgc.h
+++ b/c8/stmgc.h
@@ -73,11 +73,13 @@
 } stm_thread_local_t;
 
 #define _STM_GCFLAG_WRITE_BARRIER      0x01
+#define _STM_GCFLAG_CARDS_SET          0x08
 #define _STM_FAST_ALLOC           (66*1024)
 #define _STM_NSE_SIGNAL_ABORT             1
 #define _STM_NSE_SIGNAL_MAX               2
 
 void _stm_write_slowpath(object_t *);
+void _stm_write_slowpath_card(object_t *, uintptr_t);
 object_t *_stm_allocate_slowpath(ssize_t);
 object_t *_stm_allocate_external(ssize_t);
 void _stm_become_inevitable(const char*);
@@ -89,7 +91,7 @@
 #include <stdbool.h>
 bool _stm_was_read(object_t *obj);
 bool _stm_was_written(object_t *obj);
-
+bool _stm_was_written_card(object_t *obj);
 bool _stm_is_accessible_page(uintptr_t pagenum);
 
 void _stm_test_switch(stm_thread_local_t *tl);
@@ -125,7 +127,8 @@
 object_t *_stm_next_last_cl_entry();
 void _stm_start_enum_last_cl_entry();
 long _stm_count_cl_entries();
-
+long _stm_count_old_objects_with_cards_set(void);
+object_t *_stm_enum_old_objects_with_cards_set(long index);
 uint64_t _stm_total_allocated(void);
 #endif
 
@@ -156,6 +159,12 @@
 
 extern ssize_t stmcb_size_rounded_up(struct object_s *);
 void stmcb_trace(struct object_s *obj, void visit(object_t **));
+/* a special trace-callback that is only called for the marked
+   ranges of indices (using stm_write_card(o, index)) */
+extern void stmcb_trace_cards(struct object_s *, void (object_t **),
+                              uintptr_t start, uintptr_t stop);
+
+
 
 __attribute__((always_inline))
 static inline void stm_read(object_t *obj)
@@ -173,6 +182,14 @@
 
 
 __attribute__((always_inline))
+static inline void stm_write_card(object_t *obj, uintptr_t index)
+{
+    if (UNLIKELY((obj->stm_flags & _STM_GCFLAG_WRITE_BARRIER) != 0))
+        _stm_write_slowpath_card(obj, index);
+}
+
+
+__attribute__((always_inline))
 static inline object_t *stm_allocate(ssize_t size_rounded_up)
 {
     OPT_ASSERT(size_rounded_up >= 16);
@@ -327,14 +344,8 @@
 
 
 /* dummies for now: */
-__attribute__((always_inline))
-static inline void stm_write_card(object_t *obj, uintptr_t index)
-{
-    stm_write(obj);
-}
+static inline void stm_flush_timing(stm_thread_local_t *tl, int verbose) {}
 
-
-static inline void stm_flush_timing(stm_thread_local_t *tl, int verbose) {}
 /* ==================== END ==================== */
 
 static void (*stmcb_expand_marker)(char *segment_base, uintptr_t odd_number,
diff --git a/c8/test/support.py b/c8/test/support.py
--- a/c8/test/support.py
+++ b/c8/test/support.py
@@ -43,6 +43,8 @@
 object_t *stm_allocate_weakref(ssize_t size_rounded_up);
 object_t *stm_allocate_with_finalizer(ssize_t size_rounded_up);
 
+/*void stm_write_card(); use _checked_stm_write_card() instead */
+
 void stm_setup(void);
 void stm_teardown(void);
 void stm_register_thread_local(stm_thread_local_t *tl);
@@ -59,8 +61,10 @@
 ssize_t stmcb_size_rounded_up(struct object_s *obj);
 
 bool _checked_stm_write(object_t *obj);
+bool _checked_stm_write_card(object_t *obj, uintptr_t index);
 bool _stm_was_read(object_t *obj);
 bool _stm_was_written(object_t *obj);
+bool _stm_was_written_card(object_t *obj);
 char *_stm_get_segment_base(long index);
 bool _stm_in_transaction(stm_thread_local_t *tl);
 int _stm_get_flags(object_t *obj);
@@ -118,8 +122,10 @@
 
 long _stm_count_modified_old_objects(void);
 long _stm_count_objects_pointing_to_nursery(void);
+long _stm_count_old_objects_with_cards_set(void);
 object_t *_stm_enum_modified_old_objects(long index);
 object_t *_stm_enum_objects_pointing_to_nursery(long index);
+object_t *_stm_enum_old_objects_with_cards_set(long index);
 object_t *_stm_next_last_cl_entry();
 void _stm_start_enum_last_cl_entry();
 long _stm_count_cl_entries();
@@ -191,6 +197,10 @@
     CHECKED(stm_write(object));
 }
 
+bool _checked_stm_write_card(object_t *object, uintptr_t index) {
+    CHECKED(stm_write_card(object, index));
+}
+
 bool _check_commit_transaction(void) {
     CHECKED(stm_commit_transaction());
 }
@@ -322,6 +332,25 @@
     }
 }
 
+void stmcb_trace_cards(struct object_s *obj, void visit(object_t **),
+                       uintptr_t start, uintptr_t stop)
+{
+    int i;
+    struct myobj_s *myobj = (struct myobj_s*)obj;
+    assert(myobj->type_id != 421419);
+    assert(myobj->type_id != 421418);
+    if (myobj->type_id < 421420) {
+        /* basic case: no references */
+        return;
+    }
+
+    for (i=start; (i < myobj->type_id - 421420) && (i < stop); i++) {
+        object_t **ref = ((object_t **)(myobj + 1)) + i;
+        visit(ref);
+    }
+}
+
+
 long current_segment_num(void)
 {
     return STM_SEGMENT->segment_num;
@@ -506,11 +535,11 @@
         return None
     return map(lib._stm_enum_objects_pointing_to_nursery, range(count))
 
-def old_objects_with_cards():
-    count = lib._stm_count_old_objects_with_cards()
+def old_objects_with_cards_set():
+    count = lib._stm_count_old_objects_with_cards_set()
     if count < 0:
         return None
-    return map(lib._stm_enum_old_objects_with_cards, range(count))
+    return map(lib._stm_enum_old_objects_with_cards_set, range(count))
 
 def last_commit_log_entry_objs():
     lib._stm_start_enum_last_cl_entry()
diff --git a/c8/test/test_card_marking.py b/c8/test/test_card_marking.py
new file mode 100644
--- /dev/null
+++ b/c8/test/test_card_marking.py
@@ -0,0 +1,223 @@
+from support import *
+import py
+
+
+class TestBasic(BaseTest):
+
+    def _collect(self, kind):
+        if kind == 0:
+            stm_minor_collect()
+        elif kind == 1:
+            stm_major_collect()
+        elif kind == 2:
+            self.switch(1)
+            self.start_transaction()
+            stm_major_collect()
+            self.abort_transaction()
+            self.switch(0)
+
+    def test_simple(self):
+        o = stm_allocate_old_refs(1024)
+        self.start_transaction()
+        stm_read(o)
+        stm_write(o)
+        self.commit_transaction()
+
+    def test_simple2(self):
+        o = stm_allocate_old_refs(1024)
+        self.start_transaction()
+        stm_write_card(o, 5)
+        assert not stm_was_written(o) # don't remove GCFLAG_WRITE_BARRIER
+        assert stm_was_written_card(o)
+        self.commit_transaction()
+
+    @py.test.mark.parametrize("k", range(3))
+    def test_overflow(self, k):
+        self.start_transaction()
+        o = stm_allocate_refs(1024)
+
+        self.push_root(o)
+        self._collect(k)
+        o = self.pop_root()
+
+        stm_write_card(o, 5)
+
+        assert o in old_objects_with_cards()
+        assert o not in modified_old_objects() # overflow object
+        assert o not in objects_pointing_to_nursery()
+        # don't remove GCFLAG_WB
+        assert not stm_was_written(o)
+        stm_write(o)
+        assert stm_was_written(o)
+        self.commit_transaction()
+
+    def test_nursery(self):
+        o = stm_allocate_old_refs(200)
+        self.start_transaction()
+        p = stm_allocate(64)
+        stm_set_ref(o, 199, p, True)
+
+        # without a write-barrier:
+        lib._set_ptr(o, 0, ffi.cast("object_t*", -1))
+
+        self.push_root(o)
+        stm_minor_collect()
+        o = self.pop_root()
+
+        lib._set_ptr(o, 0, ffi.NULL)
+
+        pn = stm_get_ref(o, 199)
+        assert not is_in_nursery(pn)
+        assert pn != p
+
+        assert not stm_was_written(o)
+        stm_write_card(o, 2)
+        assert stm_was_written_card(o)
+
+        # card cleared after last collection,
+        # so no retrace of index 199:
+
+        # without a write-barrier:
+        lib._set_ptr(o, 199, ffi.cast("object_t*", -1))
+        self.push_root(o)
+        stm_minor_collect()
+        o = self.pop_root()
+
+    def test_nursery2(self):
+        o = stm_allocate_old_refs(200)
+        self.start_transaction()
+        p = stm_allocate(64)
+        d = stm_allocate(64)
+        e = stm_allocate(64)
+        stm_set_ref(o, 199, p, True)
+        stm_set_ref(o, 1, d, False)
+        lib._set_ptr(o, 100, e) # no barrier
+
+        self.push_root(o)
+        stm_minor_collect()
+        o = self.pop_root()
+
+        # stm_write in stm_set_ref made it trace everything
+        assert not is_in_nursery(stm_get_ref(o, 199))
+        assert not is_in_nursery(stm_get_ref(o, 1))
+        assert not is_in_nursery(stm_get_ref(o, 100))
+
+    def test_nursery3(self):
+        o = stm_allocate_old_refs(2000)
+        self.start_transaction()
+        stm_minor_collect()
+
+        p = stm_allocate(64)
+        d = stm_allocate(64)
+        stm_set_ref(o, 1999, p, True)
+        stm_set_ref(o, 1, d, True)
+
+        lib._set_ptr(o, 1000, ffi.cast("object_t*", -1))
+
+        assert not stm_was_written(o)
+        assert stm_was_written_card(o)
+
+        self.push_root(o)
+        stm_minor_collect()
+        o = self.pop_root()
+
+        assert not is_in_nursery(stm_get_ref(o, 1999))
+        assert not is_in_nursery(stm_get_ref(o, 1))
+
+
+    def test_abort_cleanup(self):
+        o = stm_allocate_old_refs(200)
+        self.start_transaction()
+        stm_minor_collect()
+
+        p = stm_allocate_refs(64)
+        d = stm_allocate(64)
+        e = stm_allocate(64)
+        stm_set_ref(o, 199, p, True)
+        stm_set_ref(o, 1, d, True)
+        stm_set_ref(p, 1, e)
+
+        self.abort_transaction()
+
+        assert not modified_old_objects()
+        assert not objects_pointing_to_nursery()
+        assert not old_objects_with_cards()
+
+        self.start_transaction()
+        d = stm_allocate(64)
+        e = stm_allocate(64)
+        lib._set_ptr(o, 199, d) # no barrier
+        stm_set_ref(o, 1, e, True) # card barrier
+
+        self.push_root(o)
+        stm_minor_collect()
+        o = self.pop_root()
+
+        assert not is_in_nursery(stm_get_ref(o, 1))
+        assert is_in_nursery(stm_get_ref(o, 199)) # not traced
+
+    @py.test.mark.parametrize("k", range(3))
+    def test_major_gc(self, k):
+        o = stm_allocate_old_refs(200)
+        self.start_transaction()
+        p = stm_allocate(64)
+        stm_set_ref(o, 0, p, True)
+
+        self.push_root(o)
+        stm_major_collect()
+        o = self.pop_root()
+
+        stm_set_ref(o, 1, ffi.NULL, True)
+        p = stm_get_ref(o, 0)
+        assert stm_was_written_card(o)
+
+        self.push_root(o)
+        self._collect(k)
+        o = self.pop_root()
+
+        assert not stm_was_written_card(o)
+        assert stm_get_ref(o, 0) == p
+        self.commit_transaction()
+
+    def test_synchronize_objs(self):
+        o = stm_allocate_old(1000+20*CARD_SIZE)
+
+        self.start_transaction()
+        stm_set_char(o, 'a', 1000, False)
+        self.commit_transaction()
+
+        self.switch(1)
+
+        self.start_transaction()
+        stm_set_char(o, 'b', 1001, False)
+        assert stm_get_char(o, 1000) == 'a'
+        self.commit_transaction()
+
+        self.switch(0)
+
+        self.start_transaction()
+        assert stm_get_char(o, 1001) == 'b'
+
+        stm_set_char(o, 'c', 1000, True)
+        stm_set_char(o, 'c', 1000+CARD_SIZE, True)
+        stm_set_char(o, 'c', 1000+CARD_SIZE*2, True)
+        stm_set_char(o, 'c', 1000+CARD_SIZE*3, True)
+
+        stm_set_char(o, 'd', 1000+CARD_SIZE*10, True)
+
+        stm_set_char(o, 'e', 1000+CARD_SIZE*12, True)
+        self.commit_transaction()
+
+        self.switch(1)
+
+        self.start_transaction()
+        assert stm_get_char(o, 1000) == 'c'
+        assert stm_get_char(o, 1000+CARD_SIZE) == 'c'
+        assert stm_get_char(o, 1000+CARD_SIZE*2) == 'c'
+        assert stm_get_char(o, 1000+CARD_SIZE*3) == 'c'
+
+        assert stm_get_char(o, 1000+CARD_SIZE*10) == 'd'
+
+        assert stm_get_char(o, 1000+CARD_SIZE*12) == 'e'
+
+        self.commit_transaction()
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to