[pypy-commit] pypy rawrefcount-review: Add stateful hypothesis testing for rawrefcount

rlamy pypy.commits at gmail.com
Mon Mar 7 13:41:36 EST 2016


Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: rawrefcount-review
Changeset: r82865:7ddef219107f
Date: 2016-03-07 18:40 +0000
http://bitbucket.org/pypy/pypy/changeset/7ddef219107f/

Log:	Add stateful hypothesis testing for rawrefcount

diff --git a/rpython/memory/gc/test/test_rawrefcount.py b/rpython/memory/gc/test/test_rawrefcount.py
--- a/rpython/memory/gc/test/test_rawrefcount.py
+++ b/rpython/memory/gc/test/test_rawrefcount.py
@@ -1,7 +1,7 @@
 import py
 from rpython.rtyper.lltypesystem import lltype, llmemory
 from rpython.memory.gc.incminimark import IncrementalMiniMarkGC
-from rpython.memory.gc.test.test_direct import BaseDirectGCTest
+from rpython.memory.gc.test.test_direct import BaseDirectGCTest, GCSpace
 from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY
 from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY_LIGHT
 
@@ -289,3 +289,178 @@
         check_alive(0)
         self._collect(major=True)
         check_alive(0)
+
+class RefcountSpace(GCSpace):
+    def __init__(self):
+        GCSpace.__init__(self, IncrementalMiniMarkGC, {})
+        self.trigger = []
+        self.gc.rawrefcount_init(lambda: self.trigger.append(1))
+
+    def new_rawobj(self):
+        r1 = lltype.malloc(PYOBJ_HDR, flavor='raw')
+        r1.ob_refcnt = 0
+        r1.ob_pypy_link = 0
+        return r1
+
+    def new_gcobj(self, intval):
+        p1 = self.malloc(S)
+        p1.x = intval
+        return p1
+
+    def create_link(self, rawobj, gcobj, is_light=False, is_pyobj=False):
+        if is_light:
+            rawobj.ob_refcnt += REFCNT_FROM_PYPY_LIGHT
+        else:
+            rawobj.ob_refcnt += REFCNT_FROM_PYPY
+        rawaddr = llmemory.cast_ptr_to_adr(rawobj)
+        gcref = lltype.cast_opaque_ptr(llmemory.GCREF, gcobj)
+        if is_pyobj:
+            self.gc.rawrefcount_create_link_pyobj(gcref, rawaddr)
+        else:
+            self.gc.rawrefcount_create_link_pypy(gcref, rawaddr)
+
+    def from_gc(self, gcobj):
+        gcref = lltype.cast_opaque_ptr(llmemory.GCREF, gcobj)
+        rawaddr = self.gc.rawrefcount_from_obj(gcref)
+        if rawaddr == llmemory.NULL:
+            return None
+        else:
+            return self.gc._pyobj(rawaddr)
+
+from rpython.rtyper.test.test_rdict import signal_timeout, Action
+from hypothesis.strategies import (
+    builds, sampled_from, binary, just, integers, text, characters, tuples,
+    booleans, one_of)
+from hypothesis.stateful import GenericStateMachine, run_state_machine_as_test
+from rpython.tool.leakfinder import start_tracking_allocations, stop_tracking_allocations
+
+RC_MASK = REFCNT_FROM_PYPY - 1
+
+class StateMachine(GenericStateMachine):
+    def __init__(self):
+        self.space = RefcountSpace()
+        self.rawobjs = []
+        self.rootlinks = []
+        self.next_id = 0
+        start_tracking_allocations()
+
+    def free(self, rawobj):
+        lltype.free(rawobj, flavor='raw')
+
+    def incref(self, rawobj):
+        rawobj.ob_refcnt += 1
+
+    def decref(self, rawobj):
+        assert rawobj.ob_refcnt > 0
+        rawobj.ob_refcnt -= 1
+        if rawobj.ob_refcnt == 0:
+            i = self.rawobjs.index(rawobj)
+            self.free(rawobj)
+            del self.rawobjs[i]
+        elif rawobj.ob_refcnt & RC_MASK == 0:
+            i = self.rawobjs.index(rawobj)
+            del self.rawobjs[i]
+
+    def get_linkable_gcobjs(self):
+        res = []
+        for p, has_link in zip(self.space.stackroots, self.rootlinks):
+            if not has_link:
+                res.append(p)
+        return res
+
+    def get_linkable_rawobjs(self):
+        return [r for r in self.rawobjs
+                if r.ob_refcnt != 0 and r.ob_pypy_link == 0]
+
+    def find_root_index(self, p):
+        return self.space.stackroots.index(p)
+
+    def add_rawobj(self):
+        r = self.space.new_rawobj()
+        self.incref(r)
+        self.rawobjs.append(r)
+
+    def add_gcobj(self):
+        p = self.space.new_gcobj(self.next_id)
+        self.space.stackroots.append(p)
+        self.rootlinks.append(False)
+        self.next_id += 1
+        return p
+
+    def create_gcpartner(self, raw, is_light=False, is_pyobj=False):
+        p = self.space.new_gcobj(self.next_id)
+        self.next_id += 1
+        self.space.create_link(raw, p, is_light=is_light, is_pyobj=is_pyobj)
+
+    def create_rawpartner(self, p, is_light=False, is_pyobj=False):
+        assert self.space.from_gc(p) is None
+        i = self.find_root_index(p)
+        raw = self.space.new_rawobj()
+        self.space.create_link(raw, p, is_light=is_light, is_pyobj=is_pyobj)
+        self.rootlinks[i] = True
+
+    def minor_collection(self):
+        self.space.gc.minor_collection()
+
+    def major_collection(self):
+        self.space.gc.collect()
+
+    def forget_root(self, n):
+        del self.space.stackroots[n]
+        del self.rootlinks[n]
+
+    def steps(self):
+        valid_st = []
+        global_actions = [
+            Action('add_rawobj', ()),
+            Action('minor_collection', ()),
+            Action('major_collection', ()),
+        ]
+        valid_st.append(sampled_from(global_actions))
+        valid_st.append(builds(Action, just('add_gcobj'), tuples()))
+        if self.rawobjs:
+            valid_st.append(builds(Action, just('incref'), tuples(
+                sampled_from(self.rawobjs))))
+        candidates = [r for r in self.rawobjs if r.ob_refcnt & RC_MASK > 0]
+        if candidates:
+            valid_st.append(builds(Action, just('decref'), tuples(
+                sampled_from(candidates))))
+        candidates = self.get_linkable_rawobjs()
+        if candidates:
+            st = builds(Action, just('create_gcpartner'), tuples(
+                sampled_from(candidates),
+                booleans(), booleans()))
+            valid_st.append(st)
+        candidates = self.get_linkable_gcobjs()
+        if candidates:
+            st = builds(Action, just('create_rawpartner'), tuples(
+                sampled_from(candidates),
+                booleans(), booleans()))
+            valid_st.append(st)
+        if self.space.stackroots:
+            st = builds(Action, just('forget_root'), tuples(
+                sampled_from(range(len(self.space.stackroots)))))
+            valid_st.append(st)
+        return one_of(*valid_st)
+
+    def execute_step(self, action):
+        with signal_timeout(1):  # catches infinite loops
+            action.execute(self)
+
+    def teardown(self):
+        self.space.stackroots[:] = []
+        self.space.gc.collect()
+        for r in self.rawobjs:
+            lltype.free(r, flavor='raw')
+        while True:
+            r = self.space.gc.rawrefcount_next_dead()
+            if r == llmemory.NULL:
+                break
+            else:
+                lltype.free(self.space.gc._pyobj(r), flavor='raw')
+        stop_tracking_allocations(check=True)
+
+
+def test_hypothesis():
+    run_state_machine_as_test(StateMachine)
+test_hypothesis.dont_track_allocations = True


More information about the pypy-commit mailing list