[pypy-commit] pypy stm: - various small improvements

arigo noreply at buildbot.pypy.org
Mon Oct 31 19:10:25 CET 2011


Author: Armin Rigo <arigo at tunes.org>
Branch: stm
Changeset: r48631:db149dd0eef2
Date: 2011-10-31 19:10 +0100
http://bitbucket.org/pypy/pypy/changeset/db149dd0eef2/

Log:	- various small improvements
	- distinguish gc- from raw-{get,set}fields
	- start making targetdemo really multithreaded

diff --git a/pypy/translator/stm/_rffi_stm.py b/pypy/translator/stm/_rffi_stm.py
--- a/pypy/translator/stm/_rffi_stm.py
+++ b/pypy/translator/stm/_rffi_stm.py
@@ -32,6 +32,11 @@
 commit_transaction = llexternal('stm_commit_transaction', [], lltype.Signed)
 try_inevitable = llexternal('stm_try_inevitable', [], lltype.Void)
 
+descriptor_init_and_being_inevitable_transaction = llexternal(
+    'stm_descriptor_init_and_being_inevitable_transaction', [], lltype.Void)
+commit_transaction_and_descriptor_done = llexternal(
+    'stm_commit_transaction_and_descriptor_done', [], lltype.Void)
+
 stm_read_word = llexternal('stm_read_word', [SignedP], lltype.Signed)
 stm_write_word = llexternal('stm_write_word', [SignedP, lltype.Signed],
                             lltype.Void)
diff --git a/pypy/translator/stm/llstminterp.py b/pypy/translator/stm/llstminterp.py
--- a/pypy/translator/stm/llstminterp.py
+++ b/pypy/translator/stm/llstminterp.py
@@ -69,10 +69,30 @@
         if STRUCT._immutable_field(fieldname):
             # immutable field reads are always allowed
             return LLFrame.op_getfield(self, struct, fieldname)
+        elif STRUCT._gckind == 'raw':
+            # raw getfields are allowed outside a regular transaction
+            self.check_stm_mode(lambda m: m != "regular_transaction")
+            return LLFrame.op_getfield(self, struct, fieldname)
         else:
             # mutable 'getfields' are always forbidden for now
             self.check_stm_mode(lambda m: False)
-            xxx
+            assert 0
+
+    def opstm_setfield(self, struct, fieldname, newvalue):
+        STRUCT = lltype.typeOf(struct).TO
+        if STRUCT._immutable_field(fieldname):
+            # immutable field writes (i.e. initializing writes) should
+            # always be fine, because they should occur into newly malloced
+            # structures
+            LLFrame.op_setfield(self, struct, fieldname, newvalue)
+        elif STRUCT._gckind == 'raw':
+            # raw setfields are allowed outside a regular transaction
+            self.check_stm_mode(lambda m: m != "regular_transaction")
+            LLFrame.op_setfield(self, struct, fieldname, newvalue)
+        else:
+            # mutable 'setfields' are always forbidden for now
+            self.check_stm_mode(lambda m: False)
+            assert 0
 
     def opstm_malloc(self, TYPE, flags):
         # non-GC must not occur in a regular transaction,
diff --git a/pypy/translator/stm/src_stm/et.c b/pypy/translator/stm/src_stm/et.c
--- a/pypy/translator/stm/src_stm/et.c
+++ b/pypy/translator/stm/src_stm/et.c
@@ -580,31 +580,34 @@
   if (PYPY_HAVE_DEBUG_PRINTS) {
     int num_aborts = 0, num_spinloops = 0;
     int i, prevchar;
+    char line[256], *p = line;
+
     for (i=0; i<ABORT_REASONS; i++)
       num_aborts += d->num_aborts[i];
     for (i=0; i<SPINLOOP_REASONS; i++)
       num_spinloops += d->num_spinloops[i];
 
-    fprintf(PYPY_DEBUG_FILE, "thread %lx: %d commits, %d aborts ",
-            d->my_lock_word,
-            d->num_commits,
-            num_aborts);
+    p += sprintf(p, "thread %lx: %d commits, %d aborts ",
+                 d->my_lock_word,
+                 d->num_commits,
+                 num_aborts);
 
     for (i=0; i<ABORT_REASONS; i++)
-      fprintf(PYPY_DEBUG_FILE, "%c%d", i == 0 ? '[' : ',',
-              d->num_aborts[i]);
+      p += sprintf(p, "%c%d", i == 0 ? '[' : ',',
+                   d->num_aborts[i]);
 
     for (i=1; i<SPINLOOP_REASONS; i++)  /* num_spinloops[0] == num_aborts */
-      fprintf(PYPY_DEBUG_FILE, "%c%d", i == 1 ? '|' : ',',
-              d->num_spinloops[i]);
+      p += sprintf(p, "%c%d", i == 1 ? '|' : ',',
+                   d->num_spinloops[i]);
 
 #ifdef COMMIT_OTHER_INEV
     for (i=0; i<OTHERINEV_REASONS; i++)
-      fprintf(PYPY_DEBUG_FILE, "%c%d", i == 0 ? '|' : ',',
-              d->num_otherinev[i]);
+      p += sprintf(p, "%c%d", i == 0 ? '|' : ',',
+                   d->num_otherinev[i]);
 #endif
 
-    fprintf(PYPY_DEBUG_FILE, "]\n");
+    p += sprintf(p, "]\n");
+    fwrite(line, 1, p - line, PYPY_DEBUG_FILE);
   }
   PYPY_DEBUG_STOP("stm-done");
 #endif
@@ -835,6 +838,21 @@
 #endif
 }
 
+void stm_descriptor_init_and_being_inevitable_transaction(void)
+{
+  int was_not_started = (thread_descriptor == NULL);
+  stm_descriptor_init();
+  if (was_not_started)
+    stm_begin_inevitable_transaction();
+}
+
+void stm_commit_transaction_and_descriptor_done(void)
+{
+  if (thread_descriptor->init_counter == 1)
+    stm_commit_transaction();
+  stm_descriptor_done();
+}
+
 // XXX little-endian only!
 void stm_write_partial_word(int fieldsize, char *base, long offset,
                             unsigned long nval)
diff --git a/pypy/translator/stm/src_stm/et.h b/pypy/translator/stm/src_stm/et.h
--- a/pypy/translator/stm/src_stm/et.h
+++ b/pypy/translator/stm/src_stm/et.h
@@ -36,6 +36,8 @@
 void stm_begin_inevitable_transaction(void);
 void stm_abort_and_retry(void);
 void stm_transaction_boundary(jmp_buf* buf);
+void stm_descriptor_init_and_being_inevitable_transaction(void);
+void stm_commit_transaction_and_descriptor_done(void);
 
 /* for testing only: */
 #define STM_begin_transaction()         ; \
diff --git a/pypy/translator/stm/test/targetdemo.py b/pypy/translator/stm/test/targetdemo.py
--- a/pypy/translator/stm/test/targetdemo.py
+++ b/pypy/translator/stm/test/targetdemo.py
@@ -1,19 +1,44 @@
-#from pypy.module.thread import ll_thread
+import time
+from pypy.module.thread import ll_thread
 from pypy.translator.stm import rstm
 
 
+NUM_THREADS = 4
+LENGTH      = 1000
 
 
+class Node:
+    def __init__(self, value):
+        self.value = value
+        self.next = None
+
+
+def add_at_end_of_chained_list(node, value):
+    while node.next:
+        node = node.next
+    newnode = Node(value)
+    node.next = newnode
+
+
+class Global:
+    anchor = Node(-1)
+glob = Global()
+
+def run_me():
+    print "thread starting..."
+    for i in range(LENGTH):
+        add_at_end_of_chained_list(glob.anchor, i)
+        rstm.transaction_boundary()
+    print "thread done."
+
 
 # __________  Entry point  __________
 
 def entry_point(argv):
     print "hello world"
-    rstm.transaction_boundary()
-    i = 100
-    while i > 1:
-        i *= 0.821
-    rstm.transaction_boundary()
+    for i in range(NUM_THREADS):
+        ll_thread.start_new_thread(run_me, ())
+    time.sleep(10)
     return 0
 
 # _____ Define and setup target ___
diff --git a/pypy/translator/stm/test/test_transform.py b/pypy/translator/stm/test/test_transform.py
--- a/pypy/translator/stm/test/test_transform.py
+++ b/pypy/translator/stm/test/test_transform.py
@@ -33,6 +33,17 @@
     res = eval_stm_graph(interp, graph, [p], stm_mode="regular_transaction")
     assert res == 42
 
+def test_setfield():
+    S = lltype.GcStruct('S', ('x', lltype.Signed))
+    p = lltype.malloc(S, immortal=True)
+    p.x = 42
+    def func(p):
+        p.x = 43
+    interp, graph = get_interpreter(func, [p])
+    transform_graph(graph)
+    assert summary(graph) == {'stm_setfield': 1}
+    eval_stm_graph(interp, graph, [p], stm_mode="regular_transaction")
+
 def test_immutable_field():
     S = lltype.GcStruct('S', ('x', lltype.Signed), hints = {'immutable': True})
     p = lltype.malloc(S, immortal=True)
@@ -70,6 +81,31 @@
     eval_stm_func(func, [], final_stm_mode="inevitable_transaction")
 test_unsupported_malloc.dont_track_allocations = True
 
+def test_unsupported_getfield_raw():
+    S = lltype.Struct('S', ('x', lltype.Signed))
+    p = lltype.malloc(S, immortal=True)
+    p.x = 42
+    def func(p):
+        return p.x
+    interp, graph = get_interpreter(func, [p])
+    transform_graph(graph)
+    assert summary(graph) == {'stm_try_inevitable': 1, 'getfield': 1}
+    res = eval_stm_graph(interp, graph, [p], stm_mode="regular_transaction",
+                         final_stm_mode="inevitable_transaction")
+    assert res == 42
+
+def test_unsupported_setfield_raw():
+    S = lltype.Struct('S', ('x', lltype.Signed))
+    p = lltype.malloc(S, immortal=True)
+    p.x = 42
+    def func(p):
+        p.x = 43
+    interp, graph = get_interpreter(func, [p])
+    transform_graph(graph)
+    assert summary(graph) == {'stm_try_inevitable': 1, 'setfield': 1}
+    eval_stm_graph(interp, graph, [p], stm_mode="regular_transaction",
+                   final_stm_mode="inevitable_transaction")
+
 # ____________________________________________________________
 
 class TestTransformSingleThread(StandaloneTests):
diff --git a/pypy/translator/stm/transform.py b/pypy/translator/stm/transform.py
--- a/pypy/translator/stm/transform.py
+++ b/pypy/translator/stm/transform.py
@@ -1,8 +1,8 @@
 from pypy.objspace.flow.model import SpaceOperation, Constant
+from pypy.objspace.flow.model import Block, Link, checkgraph
 from pypy.annotation import model as annmodel
-from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
 from pypy.translator.stm import _rffi_stm
-from pypy.translator.unsimplify import varoftype
+from pypy.translator.unsimplify import varoftype, copyvar
 from pypy.rpython.lltypesystem import lltype
 
 
@@ -33,12 +33,13 @@
         assert not hasattr(self.translator, 'stm_transformation_applied')
         entrypointgraph = entrypointptr._obj.graph
         for graph in self.translator.graphs:
-            if graph is entrypointgraph:
-                continue
             self.seen_transaction_boundary = False
+            self.seen_gc_stack_bottom = False
             self.transform_graph(graph)
             if self.seen_transaction_boundary:
                 self.add_stm_declare_variable(graph)
+            if self.seen_gc_stack_bottom:
+                self.add_descriptor_init_stuff(graph)
         self.add_descriptor_init_stuff(entrypointgraph)
         self.translator.stm_transformation_applied = True
 
@@ -70,24 +71,29 @@
         for block in graph.iterblocks():
             self.transform_block(block)
 
-    def add_descriptor_init_stuff(self, entrypointgraph):
+    def add_descriptor_init_stuff(self, graph):
+        f_init = _rffi_stm.descriptor_init_and_being_inevitable_transaction
+        f_done = _rffi_stm.commit_transaction_and_descriptor_done
+        c_init = Constant(f_init, lltype.typeOf(f_init))
+        c_done = Constant(f_done, lltype.typeOf(f_done))
         #
-        def descriptor_init():
-            _rffi_stm.descriptor_init()
-            _rffi_stm.begin_inevitable_transaction()
-        #def descriptor_done():
-        #    _rffi_stm.commit_transaction()
-        #    _rffi_stm.descriptor_done()
-        #
-        annhelper = MixLevelHelperAnnotator(self.translator.rtyper)
-        c_init = annhelper.constfunc(descriptor_init, [], annmodel.s_None)
-        #c_done = annhelper.constfunc(descriptor_done, [], annmodel.s_None)
-        annhelper.finish()
-        block = entrypointgraph.startblock
+        block = graph.startblock
         v = varoftype(lltype.Void)
         op = SpaceOperation('direct_call', [c_init], v)
         block.operations.insert(0, op)
-        #...add c_done...
+        #
+        v = copyvar(self.translator.annotator, graph.getreturnvar())
+        extrablock = Block([v])
+        v_none = varoftype(lltype.Void)
+        newop = SpaceOperation('direct_call', [c_done], v_none)
+        extrablock.operations = [newop]
+        extrablock.closeblock(Link([v], graph.returnblock))
+        for block in graph.iterblocks():
+            if block is not extrablock:
+                for link in block.exits:
+                    if link.target is graph.returnblock:
+                        link.target = extrablock
+        checkgraph(graph)
 
     def add_stm_declare_variable(self, graph):
         block = graph.startblock
@@ -101,12 +107,22 @@
         STRUCT = op.args[0].concretetype.TO
         if STRUCT._immutable_field(op.args[1].value):
             op1 = op
+        elif STRUCT._gckind == 'raw':
+            turn_inevitable(newoperations, "getfield_raw")
+            op1 = op
         else:
             op1 = SpaceOperation('stm_getfield', op.args, op.result)
         newoperations.append(op1)
 
     def stt_setfield(self, newoperations, op):
-        op1 = SpaceOperation('stm_setfield', op.args, op.result)
+        STRUCT = op.args[0].concretetype.TO
+        if STRUCT._immutable_field(op.args[1].value):
+            op1 = op
+        elif STRUCT._gckind == 'raw':
+            turn_inevitable(newoperations, "setfield_raw")
+            op1 = op
+        else:
+            op1 = SpaceOperation('stm_setfield', op.args, op.result)
         newoperations.append(op1)
 
     def stt_stm_transaction_boundary(self, newoperations, op):
@@ -117,15 +133,22 @@
         flags = op.args[1].value
         return flags['flavor'] == 'gc'
 
+    def stt_gc_stack_bottom(self, newoperations, op):
+        self.seen_gc_stack_bottom = True
+        newoperations.append(op)
+
 
 def transform_graph(graph):
     # for tests: only transforms one graph
     STMTransformer().transform_graph(graph)
 
 
-def turn_inevitable_and_proceed(newoperations, op):
-    c_info = Constant(op.opname, lltype.Void)
+def turn_inevitable(newoperations, info):
+    c_info = Constant(info, lltype.Void)
     op1 = SpaceOperation('stm_try_inevitable', [c_info],
                          varoftype(lltype.Void))
     newoperations.append(op1)
+
+def turn_inevitable_and_proceed(newoperations, op):
+    turn_inevitable(newoperations, op.opname)
     newoperations.append(op)


More information about the pypy-commit mailing list