Author: Remi Meier <[email protected]>
Branch: card-marking
Changeset: r1243:ea910eddec2e
Date: 2014-05-23 12:04 +0200
http://bitbucket.org/pypy/stmgc/changeset/ea910eddec2e/
Log: possible change in API (closer to pypy, but needs more nasty
callbacks)
diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -40,9 +40,10 @@
#endif
}
-void _stm_mark_card(object_t *obj, uintptr_t card_index)
+__attribute__((always_inline))
+void _stm_mark_card(object_t *obj, uintptr_t index)
{
- assert(card_index > 0);
+ assert(index != -1);
assert(obj->stm_flags & GCFLAG_HAS_CARDS);
assert(!(obj->stm_flags & GCFLAG_SMALL_UNIFORM)); /* not supported/tested
*/
@@ -54,8 +55,6 @@
/* we need at least one lock in addition to the STM-reserved object
write-lock */
#endif
- dprintf(("mark %p card %lu with %d\n", obj, card_index, CARD_MARKED));
-
if (!(obj->stm_flags & GCFLAG_CARDS_SET)) {
/* not yet in the list */
if (STM_PSEGMENT->old_objects_with_cards) {
@@ -69,24 +68,27 @@
/* 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;
+ uintptr_t card_lock_idx = get_write_lock_idx((uintptr_t)obj);
+ card_lock_idx += get_index_to_card_index(index);
assert(write_locks[get_write_lock_idx((uintptr_t)obj)] == 0 /* overflow
obj */
|| write_locks[get_write_lock_idx((uintptr_t)obj)] ==
STM_PSEGMENT->write_lock_num);
assert(get_write_lock_idx((uintptr_t)obj) != card_lock_idx);
+ dprintf(("mark %p index %lu, card:%lu with %d\n",
+ obj, index, get_index_to_card_index(index), CARD_MARKED));
if (write_locks[card_lock_idx] != CARD_MARKED)
write_locks[card_lock_idx] = CARD_MARKED;
}
-static bool _stm_write_slowpath_overflow_objs(object_t *obj, uintptr_t
card_index)
+static bool _stm_write_slowpath_overflow_objs(object_t *obj, uintptr_t index)
{
/* is this an object from the same transaction, outside the nursery? */
if (IS_OVERFLOW_OBJ(STM_PSEGMENT, obj)) {
assert(STM_PSEGMENT->objects_pointing_to_nursery != NULL);
- dprintf_test(("write_slowpath %p -> ovf obj_to_nurs\n", obj));
+ dprintf_test(("write_slowpath %p -> ovf obj_to_nurs, index:%lu\n",
obj, index));
- if (!card_index) {
+ if (index == -1) {
/* 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);
@@ -94,7 +96,7 @@
/* don't remove GCFLAG_WRITE_BARRIER because we need to be
here for every card to mark */
assert(STM_PSEGMENT->old_objects_with_cards);
- _stm_mark_card(obj, card_index);
+ _stm_mark_card(obj, index);
}
/* We don't need to do anything in the STM part of the WB slowpath: */
@@ -107,26 +109,29 @@
void _stm_write_slowpath(object_t *obj)
{
- _stm_write_slowpath_card(obj, 0);
+ _stm_write_slowpath_card(obj, -1);
}
-void _stm_write_slowpath_card(object_t *obj, uintptr_t card_index)
+void _stm_write_slowpath_card(object_t *obj, uintptr_t index)
{
assert(_seems_to_be_running_transaction());
assert(!_is_young(obj));
assert(obj->stm_flags & GCFLAG_WRITE_BARRIER);
- assert(IMPLY(card_index, (card_index - 1) * CARD_SIZE <
stmcb_size_rounded_up(
- (struct object_s*)REAL_ADDRESS(STM_SEGMENT->segment_base,
obj))));
+ assert(IMPLY(index != -1, index < stmcb_size_rounded_up(
+ (struct object_s*)REAL_ADDRESS(STM_SEGMENT->segment_base,
obj))));
uintptr_t base_lock_idx = get_write_lock_idx((uintptr_t)obj);
uint8_t lock_num = STM_PSEGMENT->write_lock_num;
+ bool mark_cards = index != -1;
+
assert(base_lock_idx < sizeof(write_locks));
+ if (!(obj->stm_flags & GCFLAG_HAS_CARDS)) {
+ index = -1;
+ mark_cards = false; /* assume no cards */
+ }
- if (!(obj->stm_flags & GCFLAG_HAS_CARDS))
- card_index = 0; /* assume no cards */
-
- /* if card_index and obj->stm_flags & CARDS_SET:
- directly mark the card of obj at card_index
+ /* if mark_cards and obj->stm_flags & CARDS_SET:
+ directly mark the card of obj at index
return (no STM part needed)
-> see stmgc.h */
/* if CARDS_SET, we entered here at least once, so we own the write_lock
@@ -137,7 +142,7 @@
|| (IS_OVERFLOW_OBJ(STM_PSEGMENT, obj) &&
write_locks[base_lock_idx] == 0)
));
- if (_stm_write_slowpath_overflow_objs(obj, card_index))
+ if (_stm_write_slowpath_overflow_objs(obj, index))
return;
/* do a read-barrier now. Note that this must occur before the
@@ -233,7 +238,7 @@
/* 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 (!card_index) {
+ if (!mark_cards) {
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);
@@ -246,7 +251,7 @@
} else {
/* don't remove WRITE_BARRIER */
- _stm_mark_card(obj, card_index);
+ _stm_mark_card(obj, index);
}
/* for sanity, check again that all other segment copies of this
@@ -532,7 +537,7 @@
uintptr_t first_card_index = get_write_lock_idx((uintptr_t)obj);
uintptr_t card_index = 1;
- uintptr_t last_card_index = get_card_index(obj_size - 1);
+ uintptr_t last_card_index = get_index_to_card_index(obj_size - 1); /* max
valid index */
long i, myself = STM_SEGMENT->segment_num;
/* simple heuristic to check if probably the whole object is
@@ -554,10 +559,8 @@
try yet to use page_copy() or otherwise take into account privatization
of pages (except _has_private_page_in_range) */
uintptr_t start = 0;
- uintptr_t copy_size = 0;
while (card_index <= last_card_index) {
uintptr_t card_lock_idx = first_card_index + card_index;
- uintptr_t card_byte_offset = get_card_byte_offset(card_index);
uint8_t card_value = write_locks[card_lock_idx];
OPT_ASSERT(card_value != CARD_MARKED); /* always only MARKED_OLD or
CLEAR */
@@ -566,14 +569,8 @@
write_locks[card_lock_idx] = CARD_CLEAR;
if (start == 0) { /* first marked card */
- start = (uintptr_t)obj + card_byte_offset;
- }
-
- copy_size += CARD_SIZE;
-
- if ((start - (uintptr_t)obj) + copy_size > obj_size) {
- /* don't copy over the object's bounds */
- copy_size = obj_size - (start - (uintptr_t)obj);
+ start = (uintptr_t)obj + stmcb_index_to_byte_offset(
+ realobj, get_card_index_to_index(card_index));
}
}
@@ -581,7 +578,17 @@
&& (card_value != CARD_MARKED_OLD /* found non-marked card
*/
|| card_index == last_card_index)) { /* this is the last card
*/
/* do the copying: */
- //dprintf(("copy %lu bytes\n", copy_size));
+ uintptr_t copy_size;
+
+ uintptr_t next_card_offset = stmcb_index_to_byte_offset(
+ realobj, get_card_index_to_index(card_index + 1));
+
+ if (next_card_offset > obj_size)
+ next_card_offset = obj_size;
+
+ copy_size = next_card_offset - (start - (uintptr_t)obj);
+
+ /* dprintf(("copy %lu bytes\n", copy_size)); */
/* since we have marked cards, at least one page here must be
private */
assert(_has_private_page_in_range(myself, start, copy_size));
diff --git a/c7/stm/core.h b/c7/stm/core.h
--- a/c7/stm/core.h
+++ b/c7/stm/core.h
@@ -236,11 +236,11 @@
#define IS_OVERFLOW_OBJ(pseg, obj) (((obj)->stm_flags &
-GCFLAG_OVERFLOW_NUMBER_bit0) \
== (pseg)->overflow_number)
-static inline uintptr_t get_card_index(uintptr_t byte_offset) {
- return (byte_offset / CARD_SIZE) + 1;
+static inline uintptr_t get_index_to_card_index(uintptr_t index) {
+ return (index / CARD_SIZE) + 1;
}
-static inline uintptr_t get_card_byte_offset(uintptr_t card_index) {
+static inline uintptr_t get_card_index_to_index(uintptr_t card_index) {
return (card_index - 1) * CARD_SIZE;
}
diff --git a/c7/stm/nursery.c b/c7/stm/nursery.c
--- a/c7/stm/nursery.c
+++ b/c7/stm/nursery.c
@@ -197,7 +197,7 @@
uintptr_t first_card_index = get_write_lock_idx((uintptr_t)obj);
uintptr_t card_index = 1;
- uintptr_t last_card_index = get_card_index(size - 1);
+ uintptr_t last_card_index = get_index_to_card_index(size - 1); /* max
valid index */
OPT_ASSERT(write_locks[first_card_index] <= NB_SEGMENTS_MAX
|| write_locks[first_card_index] == 255); /* see gcpage.c */
@@ -256,7 +256,7 @@
uintptr_t first_card_index = get_write_lock_idx((uintptr_t)obj);
uintptr_t card_index = 1;
- uintptr_t last_card_index = get_card_index(size - 1);
+ uintptr_t last_card_index = get_index_to_card_index(size - 1); /* max
valid index */
OPT_ASSERT(write_locks[first_card_index] <= NB_SEGMENTS
|| write_locks[first_card_index] == 255); /* see gcpage.c */
@@ -281,39 +281,51 @@
#pragma pop_macro("STM_PSEGMENT")
}
-static __thread object_t *_card_base_obj;
-static void minor_trace_if_young_cards(object_t **pobj)
-{
- /* 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 + get_card_index(
- (uintptr_t)((char*)pobj - STM_SEGMENT->segment_base) -
(uintptr_t)_card_base_obj);
-
- if (write_locks[card_lock_idx] == CARD_MARKED) {
- 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));
assert(obj->stm_flags & GCFLAG_CARDS_SET);
assert(obj->stm_flags & GCFLAG_WRITE_BARRIER);
dprintf(("_trace_card_object(%p)\n", obj));
-
- char *realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
- stmcb_trace((struct object_s *)realobj, &minor_trace_if_young_cards);
-
bool obj_is_overflow = IS_OVERFLOW_OBJ(STM_PSEGMENT, obj);
uint8_t mark_value = obj_is_overflow ? CARD_CLEAR : CARD_MARKED_OLD;
- _reset_object_cards(get_priv_segment(STM_SEGMENT->segment_num),
- obj, mark_value, false); /* mark marked */
+
+ struct object_s *realobj = (struct object_s
*)REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
+ size_t size = stmcb_size_rounded_up(realobj);
+
+ uintptr_t first_card_index = get_write_lock_idx((uintptr_t)obj);
+ uintptr_t card_index = 1;
+ uintptr_t last_card_index = get_index_to_card_index(size - 1); /* max
valid index */
+
+ OPT_ASSERT(write_locks[first_card_index] <= NB_SEGMENTS_MAX
+ || write_locks[first_card_index] == 255); /* see gcpage.c */
+
+ /* XXX: merge ranges */
+ while (card_index <= last_card_index) {
+ uintptr_t card_lock_idx = first_card_index + card_index;
+ if (write_locks[card_lock_idx] == CARD_MARKED) {
+ /* clear or set to old: */
+ write_locks[card_lock_idx] = mark_value;
+
+ uintptr_t start = get_card_index_to_index(card_index);
+ uintptr_t stop = get_card_index_to_index(card_index + 1);
+
+ dprintf(("trace_cards on %p with start:%lu stop:%lu\n",
+ obj, start, stop));
+ stmcb_trace_cards(realobj, &minor_trace_if_young,
+ start, stop);
+
+ }
+
+ /* all cards should be cleared on overflow objs */
+ assert(IMPLY(obj_is_overflow,
+ write_locks[card_lock_idx] == CARD_CLEAR));
+
+ card_index++;
+ }
+ obj->stm_flags &= ~GCFLAG_CARDS_SET;
}
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -225,8 +225,7 @@
of CARD_SIZE. It can only be used on objects one any object, but only
helps with those that were internally marked with GCFLAG_HAS_CARDS
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
+ 'index' can be anything < size of the object
*/
__attribute__((always_inline))
static inline void stm_write_card(object_t *obj, uintptr_t index)
@@ -251,6 +250,12 @@
*/
extern ssize_t stmcb_size_rounded_up(struct object_s *);
extern void stmcb_trace(struct object_s *, void (object_t **));
+extern void stmcb_trace_cards(struct object_s *, void (object_t **),
+ uintptr_t start, uintptr_t stop);
+/* needs to work with index > any valid index (can just return
+ object's size then) */
+extern uintptr_t stmcb_index_to_byte_offset(struct object_s *,
+ uintptr_t index);
extern void stmcb_commit_soon(void);
diff --git a/c7/test/support.py b/c7/test/support.py
--- a/c7/test/support.py
+++ b/c7/test/support.py
@@ -76,7 +76,6 @@
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_card_index(object_t *obj, int n);
void _set_weakref(object_t *obj, object_t *v);
object_t* _get_weakref(object_t *obj);
@@ -268,16 +267,6 @@
return *field;
}
-uintptr_t _index_to_card_index(object_t *obj, int n)
-{
- long nrefs = (long)((myobj_t*)obj)->type_id - 421420;
- assert(n < nrefs);
-
- stm_char *field_addr = NULL;
- field_addr += SIZEOF_MYOBJ; /* header */
- field_addr += n * sizeof(void*); /* field */
- return ((uintptr_t)field_addr / _STM_CARD_SIZE) + 1;
-}
ssize_t stmcb_size_rounded_up(struct object_s *obj)
{
@@ -312,6 +301,32 @@
}
}
+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;
+ 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);
+ }
+}
+
+uintptr_t stmcb_index_to_byte_offset(struct object_s *obj, uintptr_t index)
+{
+ struct myobj_s *myobj = (struct myobj_s*)obj;
+ if (myobj->type_id < 421420) {
+ /* basic case: no references */
+ return sizeof(struct myobj_s) + index;
+ }
+ return sizeof(struct myobj_s) + index * sizeof(object_t*);
+}
+
void stm_push_marker(stm_thread_local_t *tl, uintptr_t onum, object_t *ob)
{
STM_PUSH_MARKER(*tl, onum, ob);
@@ -358,8 +373,6 @@
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)
@@ -402,7 +415,7 @@
def stm_set_ref(obj, idx, ref, use_cards=False):
if use_cards:
- stm_write_card(obj, lib._index_to_card_index(obj, idx))
+ stm_write_card(obj, idx)
else:
stm_write(obj)
lib._set_ptr(obj, idx, ref)
@@ -414,8 +427,7 @@
def stm_set_char(obj, c, offset=HDR, use_cards=False):
assert HDR <= offset < stm_get_obj_size(obj)
if use_cards:
- index = byte_offset_to_card_index(offset)
- stm_write_card(obj, index)
+ stm_write_card(obj, offset)
else:
stm_write(obj)
stm_get_real_address(obj)[offset] = c
diff --git a/c7/test/test_card_marking.py b/c7/test/test_card_marking.py
--- a/c7/test/test_card_marking.py
+++ b/c7/test/test_card_marking.py
@@ -55,41 +55,33 @@
o = stm_allocate_old_refs(200)
self.start_transaction()
p = stm_allocate(64)
- d = stm_allocate(64)
stm_set_ref(o, 199, p, True)
# without a write-barrier:
- lib._set_ptr(o, 0, d)
+ 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
- # d was not traced!
- dn = stm_get_ref(o, 0)
- assert is_in_nursery(dn)
- assert dn == d
-
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:
- d2 = stm_allocate(64)
+
# without a write-barrier:
- lib._set_ptr(o, 199, d2)
+ lib._set_ptr(o, 199, ffi.cast("object_t*", -1))
self.push_root(o)
stm_minor_collect()
o = self.pop_root()
- # d2 was not traced!
- dn = stm_get_ref(o, 199)
- assert is_in_nursery(dn)
- assert dn == d2
def test_nursery2(self):
o = stm_allocate_old_refs(200)
@@ -111,16 +103,16 @@
assert not is_in_nursery(stm_get_ref(o, 100))
def test_nursery3(self):
- o = stm_allocate_old_refs(200)
+ o = stm_allocate_old_refs(2000)
self.start_transaction()
stm_minor_collect()
p = stm_allocate(64)
d = stm_allocate(64)
- e = stm_allocate(64)
- stm_set_ref(o, 199, p, True)
+ stm_set_ref(o, 1999, p, True)
stm_set_ref(o, 1, d, True)
- lib._set_ptr(o, 100, e) # no card marked!
+
+ lib._set_ptr(o, 1000, ffi.cast("object_t*", -1))
assert not stm_was_written(o)
assert stm_was_written_card(o)
@@ -129,9 +121,9 @@
stm_minor_collect()
o = self.pop_root()
- assert not is_in_nursery(stm_get_ref(o, 199))
+ assert not is_in_nursery(stm_get_ref(o, 1999))
assert not is_in_nursery(stm_get_ref(o, 1))
- assert stm_get_ref(o, 100) == e # not traced
+
def test_abort_cleanup(self):
o = stm_allocate_old_refs(200)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit