[pypy-commit] stmgc hashtable: A random test, and a more precise test and fix following from it.

arigo noreply at buildbot.pypy.org
Sat Nov 1 17:42:29 CET 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: hashtable
Changeset: r1489:bb24720e379b
Date: 2014-11-01 17:41 +0100
http://bitbucket.org/pypy/stmgc/changeset/bb24720e379b/

Log:	A random test, and a more precise test and fix following from it.

diff --git a/c7/stm/hashtable.c b/c7/stm/hashtable.c
--- a/c7/stm/hashtable.c
+++ b/c7/stm/hashtable.c
@@ -221,7 +221,9 @@
        item in the current table.
     */
     if (rc > 6) {
-        if (_is_from_same_transaction(hashtableobj)) {
+        /* we can only enter here once!  If we allocate stuff, we may
+           run the GC, and so 'hashtableobj' might move afterwards. */
+        if (_is_young(hashtableobj)) {
             entry = (stm_hashtable_entry_t *)
                 stm_allocate(sizeof(stm_hashtable_entry_t));
             entry->userdata = stm_hashtable_entry_userdata;
@@ -296,11 +298,14 @@
 }
 
 void stm_hashtable_write(object_t *hashtableobj, stm_hashtable_t *hashtable,
-                         uintptr_t index, object_t *nvalue)
+                         uintptr_t index, object_t *nvalue,
+                         stm_thread_local_t *tl)
 {
+    STM_PUSH_ROOT(*tl, nvalue);
     stm_hashtable_entry_t *e = _stm_hashtable_lookup(hashtableobj, hashtable,
                                                      index);
     stm_write((object_t *)e);
+    STM_POP_ROOT(*tl, nvalue);
     e->object = nvalue;
 }
 
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -538,7 +538,7 @@
 void stm_hashtable_free(stm_hashtable_t *);
 object_t *stm_hashtable_read(object_t *, stm_hashtable_t *, uintptr_t key);
 void stm_hashtable_write(object_t *, stm_hashtable_t *, uintptr_t key,
-                         object_t *nvalue);
+                         object_t *nvalue, stm_thread_local_t *);
 extern uint32_t stm_hashtable_entry_userdata;
 void stm_hashtable_tracefn(stm_hashtable_t *, void (object_t **));
 
diff --git a/c7/test/support.py b/c7/test/support.py
--- a/c7/test/support.py
+++ b/c7/test/support.py
@@ -172,7 +172,7 @@
 bool _check_hashtable_read(object_t *, stm_hashtable_t *, uintptr_t key);
 object_t *hashtable_read_result;
 bool _check_hashtable_write(object_t *, stm_hashtable_t *, uintptr_t key,
-                            object_t *nvalue);
+                            object_t *nvalue, stm_thread_local_t *tl);
 uint32_t stm_hashtable_entry_userdata;
 void stm_hashtable_tracefn(stm_hashtable_t *, void (object_t **));
 
@@ -261,9 +261,9 @@
 }
 
 bool _check_hashtable_write(object_t *hobj, stm_hashtable_t *h, uintptr_t key,
-                            object_t *nvalue)
+                            object_t *nvalue, stm_thread_local_t *tl)
 {
-    CHECKED(stm_hashtable_write(hobj, h, key, nvalue));
+    CHECKED(stm_hashtable_write(hobj, h, key, nvalue, tl));
 }
 
 #undef CHECKED
diff --git a/c7/test/test_hashtable.py b/c7/test/test_hashtable.py
--- a/c7/test/test_hashtable.py
+++ b/c7/test/test_hashtable.py
@@ -10,9 +10,9 @@
         raise Conflict
     return lib.hashtable_read_result
 
-def htset(o, key, nvalue):
+def htset(o, key, nvalue, tl):
     h = get_hashtable(o)
-    res = lib._check_hashtable_write(o, h, key, nvalue)
+    res = lib._check_hashtable_write(o, h, key, nvalue, tl)
     if res:
         raise Conflict
 
@@ -59,9 +59,10 @@
 
     def test_set_value(self):
         self.start_transaction()
+        tl0 = self.tls[self.current_thread]
         h = self.allocate_hashtable()
         lp1 = stm_allocate(16)
-        htset(h, 12345678901, lp1)
+        htset(h, 12345678901, lp1, tl0)
         assert htget(h, 12345678901) == lp1
         for i in range(64):
             index = 12345678901 ^ (1 << i)
@@ -73,16 +74,17 @@
         lp2 = stm_allocate_old(16)
         #
         self.start_transaction()
+        tl0 = self.tls[self.current_thread]
         h = self.allocate_hashtable()
         self.push_root(h)
         stm_set_char(lp1, 'A')
-        htset(h, 1234, lp1)
+        htset(h, 1234, lp1, tl0)
         self.commit_transaction()
         #
         self.start_transaction()
         h = self.pop_root()
         stm_set_char(lp2, 'B')
-        htset(h, 9991234, lp2)
+        htset(h, 9991234, lp2, tl0)
         #
         self.switch(1)
         self.start_transaction()
@@ -96,7 +98,7 @@
         assert htget(h, 9991234) == lp2
         assert stm_get_char(lp2) == 'B'
         assert htget(h, 1234) == lp1
-        htset(h, 1234, ffi.NULL)
+        htset(h, 1234, ffi.NULL, tl0)
         self.commit_transaction()
         #
         self.start_transaction()
@@ -114,11 +116,13 @@
         self.start_transaction()
         h = self.pop_root()
         self.push_root(h)
-        htset(h, 1234, lp1)
+        tl0 = self.tls[self.current_thread]
+        htset(h, 1234, lp1, tl0)
         #
         self.switch(1)
         self.start_transaction()
-        py.test.raises(Conflict, "htset(h, 1234, lp2)")
+        tl1 = self.tls[self.current_thread]
+        py.test.raises(Conflict, "htset(h, 1234, lp2, tl1)")
         #
         self.switch(0)
         self.pop_root()
@@ -131,7 +135,8 @@
         self.push_root(h)
         lp1 = stm_allocate(16)
         stm_set_char(lp1, 'N')
-        htset(h, 1234, lp1)
+        tl0 = self.tls[self.current_thread]
+        htset(h, 1234, lp1, tl0)
         stm_minor_collect()
         h = self.pop_root()
         lp1b = htget(h, 1234)
@@ -146,7 +151,8 @@
         h = self.allocate_hashtable()
         self.push_root(h)
         stm_set_char(lp1, 'N')
-        htset(h, 1234, lp1)
+        tl0 = self.tls[self.current_thread]
+        htset(h, 1234, lp1, tl0)
         self.commit_transaction()
         #
         self.start_transaction()
@@ -158,3 +164,126 @@
         #
         stm_major_collect()       # to get rid of the hashtable object
         self.commit_transaction()
+
+    def test_minor_collect_bug1(self):
+        self.start_transaction()
+        lp1 = stm_allocate(32)
+        self.push_root(lp1)
+        h = self.allocate_hashtable()
+        self.push_root(h)
+        stm_minor_collect()
+        h = self.pop_root()
+        lp1 = self.pop_root()
+        print 'h', h                       # 0xa040010
+        print 'lp1', lp1                   # 0xa040040
+        tl0 = self.tls[self.current_thread]
+        htset(h, 1, lp1, tl0)
+        self.commit_transaction()
+        #
+        self.start_transaction()
+        assert htget(h, 1) == lp1
+        stm_major_collect()       # to get rid of the hashtable object
+
+    def test_random_single_thread(self):
+        import random
+        values = []
+        mirror = {}
+        roots = []
+        def push_roots():
+            assert roots == []
+            for k, hitems in mirror.items():
+                assert lib._get_type_id(k) == 421419
+                for key, value in hitems.items():
+                    assert lib._get_type_id(value) < 1000
+                    self.push_root(value)
+                    roots.append(key)
+                self.push_root(k)
+                roots.append(None)
+            for v in values:
+                self.push_root(v)
+            mirror.clear()
+        #
+        def pop_roots():
+            assert mirror == {}
+            for i in reversed(range(len(values))):
+                values[i] = self.pop_root()
+                assert stm_get_char(values[i]) == chr((i + 1) & 255)
+            for r in reversed(roots):
+                obj = self.pop_root()
+                if r is None:
+                    assert lib._get_type_id(obj) == 421419
+                    mirror[obj] = curhitems = {}
+                else:
+                    assert lib._get_type_id(obj) < 1000
+                    curhitems[r] = obj
+            del roots[:]
+        #
+        for i in range(100):
+            print "start_transaction"
+            self.start_transaction()
+            pop_roots()
+            for j in range(10):
+                r = random.random()
+                if r < 0.05:
+                    h = self.allocate_hashtable()
+                    print "allocate_hashtable ->", h
+                    mirror[h] = {}
+                elif r < 0.10:
+                    print "stm_minor_collect"
+                    push_roots()
+                    stm_minor_collect()
+                    pop_roots()
+                elif r < 0.11:
+                    print "stm_major_collect"
+                    push_roots()
+                    stm_major_collect()
+                    pop_roots()
+                elif r < 0.5:
+                    if not mirror: continue
+                    h = random.choice(mirror.keys())
+                    if not mirror[h]: continue
+                    key = random.choice(mirror[h].keys())
+                    value = mirror[h][key]
+                    print "htget(%r, %r) == %r" % (h, key, value)
+                    push_roots()
+                    self.push_root(value)
+                    result = htget(h, key)
+                    value = self.pop_root()
+                    assert result == value
+                    pop_roots()
+                elif r < 0.6:
+                    if not mirror: continue
+                    h = random.choice(mirror.keys())
+                    key = random.randrange(0, 40)
+                    if key in mirror[h]: continue
+                    print "htget(%r, %r) == NULL" % (h, key)
+                    push_roots()
+                    assert htget(h, key) == ffi.NULL
+                    pop_roots()
+                elif r < 0.63:
+                    if not mirror: continue
+                    h, _ = mirror.popitem()
+                    print "popped", h
+                elif r < 0.75:
+                    obj = stm_allocate(32)
+                    values.append(obj)
+                    stm_set_char(obj, chr(len(values) & 255))
+                else:
+                    if not mirror or not values: continue
+                    h = random.choice(mirror.keys())
+                    key = random.randrange(0, 32)
+                    value = random.choice(values)
+                    print "htset(%r, %r, %r)" % (h, key, value)
+                    push_roots()
+                    tl = self.tls[self.current_thread]
+                    htset(h, key, value, tl)
+                    pop_roots()
+                    mirror[h][key] = value
+            push_roots()
+            print "commit_transaction"
+            self.commit_transaction()
+        #
+        self.start_transaction()
+        self.become_inevitable()
+        pop_roots()
+        stm_major_collect()       # to get rid of the hashtable objects


More information about the pypy-commit mailing list