Author: Remi Meier <[email protected]>
Branch: card-marking
Changeset: r1232:10b45dc9310d
Date: 2014-05-22 16:24 +0200
http://bitbucket.org/pypy/stmgc/changeset/10b45dc9310d/
Log: change of API; like in pypy CARDS are done internally
diff --git a/c7/stm/contention.c b/c7/stm/contention.c
--- a/c7/stm/contention.c
+++ b/c7/stm/contention.c
@@ -194,7 +194,7 @@
/* tell the other to commit ASAP, since it causes aborts */
signal_other_to_commit_soon(contmgr.other_pseg);
- dprintf(("abort in contention\n"));
+ dprintf(("abort in contention: kind %d\n", kind));
STM_SEGMENT->nursery_end = abort_category;
marker_contention(kind, false, other_segment_num, obj);
abort_with_mutex();
diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -83,7 +83,6 @@
{
/* 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));
@@ -106,17 +105,23 @@
return false;
}
-void _stm_write_slowpath(object_t *obj, uintptr_t card_index)
+void _stm_write_slowpath(object_t *obj)
{
- 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))));
+ _stm_write_slowpath_card(obj, 0);
+}
+
+void _stm_write_slowpath_card(object_t *obj, uintptr_t card_index)
+{
assert(_seems_to_be_running_transaction());
assert(!_is_young(obj));
assert(obj->stm_flags & GCFLAG_WRITE_BARRIER);
+ if (!(obj->stm_flags & GCFLAG_HAS_CARDS))
+ card_index = 0; /* assume no cards */
+
+ assert(IMPLY(card_index, (card_index - 1) * CARD_SIZE <
stmcb_size_rounded_up(
+ (struct object_s*)REAL_ADDRESS(STM_SEGMENT->segment_base,
obj))));
+
if (_stm_write_slowpath_overflow_objs(obj, card_index))
return;
@@ -353,6 +358,8 @@
({
if (was_read_remote(remote_base, item, remote_version)) {
/* A write-read conflict! */
+ dprintf(("write-read conflict on %p, our seg: %d, other:
%ld\n",
+ item, STM_SEGMENT->segment_num, i));
if (write_read_contention_management(i, item)) {
/* If we reach this point, we didn't abort, but we
had to wait for the other thread to commit. If we
diff --git a/c7/stm/gcpage.c b/c7/stm/gcpage.c
--- a/c7/stm/gcpage.c
+++ b/c7/stm/gcpage.c
@@ -119,6 +119,8 @@
object_t *o = (object_t *)(p - stm_object_pages);
o->stm_flags = GCFLAG_WRITE_BARRIER;
+ if (size_rounded_up > CARD_SIZE)
+ o->stm_flags |= GCFLAG_HAS_CARDS;
if (testing_prebuilt_objs == NULL)
testing_prebuilt_objs = list_create();
diff --git a/c7/stm/nursery.c b/c7/stm/nursery.c
--- a/c7/stm/nursery.c
+++ b/c7/stm/nursery.c
@@ -114,6 +114,8 @@
copy_large_object:;
char *realnobj = REAL_ADDRESS(STM_SEGMENT->segment_base, nobj);
memcpy(realnobj, realobj, size);
+ if (size > CARD_SIZE)
+ nobj->stm_flags |= GCFLAG_HAS_CARDS;
nobj_sync_now = ((uintptr_t)nobj) | FLAG_SYNC_LARGE;
}
@@ -149,6 +151,7 @@
/* Must trace the object later */
LIST_APPEND(STM_PSEGMENT->objects_pointing_to_nursery, nobj_sync_now);
+ _cards_cleared_in_object(get_priv_segment(STM_SEGMENT->segment_num), nobj);
}
static void collect_roots_in_nursery(void)
@@ -332,19 +335,20 @@
if (obj->stm_flags & GCFLAG_HAS_CARDS) {
/* all objects that had WB cleared need to be fully synchronised
on commit, so we have to mark all their cards */
+ struct stm_priv_segment_info_s *pseg = get_priv_segment(
+ STM_SEGMENT->segment_num);
+
if (was_definitely_young) {
- /* we don't mark cards on young objects */
+ /* stm_wb-slowpath should never have triggered for young objs
*/
assert(!(obj->stm_flags & GCFLAG_CARDS_SET));
return;
}
if (IS_OVERFLOW_OBJ(STM_PSEGMENT, obj)) {
/* we do not need the old cards for overflow objects */
- _reset_object_cards(get_priv_segment(STM_SEGMENT->segment_num),
- obj, CARD_CLEAR, false);
+ _reset_object_cards(pseg, obj, CARD_CLEAR, false);
} else {
- _reset_object_cards(get_priv_segment(STM_SEGMENT->segment_num),
- obj, CARD_MARKED_OLD, true); /* mark all */
+ _reset_object_cards(pseg, obj, CARD_MARKED_OLD, true); /* mark
all */
}
}
} if (obj->stm_flags & GCFLAG_CARDS_SET) {
@@ -362,6 +366,7 @@
while (!list_is_empty(lst)) {
object_t *obj = (object_t*)list_pop_item(lst);
+ assert(!_is_young(obj));
assert(obj->stm_flags & GCFLAG_CARDS_SET);
_collect_now(obj, false);
assert(!(obj->stm_flags & GCFLAG_CARDS_SET));
@@ -640,6 +645,10 @@
char *result = allocate_outside_nursery_large(size_rounded_up);
object_t *o = (object_t *)(result - stm_object_pages);
+
+ if (size_rounded_up > CARD_SIZE)
+ o->stm_flags |= GCFLAG_HAS_CARDS;
+
tree_insert(STM_PSEGMENT->young_outside_nursery, (uintptr_t)o, 0);
memset(REAL_ADDRESS(STM_SEGMENT->segment_base, o), 0, size_rounded_up);
@@ -741,6 +750,9 @@
memcpy(realnobj, realobj, size);
obj->stm_flags |= GCFLAG_HAS_SHADOW;
+ if (size > CARD_SIZE) /* probably not necessary */
+ nobj->stm_flags |= GCFLAG_HAS_CARDS;
+
tree_insert(STM_PSEGMENT->nursery_objects_shadows,
(uintptr_t)obj, (uintptr_t)nobj);
return nobj;
diff --git a/c7/stm/nursery.h b/c7/stm/nursery.h
--- a/c7/stm/nursery.h
+++ b/c7/stm/nursery.h
@@ -6,6 +6,7 @@
static uint32_t highest_overflow_number;
+static void _cards_cleared_in_object(struct stm_priv_segment_info_s *pseg,
object_t *obj);
static void _reset_object_cards(struct stm_priv_segment_info_s *pseg,
object_t *obj, uint8_t mark_value,
bool mark_all);
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -106,7 +106,8 @@
/* this should use llvm's coldcc calling convention,
but it's not exposed to C code so far */
-void _stm_write_slowpath(object_t *, uintptr_t);
+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*);
@@ -216,7 +217,7 @@
static inline void stm_write(object_t *obj)
{
if (UNLIKELY((obj->stm_flags & _STM_GCFLAG_WRITE_BARRIER) != 0))
- _stm_write_slowpath(obj, 0);
+ _stm_write_slowpath(obj);
}
/* The following is a GC-optimized barrier that works on the granularity
@@ -228,9 +229,8 @@
__attribute__((always_inline))
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, index);
+ _stm_write_slowpath_card(obj, index);
}
/* Must be provided by the user of this library.
@@ -268,17 +268,6 @@
return (object_t *)p;
}
-/* directly after allocation one can enable card marking for any
- kind of object with stm_use_cards(obj). This enables the use
- of stm_write/read_card() barriers that do more fine-grained
- conflict detection and garbage collection.
- These objects need to be at least 32bytes in size!
-*/
-__attribute__((always_inline))
-static inline void stm_use_cards(object_t* o)
-{
- o->stm_flags |= _STM_GCFLAG_HAS_CARDS;
-}
/* Allocate a weakref object. Weakref objects have a
reference to an object at the byte-offset
diff --git a/c7/test/support.py b/c7/test/support.py
--- a/c7/test/support.py
+++ b/c7/test/support.py
@@ -43,7 +43,6 @@
object_t *stm_allocate_weakref(ssize_t size_rounded_up);
object_t *_stm_allocate_old(ssize_t size_rounded_up);
-void stm_use_cards(object_t* o);
/*void stm_write_card(); use _checked_stm_write_card() instead */
@@ -352,7 +351,7 @@
GCFLAG_HAS_CARDS = lib._STM_GCFLAG_HAS_CARDS
CARD_SIZE = lib._STM_CARD_SIZE # 16b at least
NB_SEGMENTS = lib.STM_NB_SEGMENTS
-
+FAST_ALLOC = lib._STM_FAST_ALLOC
class Conflict(Exception):
pass
@@ -365,26 +364,20 @@
def is_in_nursery(o):
return lib.stm_can_move(o)
-def stm_allocate_old(size, use_cards=False):
+def stm_allocate_old(size):
o = lib._stm_allocate_old(size)
- if use_cards:
- lib.stm_use_cards(o)
tid = 42 + size
lib._set_type_id(o, tid)
return o
-def stm_allocate_old_refs(n, use_cards=False):
+def stm_allocate_old_refs(n):
o = lib._stm_allocate_old(HDR + n * WORD)
- if use_cards:
- lib.stm_use_cards(o)
tid = 421420 + n
lib._set_type_id(o, tid)
return o
-def stm_allocate(size, use_cards=False):
+def stm_allocate(size):
o = lib.stm_allocate(size)
- if use_cards:
- lib.stm_use_cards(o)
tid = 42 + size
lib._set_type_id(o, tid)
return o
@@ -401,10 +394,8 @@
def stm_get_weakref(o):
return lib._get_weakref(o)
-def stm_allocate_refs(n, use_cards=False):
+def stm_allocate_refs(n):
o = lib.stm_allocate(HDR + n * WORD)
- if use_cards:
- lib.stm_use_cards(o)
tid = 421420 + n
lib._set_type_id(o, tid)
return o
@@ -446,7 +437,6 @@
raise Conflict()
def stm_write_card(o, index):
- assert stm_get_flags(o) & GCFLAG_HAS_CARDS
if lib._checked_stm_write_card(o, index):
raise Conflict()
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
@@ -17,14 +17,14 @@
self.switch(0)
def test_simple(self):
- o = stm_allocate_old(1024, True)
+ o = stm_allocate_old(1024)
self.start_transaction()
stm_read(o)
stm_write(o)
self.commit_transaction()
def test_simple2(self):
- o = stm_allocate_old(1024, True)
+ o = stm_allocate_old(1024)
self.start_transaction()
stm_write_card(o, 5)
assert not stm_was_written(o) # don't remove GCFLAG_WRITE_BARRIER
@@ -34,7 +34,7 @@
@py.test.mark.parametrize("k", range(3))
def test_overflow(self, k):
self.start_transaction()
- o = stm_allocate(1024, True)
+ o = stm_allocate(1024)
self.push_root(o)
self._collect(k)
@@ -52,10 +52,10 @@
self.commit_transaction()
def test_nursery(self):
- o = stm_allocate_old_refs(200, True)
+ o = stm_allocate_old_refs(200)
self.start_transaction()
- p = stm_allocate(64, True)
- d = stm_allocate(64, True)
+ p = stm_allocate(64)
+ d = stm_allocate(64)
stm_set_ref(o, 199, p, True)
# without a write-barrier:
@@ -80,7 +80,7 @@
# card cleared after last collection,
# so no retrace of index 199:
- d2 = stm_allocate(64, True)
+ d2 = stm_allocate(64)
# without a write-barrier:
lib._set_ptr(o, 199, d2)
self.push_root(o)
@@ -92,7 +92,7 @@
assert dn == d2
def test_nursery2(self):
- o = stm_allocate_old_refs(200, True)
+ o = stm_allocate_old_refs(200)
self.start_transaction()
p = stm_allocate(64)
d = stm_allocate(64)
@@ -111,7 +111,7 @@
assert not is_in_nursery(stm_get_ref(o, 100))
def test_nursery3(self):
- o = stm_allocate_old_refs(200, True)
+ o = stm_allocate_old_refs(200)
self.start_transaction()
stm_minor_collect()
@@ -134,7 +134,7 @@
assert stm_get_ref(o, 100) == e # not traced
def test_abort_cleanup(self):
- o = stm_allocate_old_refs(200, True)
+ o = stm_allocate_old_refs(200)
self.start_transaction()
stm_minor_collect()
@@ -166,7 +166,7 @@
@py.test.mark.parametrize("k", range(3))
def test_major_gc(self, k):
- o = stm_allocate_old_refs(200, True)
+ o = stm_allocate_old_refs(200)
self.start_transaction()
p = stm_allocate(64)
stm_set_ref(o, 0, p, True)
@@ -188,7 +188,7 @@
self.commit_transaction()
def test_synchronize_objs(self):
- o = stm_allocate_old(2000, True)
+ o = stm_allocate_old(2000)
self.start_transaction()
stm_set_char(o, 'a', 1000, False)
diff --git a/c7/test/test_random.py b/c7/test/test_random.py
--- a/c7/test/test_random.py
+++ b/c7/test/test_random.py
@@ -36,17 +36,22 @@
# we win but cannot wait in tests...
raise WriteWriteConflictNotTestable
- if our_trs.inevitable:
+ if our_trs.start_time >= other_trs.start_time:
+ abort_other = False
+ else:
+ abort_other = True
+
+ if other_trs.check_must_abort():
+ abort_other = True
+ elif our_trs.inevitable:
+ abort_other = True
+ elif other_trs.inevitable:
+ abort_other = False
+
+ if not abort_other:
+ our_trs.set_must_abort(objs_in_conflict)
+ else:
other_trs.set_must_abort(objs_in_conflict)
- elif other_trs.start_time < our_trs.start_time:
- pass
- elif not other_trs.inevitable:
- other_trs.set_must_abort(objs_in_conflict)
-
- if not other_trs.check_must_abort():
- our_trs.set_must_abort(objs_in_conflict)
- elif wait:
- assert not our_trs.inevitable
class TransactionState(object):
@@ -227,19 +232,14 @@
self.root_numbering = 0
self.ref_type_map = {}
self.root_sizes = {}
- self.with_cards = {}
- def get_new_root_name(self, is_ref_type, size, with_cards):
+ def get_new_root_name(self, is_ref_type, size):
self.root_numbering += 1
r = "lp_%s_%d" % ("ref" if is_ref_type else "char",
self.root_numbering)
self.ref_type_map[r] = is_ref_type
self.root_sizes[r] = size
- self.with_cards[r] = with_cards
return r
- def has_cards(self, r):
- return self.with_cards[r]
-
def has_ref_type(self, r):
return self.ref_type_map[r]
@@ -368,11 +368,10 @@
#"SOME_MEDIUM_SIZE+16",
#"SOME_LARGE_SIZE+16",
])
- with_cards = int(size) >= 32 and global_state.rnd.randrange(1, 100) > 10
- r = global_state.get_new_root_name(False, size, with_cards)
+ r = global_state.get_new_root_name(False, size)
thread_state.push_roots(ex)
- ex.do('%s = stm_allocate(%s, %s)' % (r, size, bool(with_cards)))
+ ex.do('%s = stm_allocate(%s)' % (r, size))
ex.do('# 0x%x' % (int(ffi.cast("uintptr_t", ex.content[r]))))
thread_state.transaction_state.add_root(r, 0, True)
@@ -382,10 +381,9 @@
def op_allocate_ref(ex, global_state, thread_state):
num = str(global_state.rnd.randrange(1, 100))
- with_cards = int(num) >= 4 and global_state.rnd.randrange(1, 100) > 10
- r = global_state.get_new_root_name(True, num, with_cards)
+ r = global_state.get_new_root_name(True, num)
thread_state.push_roots(ex)
- ex.do('%s = stm_allocate_refs(%s, %s)' % (r, num, bool(with_cards)))
+ ex.do('%s = stm_allocate_refs(%s)' % (r, num))
ex.do('# 0x%x' % (int(ffi.cast("uintptr_t", ex.content[r]))))
thread_state.transaction_state.add_root(r, "ffi.NULL", True)
@@ -417,7 +415,7 @@
r = thread_state.get_random_root()
trs = thread_state.transaction_state
is_ref = global_state.has_ref_type(r)
- has_cards = global_state.has_cards(r) and global_state.rnd.randrange(1,
100) > 5
+ try_cards = global_state.rnd.randrange(1, 100) > 5
#
# check for possible write-write conflict:
was_written = False
@@ -446,13 +444,13 @@
thread_state.abort_transaction()
offset = global_state.get_root_size(r) + " - 1"
if is_ref:
- ex.do(raising_call(aborts, "stm_set_ref", r, offset, v, has_cards))
+ ex.do(raising_call(aborts, "stm_set_ref", r, offset, v, try_cards))
if not aborts:
- ex.do(raising_call(False, "stm_set_ref", r, "0", v, has_cards))
+ ex.do(raising_call(False, "stm_set_ref", r, "0", v, try_cards))
else:
- ex.do(raising_call(aborts, "stm_set_char", r, repr(chr(v)), offset,
has_cards))
+ ex.do(raising_call(aborts, "stm_set_char", r, repr(chr(v)), offset,
try_cards))
if not aborts:
- ex.do(raising_call(False, "stm_set_char", r, repr(chr(v)), "HDR",
has_cards))
+ ex.do(raising_call(False, "stm_set_char", r, repr(chr(v)), "HDR",
try_cards))
def op_read(ex, global_state, thread_state):
r = thread_state.get_random_root()
@@ -564,13 +562,13 @@
curr_thread = global_state.thread_states[0]
for i in range(N_OBJECTS):
- r = global_state.get_new_root_name(False, "384", True)
- ex.do('%s = stm_allocate_old(384, True)' % r)
+ r = global_state.get_new_root_name(False, "384")
+ ex.do('%s = stm_allocate_old(384)' % r)
global_state.committed_transaction_state.add_root(r, 0, False)
global_state.prebuilt_roots.append(r)
- r = global_state.get_new_root_name(True, "50", True)
- ex.do('%s = stm_allocate_old_refs(50, True)' % r)
+ r = global_state.get_new_root_name(True, "50")
+ ex.do('%s = stm_allocate_old_refs(50)' % r)
global_state.committed_transaction_state.add_root(r, "ffi.NULL",
False)
global_state.prebuilt_roots.append(r)
global_state.committed_transaction_state.write_set = set()
@@ -624,5 +622,6 @@
return test_fun
for _seed in range(5000, 5100):
+ _seed = 5004
_fn = _make_fun(_seed)
locals()[_fn.__name__] = _fn
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit