Author: Carl Friedrich Bolz <cfb...@gmx.de> Branch: Changeset: r85471:b116f09c4e9d Date: 2016-06-30 14:41 +0200 http://bitbucket.org/pypy/pypy/changeset/b116f09c4e9d/
Log: don't add superfluous QUASIIMMUT_FIELD during tracing (I've seen their creation take 2% of the full execution time during profiling) 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 @@ -57,10 +57,16 @@ self.cache_anything = {} self.cache_seen_allocation = {} + # set of boxes that we've seen a quasi-immut for the field on. cleared + # on writes to the field. + self.quasiimmut_seen = None + def _clear_cache_on_write(self, seen_allocation_of_target): if not seen_allocation_of_target: self.cache_seen_allocation.clear() self.cache_anything.clear() + if self.quasiimmut_seen is not None: + self.quasiimmut_seen.clear() def _seen_alloc(self, ref_box): if not isinstance(ref_box, RefFrontendOp): @@ -92,6 +98,8 @@ def invalidate_unescaped(self): self._invalidate_unescaped(self.cache_anything) self._invalidate_unescaped(self.cache_seen_allocation) + if self.quasiimmut_seen is not None: + self.quasiimmut_seen.clear() def _invalidate_unescaped(self, d): for ref_box in d.keys(): @@ -484,3 +492,18 @@ if isinstance(oldbox, FrontendOp) and isinstance(newbox, Const): assert newbox.same_constant(constant_from_op(oldbox)) oldbox.set_replaced_with_const() + + def is_quasi_immut_known(self, fielddescr, box): + cache = self.heap_cache.get(fielddescr, None) + if cache is not None and cache.quasiimmut_seen is not None: + return box in cache.quasiimmut_seen + return False + + def quasi_immut_now_known(self, fielddescr, box): + cache = self.heap_cache.get(fielddescr, None) + if cache is None: + cache = self.heap_cache[fielddescr] = CacheEntry(self) + if cache.quasiimmut_seen is not None: + cache.quasiimmut_seen[box] = None + else: + cache.quasiimmut_seen = {box: None} 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 @@ -829,8 +829,11 @@ mutatefielddescr, orgpc): from rpython.jit.metainterp.quasiimmut import QuasiImmutDescr cpu = self.metainterp.cpu + if self.metainterp.heapcache.is_quasi_immut_known(fielddescr, box): + return descr = QuasiImmutDescr(cpu, box.getref_base(), fielddescr, mutatefielddescr) + self.metainterp.heapcache.quasi_immut_now_known(fielddescr, box) self.metainterp.history.record(rop.QUASIIMMUT_FIELD, [box], None, descr=descr) self.metainterp.generate_guard(rop.GUARD_NOT_INVALIDATED, 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 @@ -797,3 +797,46 @@ h.class_now_known(box1) # interaction of the two families of flags assert not h.is_unescaped(box1) assert h.is_likely_virtual(box1) + + def test_quasiimmut_seen(self): + h = HeapCache() + box1 = RefFrontendOp(1) + box2 = RefFrontendOp(2) + box3 = RefFrontendOp(3) + box4 = RefFrontendOp(4) + assert not h.is_quasi_immut_known(descr1, box1) + assert not h.is_quasi_immut_known(descr1, box2) + assert not h.is_quasi_immut_known(descr2, box3) + assert not h.is_quasi_immut_known(descr2, box4) + h.quasi_immut_now_known(descr1, box1) + assert h.is_quasi_immut_known(descr1, box1) + assert not h.is_quasi_immut_known(descr1, box2) + assert not h.is_quasi_immut_known(descr2, box3) + assert not h.is_quasi_immut_known(descr2, box4) + h.quasi_immut_now_known(descr1, box2) + assert h.is_quasi_immut_known(descr1, box1) + assert h.is_quasi_immut_known(descr1, box2) + assert not h.is_quasi_immut_known(descr2, box3) + assert not h.is_quasi_immut_known(descr2, box4) + h.quasi_immut_now_known(descr2, box3) + assert h.is_quasi_immut_known(descr1, box1) + assert h.is_quasi_immut_known(descr1, box2) + assert h.is_quasi_immut_known(descr2, box3) + assert not h.is_quasi_immut_known(descr2, box4) + h.quasi_immut_now_known(descr2, box4) + assert h.is_quasi_immut_known(descr1, box1) + assert h.is_quasi_immut_known(descr1, box2) + assert h.is_quasi_immut_known(descr2, box3) + assert h.is_quasi_immut_known(descr2, box4) + + # invalidate the descr1 cache + + h.setfield(box1, box3, descr1) + assert not h.is_quasi_immut_known(descr1, box1) + assert not h.is_quasi_immut_known(descr1, box2) + + # a call invalidates everything + h.invalidate_caches( + rop.CALL_N, FakeCallDescr(FakeEffectinfo.EF_CAN_RAISE), []) + assert not h.is_quasi_immut_known(descr2, box3) + assert not h.is_quasi_immut_known(descr2, box4) diff --git a/rpython/jit/metainterp/test/test_tracingopts.py b/rpython/jit/metainterp/test/test_tracingopts.py --- a/rpython/jit/metainterp/test/test_tracingopts.py +++ b/rpython/jit/metainterp/test/test_tracingopts.py @@ -512,6 +512,32 @@ assert res == 4 * 7 self.check_operations_history(getfield_gc_i=2, getfield_gc_r=2) + def test_heap_caching_quasi_immutable(self): + class A: + _immutable_fields_ = ['x?'] + a1 = A() + a1.x = 5 + a2 = A() + a2.x = 7 + + @jit.elidable + def get(n): + if n > 0: + return a1 + return a2 + + def g(a): + return a.x + + def fn(n): + jit.promote(n) + a = get(n) + return g(a) + a.x + res = self.interp_operations(fn, [7]) + assert res == 10 + self.check_operations_history(quasiimmut_field=1) + + def test_heap_caching_multiple_tuples(self): class Gbl(object): pass _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit