Author: Remi Meier <[email protected]>
Branch: card-marking
Changeset: r1218:36e751d8b104
Date: 2014-05-20 13:12 +0200
http://bitbucket.org/pypy/stmgc/changeset/36e751d8b104/
Log: change the interface from offset to index (and finally add the
forgotten tests)
diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -40,7 +40,29 @@
#endif
}
-static bool _stm_write_slowpath_overflow_objs(object_t *obj, uintptr_t offset)
+static void _stm_mark_card(object_t *obj, uintptr_t card_index)
+{
+ if (!(obj->stm_flags & GCFLAG_CARDS_SET)) {
+ /* not yet in the list */
+ if (STM_PSEGMENT->old_objects_with_cards) {
+ /* if we never had a minor collection in this transaction,
+ this list doesn't exist */
+ LIST_APPEND(STM_PSEGMENT->old_objects_with_cards, obj);
+ }
+ obj->stm_flags |= GCFLAG_CARDS_SET;
+ }
+
+ /* Just acquire the corresponding lock for the next minor_collection
+ to know what may have changed.
+ We already own the object here or it is an overflow obj. */
+ uintptr_t card_lock_idx = get_write_lock_idx((uintptr_t)obj) + card_index;
+ assert(write_locks[card_lock_idx] == 0
+ || write_locks[card_lock_idx] == STM_PSEGMENT->write_lock_num);
+ if (!write_locks[card_lock_idx])
+ write_locks[card_lock_idx] = STM_PSEGMENT->write_lock_num;
+}
+
+static bool _stm_write_slowpath_overflow_objs(object_t *obj, uintptr_t
card_index)
{
/* is this an object from the same transaction, outside the nursery? */
if ((obj->stm_flags & -GCFLAG_OVERFLOW_NUMBER_bit0)
@@ -49,24 +71,15 @@
assert(STM_PSEGMENT->objects_pointing_to_nursery != NULL);
dprintf_test(("write_slowpath %p -> ovf obj_to_nurs\n", obj));
- if (!offset) {
- /* no card to be marked */
+ if (!card_index) {
+ /* no card to be marked, don't call again until next collection */
obj->stm_flags &= ~GCFLAG_WRITE_BARRIER;
LIST_APPEND(STM_PSEGMENT->objects_pointing_to_nursery, obj);
} else {
/* don't remove GCFLAG_WRITE_BARRIER because we need to be
here for every card to mark */
- if (!(obj->stm_flags & GCFLAG_CARDS_SET)) {
- /* not yet in the list */
- LIST_APPEND(STM_PSEGMENT->old_objects_with_cards, obj);
- obj->stm_flags |= GCFLAG_CARDS_SET;
- }
-
- /* just acquire the corresponding lock for the next
minor_collection
- to know what may have changed. only we know about this object:
*/
- uintptr_t lock_idx = get_write_lock_idx((uintptr_t)obj + offset);
- assert(!write_locks[lock_idx]);
- write_locks[lock_idx] = STM_PSEGMENT->write_lock_num;
+ assert(STM_PSEGMENT->old_objects_with_cards);
+ _stm_mark_card(obj, card_index);
}
/* We don't need to do anything in the STM part of the WB slowpath: */
@@ -77,14 +90,18 @@
return false;
}
-void _stm_write_slowpath(object_t *obj, uintptr_t offset)
+void _stm_write_slowpath(object_t *obj, uintptr_t card_index)
{
- assert(IMPLY(!(obj->stm_flags & GCFLAG_HAS_CARDS), offset == 0));
+ assert(IMPLY(!(obj->stm_flags & GCFLAG_HAS_CARDS), card_index == 0));
+ assert(
+ IMPLY(card_index, (card_index - 1) * CARD_SIZE < stmcb_size_rounded_up(
+ (struct object_s*)REAL_ADDRESS(STM_SEGMENT->segment_base,
+ obj))));
assert(_seems_to_be_running_transaction());
assert(!_is_young(obj));
assert(obj->stm_flags & GCFLAG_WRITE_BARRIER);
- if (_stm_write_slowpath_overflow_objs(obj, offset))
+ if (_stm_write_slowpath_overflow_objs(obj, card_index))
return;
/* do a read-barrier now. Note that this must occur before the
@@ -98,9 +115,7 @@
'modified_old_objects' (but, because it had GCFLAG_WRITE_BARRIER,
not in 'objects_pointing_to_nursery'). We'll detect this case
by finding that we already own the write-lock. */
- bool lock_whole = offset == 0;
uintptr_t base_lock_idx = get_write_lock_idx((uintptr_t)obj);
- //uintptr_t card_lock_idx = get_write_lock_idx((uintptr_t)obj + offset);
uint8_t lock_num = STM_PSEGMENT->write_lock_num;
assert(base_lock_idx < sizeof(write_locks));
retry:
@@ -175,43 +190,36 @@
goto retry;
}
+
+ /* check that we really have a private page */
+ assert(is_private_page(STM_SEGMENT->segment_num,
+ ((uintptr_t)obj) / 4096));
+
+ /* check that so far all copies of the object have the flag */
+ check_flag_write_barrier(obj);
+
/* A common case for write_locks[] that was either 0 or lock_num:
we need to add the object to the appropriate list if there is one. */
- if (lock_whole) {
+ if (!card_index) {
if (STM_PSEGMENT->objects_pointing_to_nursery != NULL) {
dprintf_test(("write_slowpath %p -> old obj_to_nurs\n", obj));
LIST_APPEND(STM_PSEGMENT->objects_pointing_to_nursery, obj);
}
- /* check that we really have a private page */
- assert(is_private_page(STM_SEGMENT->segment_num,
- ((uintptr_t)obj) / 4096));
- /* check that so far all copies of the object have the flag */
- check_flag_write_barrier(obj);
-
/* remove GCFLAG_WRITE_BARRIER if we succeeded in getting the base
write-lock (not for card marking). */
assert(obj->stm_flags & GCFLAG_WRITE_BARRIER);
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);
+ } else {
+ /* don't remove WRITE_BARRIER */
+ _stm_mark_card(obj, card_index);
+ }
- } else { /* card marking case */
+ /* for sanity, check again that all other segment copies of this
+ object still have the flag (so privatization worked) */
+ check_flag_write_barrier(obj);
- if (!(obj->stm_flags & GCFLAG_CARDS_SET)) {
- /* not yet in the list (may enter here multiple times) */
- if (STM_PSEGMENT->old_objects_with_cards != NULL) {
- LIST_APPEND(STM_PSEGMENT->old_objects_with_cards, obj);
- }
- obj->stm_flags |= GCFLAG_CARDS_SET;
- }
-
- /* check that we really have a private page */
- assert(is_private_page(STM_SEGMENT->segment_num,
- ((uintptr_t)obj + offset) / 4096));
- }
}
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
@@ -226,6 +226,10 @@
#define REAL_ADDRESS(segment_base, src) ((segment_base) + (uintptr_t)(src))
+static inline uintptr_t get_card_index(uintptr_t byte_offset) {
+ assert(_STM_CARD_SIZE == 32);
+ return (byte_offset >> 5) + 1;
+}
static inline uintptr_t get_write_lock_idx(uintptr_t obj) {
return (obj >> 4) - WRITELOCK_START;
}
@@ -262,15 +266,6 @@
return rm == other_transaction_read_version;
}
-static inline bool was_read_remote_card(char *base, object_t *obj, uintptr_t
offset,
- uint8_t other_transaction_read_version)
-{
- uint8_t rm = ((struct stm_read_marker_s *)
- (base + (((uintptr_t)obj + offset) >> 4)))->rm;
- assert(rm <= other_transaction_read_version);
- return rm == other_transaction_read_version;
-}
-
static inline void _duck(void) {
/* put a call to _duck() between two instructions that set 0 into
a %gs-prefixed address and that may otherwise be replaced with
diff --git a/c7/stm/misc.c b/c7/stm/misc.c
--- a/c7/stm/misc.c
+++ b/c7/stm/misc.c
@@ -40,12 +40,6 @@
return (obj->stm_flags & _STM_GCFLAG_WRITE_BARRIER) == 0;
}
-bool _stm_was_read_card(object_t *obj, uintptr_t offset)
-{
- return was_read_remote_card(
- STM_SEGMENT->segment_base, obj, offset,
- STM_SEGMENT->transaction_read_version);
-}
bool _stm_was_written_card(object_t *obj)
{
diff --git a/c7/stm/nursery.c b/c7/stm/nursery.c
--- a/c7/stm/nursery.c
+++ b/c7/stm/nursery.c
@@ -183,16 +183,32 @@
minor_trace_if_young(&tl->thread_local_obj);
}
+static __thread object_t *_card_base_obj;
static void minor_trace_if_young_cards(object_t **pobj)
{
- /* XXX: maybe add a specialised stmcb_trace_cards() */
- uintptr_t obj = (uintptr_t)((char*)pobj - STM_SEGMENT->segment_base);
- if (write_locks[get_write_lock_idx(obj)]) {
+ /* XXX: add a specialised stmcb_trace_cards() that
+ also gives the obj-base */
+ assert(_card_base_obj);
+ uintptr_t base_lock_idx = get_write_lock_idx((uintptr_t)_card_base_obj);
+ uintptr_t card_lock_idx = base_lock_idx;
+ card_lock_idx += get_card_index(
+ (uintptr_t)((char*)pobj - STM_SEGMENT->segment_base) -
(uintptr_t)_card_base_obj);
+
+ if (write_locks[card_lock_idx]) {
dprintf(("minor_trace_if_young_cards: trace %p\n", *pobj));
minor_trace_if_young(pobj);
}
}
+static void _trace_card_object(object_t *obj)
+{
+ /* XXX HACK XXX: */
+ _card_base_obj = obj;
+ assert(!_is_in_nursery(obj));
+ char *realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
+ stmcb_trace((struct object_s *)realobj, &minor_trace_if_young_cards);
+}
+
static inline void _collect_now(object_t *obj)
{
assert(!_is_young(obj));
@@ -212,9 +228,7 @@
} else {
/* only trace cards */
dprintf(("-> has cards\n"));
- assert(!_is_in_nursery(obj));
- char *realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
- stmcb_trace((struct object_s *)realobj, &minor_trace_if_young_cards);
+ _trace_card_object(obj);
}
/* clear the CARDS_SET, but not the real cards since they are
diff --git a/c7/stm/setup.c b/c7/stm/setup.c
--- a/c7/stm/setup.c
+++ b/c7/stm/setup.c
@@ -84,7 +84,7 @@
/* Check that some values are acceptable */
assert(NB_SEGMENTS <= NB_SEGMENTS_MAX);
assert(CARD_SIZE > 0 && CARD_SIZE % 16 == 0);
- assert(CARD_SIZE == 16); /* actually, it is hardcoded in some places
right now.. */
+ assert(CARD_SIZE == 32); /* actually, it is hardcoded in some places
right now.. */
assert(4096 <= ((uintptr_t)STM_SEGMENT));
assert((uintptr_t)STM_SEGMENT == (uintptr_t)STM_PSEGMENT);
assert(((uintptr_t)STM_PSEGMENT) + sizeof(*STM_PSEGMENT) <= 8192);
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -120,7 +120,6 @@
#include <stdbool.h>
bool _stm_was_read(object_t *obj);
bool _stm_was_written(object_t *obj);
-bool _stm_was_read_card(object_t *obj, uintptr_t offset);
bool _stm_was_written_card(object_t *obj);
uintptr_t _stm_get_private_page(uintptr_t pagenum);
bool _stm_in_transaction(stm_thread_local_t *tl);
@@ -147,7 +146,7 @@
#define _STM_GCFLAG_WRITE_BARRIER 0x01
#define _STM_GCFLAG_HAS_CARDS 0x08
#define _STM_GCFLAG_CARDS_SET 0x10
-#define _STM_CARD_SIZE 16 /* modulo 16 == 0! */
+#define _STM_CARD_SIZE 32 /* 16 may be safe too */
#define _STM_NSE_SIGNAL_MAX _STM_TIME_N
#define _STM_FAST_ALLOC (66*1024)
@@ -218,21 +217,18 @@
_stm_write_slowpath(obj, 0);
}
-/* The following are barriers that work on the granularity of CARD_SIZE.
- They can only be used on objects one called stm_use_cards() on. */
+/* The following is a GC-optimized barrier that works on the granularity
+ of CARD_SIZE. It can only be used on objects one called stm_use_cards()
+ on. It has the same purpose as stm_write() for TM.
+ 'index' is the byte-offset into the object divided by _STM_CARD_SIZE
+ plus 1: (offset // CARD_SIZE) + 1
+*/
__attribute__((always_inline))
-static inline void stm_read_card(object_t *obj, uintptr_t offset)
-{
- OPT_ASSERT(obj->stm_flags & _STM_GCFLAG_HAS_CARDS);
- ((stm_read_marker_t *)(((uintptr_t)obj + offset) >> 4))->rm =
- STM_SEGMENT->transaction_read_version;
-}
-__attribute__((always_inline))
-static inline void stm_write_card(object_t *obj, uintptr_t offset)
+static inline void stm_write_card(object_t *obj, uintptr_t index)
{
OPT_ASSERT(obj->stm_flags & _STM_GCFLAG_HAS_CARDS);
if (UNLIKELY((obj->stm_flags & _STM_GCFLAG_WRITE_BARRIER) != 0))
- _stm_write_slowpath(obj, offset);
+ _stm_write_slowpath(obj, index);
}
/* Must be provided by the user of this library.
diff --git a/c7/test/support.py b/c7/test/support.py
--- a/c7/test/support.py
+++ b/c7/test/support.py
@@ -44,7 +44,6 @@
object_t *_stm_allocate_old(ssize_t size_rounded_up);
void stm_use_cards(object_t* o);
-void stm_read_card(object_t *obj, uintptr_t offset);
/*void stm_write_card(); use _checked_stm_write_card() instead */
@@ -56,9 +55,8 @@
object_t *stm_setup_prebuilt_weakref(object_t *);
bool _checked_stm_write(object_t *obj);
-bool _checked_stm_write_card(object_t *obj, uintptr_t offset);
+bool _checked_stm_write_card(object_t *obj, uintptr_t index);
bool _stm_was_read(object_t *obj);
-bool _stm_was_read_card(object_t *obj, uintptr_t offset);
bool _stm_was_written(object_t *obj);
bool _stm_was_written_card(object_t *obj);
char *_stm_real_address(object_t *obj);
@@ -79,7 +77,7 @@
uint32_t _get_type_id(object_t *obj);
void _set_ptr(object_t *obj, int n, object_t *v);
object_t * _get_ptr(object_t *obj, int n);
-uintptr_t _index_to_offset(object_t *obj, int n);
+uintptr_t _index_to_card_index(object_t *obj, int n);
void _set_weakref(object_t *obj, object_t *v);
object_t* _get_weakref(object_t *obj);
@@ -192,8 +190,8 @@
CHECKED(stm_write(object));
}
-bool _checked_stm_write_card(object_t *object, uintptr_t offset) {
- CHECKED(stm_write_card(object, offset));
+bool _checked_stm_write_card(object_t *object, uintptr_t index) {
+ CHECKED(stm_write_card(object, index));
}
bool _check_stop_safe_point(void) {
@@ -268,7 +266,7 @@
return *field;
}
-uintptr_t _index_to_offset(object_t *obj, int n)
+uintptr_t _index_to_card_index(object_t *obj, int n)
{
long nrefs = (long)((myobj_t*)obj)->type_id - 421420;
assert(n < nrefs);
@@ -276,7 +274,7 @@
stm_char *field_addr = NULL;
field_addr += SIZEOF_MYOBJ; /* header */
field_addr += n * sizeof(void*); /* field */
- return (uintptr_t)field_addr;
+ return ((uintptr_t)field_addr / _STM_CARD_SIZE) + 1;
}
ssize_t stmcb_size_rounded_up(struct object_s *obj)
@@ -358,6 +356,8 @@
class EmptyStack(Exception):
pass
+def byte_offset_to_card_index(offset):
+ return (offset // CARD_SIZE) + 1
def is_in_nursery(o):
return lib.stm_can_move(o)
@@ -408,32 +408,27 @@
def stm_set_ref(obj, idx, ref, use_cards=False):
if use_cards:
- stm_write_card(obj, lib._index_to_offset(obj, idx))
+ stm_write_card(obj, lib._index_to_card_index(obj, idx))
else:
stm_write(obj)
lib._set_ptr(obj, idx, ref)
-def stm_get_ref(obj, idx, use_cards=False):
- if use_cards:
- stm_read_card(obj, lib._index_to_offset(obj, idx))
- else:
- stm_read(obj)
+def stm_get_ref(obj, idx):
+ stm_read(obj)
return lib._get_ptr(obj, idx)
def stm_set_char(obj, c, offset=HDR, use_cards=False):
assert HDR <= offset < stm_get_obj_size(obj)
if use_cards:
- stm_write_card(obj, offset)
+ index = byte_offset_to_card_index(offset)
+ stm_write_card(obj, index)
else:
stm_write(obj)
stm_get_real_address(obj)[offset] = c
-def stm_get_char(obj, offset=HDR, use_cards=False):
+def stm_get_char(obj, offset=HDR):
assert HDR <= offset < stm_get_obj_size(obj)
- if use_cards:
- stm_read_card(obj, offset)
- else:
- stm_read(obj)
+ stm_read(obj)
return stm_get_real_address(obj)[offset]
def stm_get_real_address(obj):
@@ -442,19 +437,14 @@
def stm_read(o):
lib.stm_read(o)
-def stm_read_card(o, offset):
- assert stm_get_flags(o) & GCFLAG_HAS_CARDS
- assert offset < stm_get_obj_size(o)
- lib.stm_read_card(o, offset)
def stm_write(o):
if lib._checked_stm_write(o):
raise Conflict()
-def stm_write_card(o, offset):
+def stm_write_card(o, index):
assert stm_get_flags(o) & GCFLAG_HAS_CARDS
- assert offset < stm_get_obj_size(o)
- if lib._checked_stm_write_card(o, offset):
+ if lib._checked_stm_write_card(o, index):
raise Conflict()
def stm_was_read(o):
@@ -463,9 +453,6 @@
def stm_was_written(o):
return lib._stm_was_written(o)
-def stm_was_read_card(o, offset):
- return lib._stm_was_read_card(o, offset)
-
def stm_was_written_card(o):
return lib._stm_was_written_card(o)
diff --git a/c7/test/test_card_marking.py b/c7/test/test_card_marking.py
new file mode 100644
--- /dev/null
+++ b/c7/test/test_card_marking.py
@@ -0,0 +1,56 @@
+from support import *
+import py
+
+class TestBasic(BaseTest):
+
+ def test_simple(self):
+ o = stm_allocate_old(1024, True)
+ self.start_transaction()
+ stm_read(o)
+ stm_write(o)
+ self.commit_transaction()
+
+
+ def test_simple2(self):
+ o = stm_allocate_old(1024, True)
+ 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()
+
+ def test_overflow(self):
+ self.start_transaction()
+ o = stm_allocate(1024, True)
+ self.push_root(o)
+ stm_minor_collect()
+ o = self.pop_root()
+ stm_write_card(o, 5)
+ # 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, True)
+ self.start_transaction()
+ p = stm_allocate(64, True)
+ d = stm_allocate(64, True)
+ stm_set_ref(o, 199, p, True)
+
+ # without a write-barrier:
+ lib._set_ptr(o, 0, d)
+
+ self.push_root(o)
+ stm_minor_collect()
+ o = self.pop_root()
+
+ pn = stm_get_ref(o, 199)
+ assert not is_in_nursery(pn)
+ assert pn != p
+
+ # d was not traced!
+ dn = stm_get_ref(o, 0)
+ assert is_in_nursery(dn)
+ assert dn == d
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit