Author: Remi Meier <[email protected]>
Branch: stmgc-c7
Changeset: r70704:899027a93ced
Date: 2014-04-17 17:26 +0200
http://bitbucket.org/pypy/pypy/changeset/899027a93ced/
Log: Backed out changeset: 5e60afcef785 (doesn't improve performance)
diff --git a/rpython/translator/stm/readbarrier.py
b/rpython/translator/stm/readbarrier.py
--- a/rpython/translator/stm/readbarrier.py
+++ b/rpython/translator/stm/readbarrier.py
@@ -1,17 +1,14 @@
from rpython.flowspace.model import SpaceOperation, Constant, Variable
+from rpython.translator.unsimplify import varoftype
from rpython.rtyper.lltypesystem import lltype
-from rpython.translator.unsimplify import varoftype, insert_empty_block
-from rpython.translator.unsimplify import insert_empty_startblock
-from rpython.translator.simplify import join_blocks
-MALLOCS = set([
- 'malloc', 'malloc_varsize',
- 'malloc_nonmovable', 'malloc_nonmovable_varsize',
- ])
-
READ_OPS = set(['getfield', 'getarrayitem', 'getinteriorfield', 'raw_load'])
+
+def is_gc_ptr(T):
+ return isinstance(T, lltype.Ptr) and T.TO._gckind == 'gc'
+
def unwraplist(list_v):
for v in list_v:
if isinstance(v, Constant):
@@ -36,38 +33,25 @@
return OUTER._immutable_interiorfield(unwraplist(op.args[1:-1]))
if op.opname in ('raw_load', 'raw_store'):
return False
- raise AssertionError(op)
-def needs_barrier(frm, to):
- return to > frm
-def is_gc_ptr(T):
- return isinstance(T, lltype.Ptr) and T.TO._gckind == 'gc'
+def insert_stm_read_barrier(transformer, graph):
+ # We need to put enough 'stm_read' in the graph so that any
+ # execution of a READ_OP on some GC object is guaranteed to also
+ # execute either 'stm_read' or 'stm_write' on the same GC object
+ # during the same transaction.
+ #
+ # XXX this can be optimized a lot, but for now we go with the
+ # simplest possible solution...
+ #
+ gcremovetypeptr = transformer.translator.config.translation.gcremovetypeptr
-
-
-
-class BlockTransformer(object):
-
- def __init__(self, stmtransformer, block):
- self.stmtransformer = stmtransformer
- self.block = block
- self.patch = None
- self.inputargs_category = None
- self.inputargs_category_per_link = {}
-
- def init_start_block(self):
- from_outside = ['A'] * len(self.block.inputargs)
- self.inputargs_category_per_link[None] = from_outside
- self.update_inputargs_category()
-
-
- def analyze_inside_block(self, graph):
- gcremovetypeptr = (
- self.stmtransformer.translator.config.translation.gcremovetypeptr)
- wants_a_barrier = {}
+ for block in graph.iterblocks():
+ if not block.operations:
+ continue
+ newops = []
stm_ignored = False
- for op in self.block.operations:
+ for op in block.operations:
is_getter = (op.opname in READ_OPS and
op.result.concretetype is not lltype.Void and
is_gc_ptr(op.args[0].concretetype))
@@ -77,188 +61,26 @@
op.args[0].concretetype.TO._hints.get('typeptr')):
# typeptr is always immutable
pass
- elif (op.opname in ('getarraysize', 'getinteriorarraysize') and
- is_gc_ptr(op.args[0].concretetype) or
+ elif ((op.opname in ('getarraysize', 'getinteriorarraysize') and
+ is_gc_ptr(op.args[0].concretetype)) or
(is_getter and is_immutable(op))):
# immutable getters
+ # 'weakref_deref': kind of immutable, but the GC has to see
+ # which transactions read from a dying weakref, so we
+ # need the barrier nonetheless...
pass
elif is_getter:
- # the non-immutable getfields need a regular read barrier
if not stm_ignored:
- wants_a_barrier[op] = 'R'
- elif op.opname == 'weakref_deref':
- # 'weakref_deref' needs a read barrier if we want to work
- # around the "weakref issue"
- assert not stm_ignored
- wants_a_barrier[op] = 'R'
+ v_none = varoftype(lltype.Void)
+ newops.append(SpaceOperation('stm_read',
+ [op.args[0]], v_none))
+ transformer.read_barrier_counts += 1
elif op.opname == 'stm_ignored_start':
- assert not stm_ignored, "nested 'with stm_ignored'"
+ assert stm_ignored == False
stm_ignored = True
elif op.opname == 'stm_ignored_stop':
- assert stm_ignored, "stm_ignored_stop without start?"
+ assert stm_ignored == True
stm_ignored = False
- #
- if stm_ignored:
- raise Exception("%r: 'with stm_ignored:' code body too complex"
- % (graph,))
- self.wants_a_barrier = wants_a_barrier
-
-
- def flow_through_block(self):
- def cat_fetch(v):
- return categories.setdefault(v, 'A')
-
- def get_category_or_null(v):
- # 'v' is an original variable here, or a constant
- if isinstance(v, Constant) and not v.value: # a NULL constant
- return 'Z'
- if v in categories:
- return categories[v]
- return 'A'
-
- newoperations = []
- stmtransformer = self.stmtransformer
- categories = {}
-
- # make the initial trivial renamings needed to have some precise
- # categories for the input args
- for v, cat in zip(self.block.inputargs, self.inputargs_category):
- if is_gc_ptr(v.concretetype):
- assert cat is not None
- categories[v] = cat
-
- for op in self.block.operations:
- if (op.opname in ('cast_pointer', 'same_as') and
- is_gc_ptr(op.result.concretetype)):
- categories[op.result] = cat_fetch(op.args[0])
- newoperations.append(op)
- continue
- #
- to = self.wants_a_barrier.get(op)
- if to is not None:
- v = op.args[0]
- frm = cat_fetch(v)
- if needs_barrier(frm, to):
- stmtransformer.read_barrier_counts += 1
- v_none = varoftype(lltype.Void)
- newop = SpaceOperation('stm_read', [v], v_none)
- categories[v] = to
- newoperations.append(newop)
- #
- newoperations.append(op)
- #
- if stmtransformer.break_analyzer.analyze(op):
- # this operation can perform a transaction break:
- # all references are lowered to 'A' again
- for v in categories:
- categories[v] = 'A'
-
- if op.opname == 'debug_stm_flush_barrier':
- for v in categories:
- categories[v] = 'A'
-
- if op.opname in MALLOCS:
- categories[op.result] = 'R'
-
- blockoperations = newoperations
- linkoperations = []
- for link in self.block.exits:
- output_categories = []
- for v in link.args:
- if is_gc_ptr(v.concretetype):
- cat = cat_fetch(v)
- else:
- cat = None
- output_categories.append(cat)
- linkoperations.append(output_categories)
- #
- # Record how we'd like to patch the block, but don't do any
- # patching yet
- self.patch = (blockoperations, linkoperations)
-
-
- def update_targets(self, block_transformers):
- (_, linkoperations) = self.patch
- assert len(linkoperations) == len(self.block.exits)
- targetbts = []
- for link, output_categories in zip(self.block.exits, linkoperations):
- targetblock = link.target
- if targetblock not in block_transformers:
- continue # ignore the exit block
- targetbt = block_transformers[targetblock]
- targetbt.inputargs_category_per_link[link] = output_categories
- if targetbt.update_inputargs_category():
- targetbts.append(targetbt)
- return set(targetbts)
-
- def update_inputargs_category(self):
- values = self.inputargs_category_per_link.values()
- newcats = []
- for i, v in enumerate(self.block.inputargs):
- if is_gc_ptr(v.concretetype):
- cats = [output_categories[i] for output_categories in values]
- assert None not in cats
- newcats.append(min(cats))
- else:
- newcats.append(None)
- if newcats != self.inputargs_category:
- self.inputargs_category = newcats
- return True
- else:
- return False
-
-
- def patch_now(self):
- if self.patch is None:
- return
- newoperations, linkoperations = self.patch
- self.block.operations = newoperations
- assert len(linkoperations) == len(self.block.exits)
- # for link, (newargs, newoperations, _) in zip(self.block.exits,
- # linkoperations):
- # link.args[:] = newargs
- # if newoperations:
- # # must put them in a fresh block along the link
- # annotator = self.stmtransformer.translator.annotator
- # insert_empty_block(annotator, link, newoperations)
-
-
-def insert_stm_read_barrier(stmtransformer, graph):
- """This function uses the following characters for 'categories':
-
- * 'A': any general pointer
- * 'R': the read barrier was applied
- * 'Z': the null constant
-
- The letters are chosen so that a barrier is needed to change a
- pointer from category x to category y if and only if y > x.
- """
- # XXX: we currently don't use the information that any write
- # operation on a gcptr will make it readable automatically
- join_blocks(graph)
- annotator = stmtransformer.translator.annotator
- insert_empty_startblock(annotator, graph)
-
- block_transformers = {}
-
- for block in graph.iterblocks():
- if block.operations == ():
- continue
- bt = BlockTransformer(stmtransformer, block)
- bt.analyze_inside_block(graph)
- block_transformers[block] = bt
-
- bt = block_transformers[graph.startblock]
- bt.init_start_block()
- pending = set([bt])
-
- while pending:
- bt = pending.pop()
- bt.flow_through_block()
- pending |= bt.update_targets(block_transformers)
-
- for bt in block_transformers.values():
- bt.patch_now()
-
- # needed only for some fragile test ztranslated.test_stm_ignored
- join_blocks(graph)
+ newops.append(op)
+ assert stm_ignored == False
+ block.operations = newops
diff --git a/rpython/translator/stm/test/test_readbarrier.py
b/rpython/translator/stm/test/test_readbarrier.py
--- a/rpython/translator/stm/test/test_readbarrier.py
+++ b/rpython/translator/stm/test/test_readbarrier.py
@@ -1,8 +1,7 @@
from rpython.rlib.objectmodel import stm_ignored
from rpython.translator.stm.test.transform_support import BaseTestTransform
-from rpython.rtyper.lltypesystem import lltype, rffi
-from rpython.rlib.rstm import register_invoke_around_extcall
-from rpython.rtyper.lltypesystem.lloperation import llop
+from rpython.rtyper.lltypesystem import lltype
+
class TestReadBarrier(BaseTestTransform):
do_read_barrier = True
@@ -27,127 +26,6 @@
assert res == 42
assert self.read_barriers == [x1]
- def test_array_size(self):
- array_gc = lltype.GcArray(('z', lltype.Signed))
- array_nongc = lltype.Array(('z', lltype.Signed))
- Q = lltype.GcStruct('Q',
- ('gc', lltype.Ptr(array_gc)),
- ('raw', lltype.Ptr(array_nongc)))
- q = lltype.malloc(Q, immortal=True)
- q.gc = lltype.malloc(array_gc, n=3, flavor='gc', immortal=True)
- q.raw = lltype.malloc(array_nongc, n=5, flavor='raw', immortal=True)
- def f1(n):
- if n == 1:
- return len(q.gc)
- else:
- return len(q.raw)
- self.interpret(f1, [1])
- assert self.read_barriers == [q]
- self.interpret(f1, [0])
- assert self.read_barriers == [q]
-
- def test_simple_read_2(self):
- X = lltype.GcStruct('X', ('foo', lltype.Signed))
- x2 = lltype.malloc(X, immortal=True)
- x2.foo = 81
- null = lltype.nullptr(X)
-
- def f1(n):
- if n < 1:
- p = null
- else:
- p = x2
- return p.foo
-
- res = self.interpret(f1, [4])
- assert res == 81
- assert self.read_barriers == [x2]
-
-
- def test_multiple_reads(self):
- X = lltype.GcStruct('X', ('foo', lltype.Signed),
- ('bar', lltype.Signed))
- x1 = lltype.malloc(X, immortal=True)
- x1.foo = 6
- x1.bar = 7
- x2 = lltype.malloc(X, immortal=True)
- x2.foo = 81
- x2.bar = -1
-
- def f1(n):
- if n > 1:
- return x2.foo * x2.bar
- else:
- return x1.foo * x1.bar
-
- res = self.interpret(f1, [4])
- assert res == -81
- assert self.read_barriers == [x2]
-
- def test_malloc(self):
- X = lltype.GcStruct('X', ('foo', lltype.Signed))
- def f1(n):
- p = lltype.malloc(X)
- p.foo = n
-
- self.interpret(f1, [4])
- assert self.read_barriers == []
-
- def test_repeat_read_barrier_after_malloc(self):
- X = lltype.GcStruct('X', ('foo', lltype.Signed))
- x1 = lltype.malloc(X, immortal=True)
- x1.foo = 6
- def f1(n):
- i = x1.foo
- lltype.malloc(X)
- i = x1.foo + i
- return i
-
- self.interpret(f1, [4])
- assert self.read_barriers == [x1]
-
- def test_call_external_release_gil(self):
- X = lltype.GcStruct('X', ('foo', lltype.Signed))
- def f1(p):
- register_invoke_around_extcall()
- x1 = p.foo
- external_release_gil()
- x2 = p.foo
- return x1 * x2
-
- x = lltype.malloc(X, immortal=True); x.foo = 6
- res = self.interpret(f1, [x])
- assert res == 36
- assert self.read_barriers == [x, x]
-
- def test_call_external_any_gcobj(self):
- X = lltype.GcStruct('X', ('foo', lltype.Signed))
- def f1(p):
- register_invoke_around_extcall()
- x1 = p.foo
- external_any_gcobj()
- x2 = p.foo
- return x1 * x2
-
- x = lltype.malloc(X, immortal=True); x.foo = 6
- res = self.interpret(f1, [x])
- assert res == 36
- assert self.read_barriers == [x]
-
- def test_call_external_safest(self):
- X = lltype.GcStruct('X', ('foo', lltype.Signed))
- def f1(p):
- register_invoke_around_extcall()
- x1 = p.foo
- external_safest()
- x2 = p.foo
- return x1 * x2
-
- x = lltype.malloc(X, immortal=True); x.foo = 6
- res = self.interpret(f1, [x])
- assert res == 36
- assert self.read_barriers == [x]
-
def test_stm_ignored_read(self):
X = lltype.GcStruct('X', ('foo', lltype.Signed))
x1 = lltype.malloc(X, immortal=True)
@@ -170,19 +48,3 @@
res = self.interpret(f1, [2])
assert res == 42
assert self.read_barriers == [x1]
-
-
-
-
-external_release_gil = rffi.llexternal('external_release_gil', [], lltype.Void,
- _callable=lambda: None,
- random_effects_on_gcobjs=True,
- releasegil=True) # GIL is released
-external_any_gcobj = rffi.llexternal('external_any_gcobj', [], lltype.Void,
- _callable=lambda: None,
- random_effects_on_gcobjs=True,
- releasegil=False) # GIL is not released
-external_safest = rffi.llexternal('external_safest', [], lltype.Void,
- _callable=lambda: None,
- random_effects_on_gcobjs=False,
- releasegil=False) # GIL is not released
diff --git a/rpython/translator/stm/test/transform_support.py
b/rpython/translator/stm/test/transform_support.py
--- a/rpython/translator/stm/test/transform_support.py
+++ b/rpython/translator/stm/test/transform_support.py
@@ -103,6 +103,12 @@
def op_setfield(self, obj, fieldname, fieldvalue):
if obj._TYPE.TO._gckind == 'gc':
+ T = lltype.typeOf(fieldvalue)
+ if isinstance(T, lltype.Ptr) and T.TO._gckind == 'gc':
+ self.check_category(obj, 'W')
+ else:
+ self.check_category(obj, 'V')
+ # convert R -> Q all other pointers to the same object we can find
for p in self.all_stm_ptrs():
if p._category == 'R' and p._T == obj._T and p == obj:
_stmptr._category.__set__(p, 'Q')
@@ -132,6 +138,7 @@
_stmptr._category.__set__(p, 'V')
p = LLFrame.op_malloc(self, obj, flags)
ptr2 = _stmptr(p, 'W')
+ self.llinterpreter.tester.writemode.add(ptr2._obj)
return ptr2
def transaction_break(self):
@@ -140,13 +147,6 @@
if p._category > 'I':
_stmptr._category.__set__(p, 'I')
-
- def op_stm_commit_if_not_atomic(self):
- self.transaction_break()
-
- def op_stm_start_inevitable_if_not_atomic(self):
- self.transaction_break()
-
def op_stm_commit_transaction(self):
self.transaction_break()
diff --git a/rpython/translator/stm/transform.py
b/rpython/translator/stm/transform.py
--- a/rpython/translator/stm/transform.py
+++ b/rpython/translator/stm/transform.py
@@ -2,7 +2,6 @@
from rpython.translator.stm.readbarrier import insert_stm_read_barrier
from rpython.translator.stm.jitdriver import reorganize_around_jit_driver
from rpython.translator.stm.threadlocalref import transform_tlref
-from rpython.translator.stm.breakfinder import TransactionBreakAnalyzer
from rpython.translator.c.support import log
@@ -30,12 +29,10 @@
self.print_logs(3)
def transform_read_barrier(self):
- self.break_analyzer = TransactionBreakAnalyzer(self.translator)
self.read_barrier_counts = 0
for graph in self.translator.graphs:
insert_stm_read_barrier(self, graph)
log.info("%d read barriers inserted" % (self.read_barrier_counts,))
- del self.break_analyzer
def transform_turn_inevitable(self):
for graph in self.translator.graphs:
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit