[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