[pypy-commit] pypy default: don't add superfluous QUASIIMMUT_FIELD during tracing (I've seen their creation
cfbolz
pypy.commits at gmail.com
Thu Jun 30 08:42:32 EDT 2016
Author: Carl Friedrich Bolz <cfbolz at 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
More information about the pypy-commit
mailing list