Author: Remi Meier <remi.me...@inf.ethz.ch> Branch: stmgc-c7 Changeset: r70687:bd3323514386 Date: 2014-04-17 11:14 +0200 http://bitbucket.org/pypy/pypy/changeset/bd3323514386/
Log: try emitting less transaction breaks by adding some logic from optimizeopt/stm.py to heapcache. diff --git a/rpython/jit/metainterp/heapcache.py b/rpython/jit/metainterp/heapcache.py --- a/rpython/jit/metainterp/heapcache.py +++ b/rpython/jit/metainterp/heapcache.py @@ -45,6 +45,13 @@ self.input_indirections = {} self.output_indirections = {} + + # to do some of the work of optimizeopt/stm.py, we have a similar + # logic here: + self.stm_break_wanted = True + + + def _input_indirection(self, box): return self.input_indirections.get(box, box) @@ -120,6 +127,9 @@ opnum == rop.COPYSTRCONTENT or opnum == rop.COPYUNICODECONTENT): return + if opnum in (rop.GUARD_NOT_FORCED, rop.GUARD_NOT_FORCED_2): + self.stm_break_wanted = True + return if (rop._OVF_FIRST <= opnum <= rop._OVF_LAST or rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST or rop._GUARD_FIRST <= opnum <= rop._GUARD_LAST): @@ -184,6 +194,7 @@ del cache[frombox] return else: + self.stm_break_wanted = True # Only invalidate things that are either escaped or arguments for descr, boxes in self.heap_cache.iteritems(): for box in boxes.keys(): @@ -202,6 +213,8 @@ self.heap_cache.clear() self.heap_array_cache.clear() + self.stm_break_wanted = True + def is_class_known(self, box): return box in self.known_class_boxes @@ -308,3 +321,6 @@ def replace_box(self, oldbox, newbox): self.input_indirections[self._output_indirection(newbox)] = self._input_indirection(oldbox) self.output_indirections[self._input_indirection(oldbox)] = self._output_indirection(newbox) + + def stm_break_done(self): + self.stm_break_wanted = False diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py --- a/rpython/jit/metainterp/pyjitpl.py +++ b/rpython/jit/metainterp/pyjitpl.py @@ -197,25 +197,33 @@ mi.vrefs_after_residual_call() mi.vable_after_residual_call() mi.generate_guard(rop.GUARD_NOT_FORCED, None) - - + self.metainterp.heapcache.stm_break_done() + + @arguments("int") def opimpl_stm_should_break_transaction(self, if_there_is_no_other): - from rpython.rtyper.lltypesystem import llmemory val = bool(if_there_is_no_other) mi = self.metainterp if val: + # app-level loop: only one of these per loop is really needed resbox = history.BoxInt(0) mi.history.record(rop.STM_SHOULD_BREAK_TRANSACTION, [], resbox) + self.metainterp.heapcache.stm_break_done() return resbox else: - self._record_stm_transaction_break(False) + # between byte-code instructions: only keep if it is + # likely that we are inevitable here + if self.metainterp.heapcache.stm_break_wanted: + self._record_stm_transaction_break(False) return ConstInt(0) @arguments() def opimpl_stm_transaction_break(self): + # always wanted: inserted after we compile a bridge because there + # were just too many breaks and we failed the should_break&guard + # because of that self._record_stm_transaction_break(True) - + for _opimpl in ['int_add', 'int_sub', 'int_mul', 'int_floordiv', 'int_mod', 'int_lt', 'int_le', 'int_eq', 'int_ne', 'int_gt', 'int_ge', @@ -1692,7 +1700,7 @@ self.call_ids = [] self.current_call_id = 0 - + def retrace_needed(self, trace): self.partial_trace = trace @@ -1819,6 +1827,8 @@ if opnum == rop.GUARD_NOT_FORCED or opnum == rop.GUARD_NOT_FORCED_2: resumedescr = compile.ResumeGuardForcedDescr(self.staticdata, self.jitdriver_sd) + # for detecting stm breaks that are needed + self.heapcache.invalidate_caches(opnum, resumedescr, moreargs) elif opnum == rop.GUARD_NOT_INVALIDATED: resumedescr = compile.ResumeGuardNotInvalidated() else: diff --git a/rpython/jit/metainterp/test/test_heapcache.py b/rpython/jit/metainterp/test/test_heapcache.py --- a/rpython/jit/metainterp/test/test_heapcache.py +++ b/rpython/jit/metainterp/test/test_heapcache.py @@ -533,3 +533,27 @@ [] ) assert h.getarrayitem(box1, index1, descr1) is box3 + + def test_stm_break(self): + h = HeapCache() + assert h.stm_break_wanted + h.stm_break_done() + assert not h.stm_break_wanted + # loop headers + h.reset() + assert h.stm_break_wanted + h.stm_break_done() + assert not h.stm_break_wanted + # call that may make the transaction inevitable + h.invalidate_caches( + rop.CALL, FakeCallDescr(FakeEffectinfo.EF_RANDOM_EFFECTS), [box1] + ) + assert h.stm_break_wanted + h.stm_break_done() + # unknown op + h.invalidate_caches(rop.JIT_DEBUG, None, [box1, lengthbox2, box2]) + assert h.stm_break_wanted + h.stm_break_done() + # GUARD_NOT_FORCED + h.invalidate_caches(rop.GUARD_NOT_FORCED, None, []) + assert h.stm_break_wanted diff --git a/rpython/jit/metainterp/test/test_stm.py b/rpython/jit/metainterp/test/test_stm.py --- a/rpython/jit/metainterp/test/test_stm.py +++ b/rpython/jit/metainterp/test/test_stm.py @@ -43,16 +43,29 @@ self.interp_operations(g, [], translationoptions={"stm":True}) self.check_operations_history({'stm_transaction_break':1, 'guard_not_forced':1}) - - - + + def test_heapcache(self): + import time + def g(): + rstm.jit_stm_should_break_transaction(True) # keep (start of loop) + rstm.jit_stm_should_break_transaction(False) + time.sleep(0) + rstm.jit_stm_should_break_transaction(False) # keep (after guard_not_forced) + rstm.jit_stm_should_break_transaction(True) # keep (True) + rstm.jit_stm_should_break_transaction(True) # keep (True) + rstm.jit_stm_should_break_transaction(False) + return 42 + res = self.interp_operations(g, [], translationoptions={"stm":True}) + assert res == 42 + self.check_operations_history({ + 'stm_transaction_break':1, + 'stm_should_break_transaction':3, + 'guard_not_forced':2, + 'guard_no_exception':1, + 'call_may_force':1}) + + + class TestLLtype(STMTests, LLJitMixin): pass - - - - - - - diff --git a/rpython/rlib/rstm.py b/rpython/rlib/rstm.py --- a/rpython/rlib/rstm.py +++ b/rpython/rlib/rstm.py @@ -37,6 +37,7 @@ if we_are_translated(): llop.jit_stm_transaction_break_point(lltype.Void) +@specialize.arg(0) def jit_stm_should_break_transaction(if_there_is_no_other): # XXX REFACTOR AWAY # if_there_is_no_other means that we use this point only _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit