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