Author: Remi Meier <remi.me...@inf.ethz.ch> Branch: Changeset: r1372:f7891821148c Date: 2014-09-09 10:15 +0200 http://bitbucket.org/pypy/stmgc/changeset/f7891821148c/
Log: start with test_nursery (fix missing GCWORD_MOVED test) diff --git a/c8/stm/gcpage.c b/c8/stm/gcpage.c --- a/c8/stm/gcpage.c +++ b/c8/stm/gcpage.c @@ -38,6 +38,10 @@ stm_fatalerror("uninitialized_page_start changed?"); } } + dprintf(("allocate_outside_nursery_large(%lu): %p, seg=%d, page=%lu\n", + size, addr, get_segment_of_linear_address(addr), + (addr - STM_SEGMENT->segment_base) / 4096UL)); + return addr; } diff --git a/c8/stm/nursery.c b/c8/stm/nursery.c --- a/c8/stm/nursery.c +++ b/c8/stm/nursery.c @@ -63,6 +63,11 @@ where the object moved to, is stored in the second word in 'obj'. */ object_t *TLPREFIX *pforwarded_array = (object_t *TLPREFIX *)obj; + if (LIKELY(pforwarded_array[0] == GCWORD_MOVED)) { + *pobj = pforwarded_array[1]; /* already moved */ + return; + } + realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj); size = stmcb_size_rounded_up((struct object_s *)realobj); @@ -199,6 +204,16 @@ _do_minor_collection(commit); } +void stm_collect(long level) +{ + if (level > 0) + abort(); + + minor_collection(/*commit=*/ false); + /* XXX: major_collection_if_requested(); */ +} + + /************************************************************/ @@ -220,7 +235,7 @@ return (object_t *)p; } - abort();//stm_collect(0); + stm_collect(0); goto restart; } diff --git a/c8/stmgc.h b/c8/stmgc.h --- a/c8/stmgc.h +++ b/c8/stmgc.h @@ -181,6 +181,8 @@ void stm_commit_transaction(void); void stm_abort_transaction(void) __attribute__((noreturn)); +void stm_collect(long level); + #ifdef STM_NO_AUTOMATIC_SETJMP int stm_is_inevitable(void); diff --git a/c8/test/test_nursery.py b/c8/test/test_nursery.py new file mode 100644 --- /dev/null +++ b/c8/test/test_nursery.py @@ -0,0 +1,250 @@ +from support import * +import py + +class TestNursery(BaseTest): + + def test_nursery_full(self): + lib._stm_set_nursery_free_count(2048) + self.start_transaction() + self.push_root_no_gc() + lp1 = stm_allocate(2048) # no collection here + self.pop_root() + # + self.push_root(lp1) + lp2 = stm_allocate(2048) + lp1b = self.pop_root() + assert lp1b != lp1 # collection occurred + + def test_several_minor_collections(self): + # make a long, ever-growing linked list of objects, in one transaction + lib._stm_set_nursery_free_count(2048) + self.start_transaction() + lp1 = stm_allocate_refs(1) + self.push_root(lp1) + prev = lp1 + prevprev = None + FIT = 2048 / 16 - 1 # without 'lp1' above + N = 4096 / 16 + 41 + for i in range(N): + if prevprev: + assert stm_get_ref(prevprev, 0) == prev + self.push_root(prevprev) + self.push_root(prev) + lp3 = stm_allocate_refs(1) + prev = self.pop_root() + if prevprev: + prevprev = self.pop_root() + assert prevprev != prev + stm_set_ref(prev, 0, lp3) + + #assert modified_old_objects() == [] # only 1 transaction + opn = objects_pointing_to_nursery() + if i < FIT: + assert opn == [] # no minor collection so far + else: + assert len(opn) == 1 + + prevprev = prev + prev = lp3 + + lp1 = self.pop_root() + #assert modified_old_objects() == [] + + lp2 = lp1 + for i in range(N): + assert lp2 + prev = lp2 + lp2 = stm_get_ref(lp2, 0) + assert lp2 == lp3 + + def test_many_allocs(self): + lib._stm_set_nursery_free_count(32768) + obj_size = 512 + num = 65536 / obj_size + 41 + + self.start_transaction() + for i in range(num): + new = stm_allocate(obj_size) + stm_set_char(new, chr(i % 255)) + self.push_root(new) + + old = [] + young = [] + for i in reversed(range(num)): + r = self.pop_root() + assert stm_get_char(r) == chr(i % 255) + if is_in_nursery(r): + young.append(r) + else: + old.append(r) + + assert old + assert young + + def test_larger_than_limit_for_nursery_die(self): + obj_size = lib._STM_FAST_ALLOC + 16 + + self.start_transaction() + assert lib._stm_total_allocated() == 0 + seen = set() + for i in range(10): + stm_minor_collect() + new = stm_allocate(obj_size) + assert not is_in_nursery(new) + assert lib._stm_total_allocated() == obj_size + 16 + seen.add(new) + assert len(seen) < 5 # addresses are reused + stm_minor_collect() + assert lib._stm_total_allocated() == 0 + + def test_larger_than_limit_for_nursery_dont_die(self): + obj_nrefs = (lib._STM_FAST_ALLOC + 16) // 8 + + self.start_transaction() + lp1 = ffi.cast("object_t *", 0) + seen = set() + for i in range(100): + self.push_root(lp1) + stm_minor_collect() + lp1 = self.pop_root() + new = stm_allocate_refs(obj_nrefs) + assert not is_in_nursery(new) + seen.add(new) + stm_set_ref(new, i, lp1) + lp1 = new + assert len(seen) == 100 # addresses are not reused + + for i in reversed(range(100)): + assert lp1 + lp1 = stm_get_ref(lp1, i) + assert not lp1 + + def test_account_for_privatized_page(self): + self.start_transaction() + obj = stm_allocate(16) + self.push_root(obj) + self.commit_transaction() + obj = self.pop_root() + base = lib._stm_total_allocated() + assert base <= 4096 + + self.start_transaction() + stm_write(obj) + assert lib._stm_total_allocated() == base + 4096 + + def test_reset_partial_alloc_pages(self): + py.test.skip("a would-be-nice feature, but not actually needed: " + "the next major GC will take care of it") + self.start_transaction() + new = stm_allocate(16) + stm_set_char(new, 'a') + self.push_root(new) + stm_minor_collect() + new = self.pop_root() + self.abort_transaction() + + self.start_transaction() + newer = stm_allocate(16) + self.push_root(newer) + stm_minor_collect() + newer = self.pop_root() + assert stm_get_real_address(new) == stm_get_real_address(newer) + assert stm_get_char(newer) == '\0' + + def test_reuse_page(self): + py.test.skip("a would-be-nice feature, but not actually needed: " + "the next major GC will take care of it") + self.start_transaction() + new = stm_allocate(16) + self.push_root(new) + stm_minor_collect() + new = self.pop_root() + # assert stm_get_page_flag(stm_get_obj_pages(new)[0]) == lib.UNCOMMITTED_SHARED_PAGE + self.abort_transaction() + + self.start_transaction() + newer = stm_allocate(16) + self.push_root(newer) + stm_minor_collect() + newer = self.pop_root() + assert new == newer + + def test_write_to_old_after_minor(self): + self.start_transaction() + new = stm_allocate(16) + self.push_root(new) + stm_minor_collect() + old = self.pop_root() + self.commit_transaction() + + self.start_transaction() + stm_write(old) # old objs to trace + stm_set_char(old, 'x') + stm_minor_collect() + stm_write(old) # old objs to trace + stm_set_char(old, 'y') + self.commit_transaction() + + def test_can_move(self): + self.start_transaction() + new = stm_allocate(16) + assert lib.stm_can_move(new) == 1 + self.push_root(new) + stm_minor_collect() + old = self.pop_root() + assert lib.stm_can_move(old) == 0 + self.commit_transaction() + + self.start_transaction() + assert lib.stm_can_move(old) == 0 + + def test_marker_1(self): + self.start_transaction() + p1 = stm_allocate(600) + stm_set_char(p1, 'o') + self.push_root(p1) + self.push_root(ffi.cast("object_t *", 123)) + p2 = stm_allocate(600) + stm_set_char(p2, 't') + self.push_root(p2) + stm_minor_collect() + assert lib._stm_total_allocated() == 2 * 616 + # + p2 = self.pop_root() + m = self.pop_root() + assert m == ffi.cast("object_t *", 123) + p1 = self.pop_root() + assert stm_get_char(p1) == 'o' + assert stm_get_char(p2) == 't' + + def test_marker_2(self): + py.test.skip("testing this requires working shadowstack saving logic") + self.start_transaction() + p1 = stm_allocate(600) + stm_set_char(p1, 'o') + self.push_root(p1) + self.push_root(ffi.cast("object_t *", lib.STM_STACK_MARKER_OLD)) + p2 = stm_allocate(600) + stm_set_char(p2, 't') + self.push_root(p2) + stm_minor_collect() + assert lib._stm_total_allocated() == 1 * 616 + # + p2 = self.pop_root() + m = self.pop_root() + assert m == ffi.cast("object_t *", lib.STM_STACK_MARKER_OLD) + assert stm_get_char(p2) == 't' + # the 'p1' reference is invalid now, don't try to read it. + # we check that it's invalid because _stm_total_allocated() + # only records one of the two objects. + + def test_clear_read_marker_for_external_young(self): + self.start_transaction() + big = stm_allocate(FAST_ALLOC + 1000) # young outside nursery + stm_read(big) + assert stm_was_read(big) + stm_minor_collect() # free young outside + assert not stm_was_read(big) + # if the read marker is not cleared, we get false conflicts + # with later transactions using the same large-malloced slot + # as our outside-nursery-obj _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit