[pypy-commit] pypy improve-heap-caching-tracing: move all the heap caching to the new file. add unit tests.
cfbolz
noreply at buildbot.pypy.org
Fri Sep 2 11:24:09 CEST 2011
Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: improve-heap-caching-tracing
Changeset: r47012:8549556a3847
Date: 2011-09-02 11:22 +0200
http://bitbucket.org/pypy/pypy/changeset/8549556a3847/
Log: move all the heap caching to the new file. add unit tests.
diff --git a/pypy/jit/metainterp/heapcache.py b/pypy/jit/metainterp/heapcache.py
--- a/pypy/jit/metainterp/heapcache.py
+++ b/pypy/jit/metainterp/heapcache.py
@@ -1,4 +1,5 @@
-
+from pypy.jit.metainterp.resoperation import rop
+from pypy.jit.metainterp.history import ConstInt
class HeapCache(object):
def __init__(self):
@@ -9,6 +10,29 @@
self.known_class_boxes = {}
# contains frame boxes that are not virtualizables
self.nonstandard_virtualizables = {}
+ # heap cache
+ # maps descrs to (from_box, to_box) tuples
+ self.heap_cache = {}
+ # heap array cache
+ # maps descrs to {index: (from_box, to_box)} dicts
+ self.heap_array_cache = {}
+
+ def invalidate_caches(self, opnum, descr):
+ if opnum == rop.SETFIELD_GC:
+ return
+ if opnum == rop.SETARRAYITEM_GC:
+ return
+ if rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST:
+ return
+ if opnum == rop.CALL:
+ effectinfo = descr.get_extra_info()
+ ef = effectinfo.extraeffect
+ if ef == effectinfo.EF_LOOPINVARIANT or \
+ ef == effectinfo.EF_ELIDABLE_CANNOT_RAISE or \
+ ef == effectinfo.EF_ELIDABLE_CAN_RAISE:
+ return
+ self.heap_cache.clear()
+ self.heap_array_cache.clear()
def is_class_known(self, box):
return box in self.known_class_boxes
@@ -21,3 +45,46 @@
def nonstandard_virtualizables_now_known(self, box):
self.nonstandard_virtualizables[box] = None
+
+
+ def getfield(self, box, descr):
+ frombox, tobox = self.heap_cache.get(descr, (None, None))
+ if box is frombox:
+ return tobox
+ return None
+
+ def setfield(self, box, descr, fieldbox):
+ self.heap_cache[descr] = (box, fieldbox)
+
+ def getarrayitem(self, box, descr, indexbox):
+ if not isinstance(indexbox, ConstInt):
+ return
+ index = indexbox.getint()
+ cache = self.heap_array_cache.get(descr, None)
+ if cache:
+ frombox, tobox = cache.get(index, (None, None))
+ if frombox is box:
+ return tobox
+
+ def setarrayitem(self, box, descr, indexbox, valuebox):
+ if not isinstance(indexbox, ConstInt):
+ cache = self.heap_array_cache.get(descr, None)
+ if cache is not None:
+ cache.clear()
+ return
+ cache = self.heap_array_cache.setdefault(descr, {})
+ index = indexbox.getint()
+ cache[index] = box, valuebox
+
+ def replace_box(self, oldbox, newbox):
+ for descr, (frombox, tobox) in self.heap_cache.iteritems():
+ change = False
+ if frombox is oldbox:
+ change = True
+ frombox = newbox
+ if tobox is oldbox:
+ change = True
+ tobox = newbox
+ if change:
+ self.heap_cache[descr] = frombox, tobox
+ # XXX what about self.heap_array_cache?
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -398,19 +398,14 @@
@arguments("box", "descr", "box")
def _opimpl_getarrayitem_gc_any(self, arraybox, arraydescr, indexbox):
- cache = self.metainterp.heap_array_cache.get(arraydescr, None)
- if cache and isinstance(indexbox, ConstInt):
- index = indexbox.getint()
- frombox, tobox = cache.get(index, (None, None))
- if frombox is arraybox:
- return tobox
+ tobox = self.metainterp.heapcache.getarrayitem(
+ arraybox, arraydescr, indexbox)
+ if tobox:
+ return tobox
resbox = self.execute_with_descr(rop.GETARRAYITEM_GC,
arraydescr, arraybox, indexbox)
- if isinstance(indexbox, ConstInt):
- if not cache:
- cache = self.metainterp.heap_array_cache[arraydescr] = {}
- index = indexbox.getint()
- cache[index] = arraybox, resbox
+ self.metainterp.heapcache.setarrayitem(
+ arraybox, arraydescr, indexbox, resbox)
return resbox
@@ -440,13 +435,8 @@
indexbox, itembox):
self.execute_with_descr(rop.SETARRAYITEM_GC, arraydescr, arraybox,
indexbox, itembox)
- if isinstance(indexbox, ConstInt):
- cache = self.metainterp.heap_array_cache.setdefault(arraydescr, {})
- cache[indexbox.getint()] = arraybox, itembox
- else:
- cache = self.metainterp.heap_array_cache.get(arraydescr, None)
- if cache:
- cache.clear()
+ self.metainterp.heapcache.setarrayitem(
+ arraybox, arraydescr, indexbox, itembox)
opimpl_setarrayitem_gc_i = _opimpl_setarrayitem_gc_any
opimpl_setarrayitem_gc_r = _opimpl_setarrayitem_gc_any
@@ -541,11 +531,11 @@
@specialize.arg(1)
def _opimpl_getfield_gc_any_pureornot(self, opnum, box, fielddescr):
- frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None))
- if frombox is box:
+ tobox = self.metainterp.heapcache.getfield(box, fielddescr)
+ if tobox is not None:
return tobox
resbox = self.execute_with_descr(opnum, fielddescr, box)
- self.metainterp.heap_cache[fielddescr] = (box, resbox)
+ self.metainterp.heapcache.setfield(box, fielddescr, resbox)
return resbox
@arguments("orgpc", "box", "descr")
@@ -566,11 +556,11 @@
@arguments("box", "descr", "box")
def _opimpl_setfield_gc_any(self, box, fielddescr, valuebox):
- frombox, tobox = self.metainterp.heap_cache.get(fielddescr, (None, None))
- if frombox is box and tobox is valuebox:
+ tobox = self.metainterp.heapcache.getfield(box, fielddescr)
+ if tobox is valuebox:
return
self.execute_with_descr(rop.SETFIELD_GC, fielddescr, box, valuebox)
- self.metainterp.heap_cache[fielddescr] = (box, valuebox)
+ self.metainterp.heapcache.setfield(box, fielddescr, valuebox)
opimpl_setfield_gc_i = _opimpl_setfield_gc_any
opimpl_setfield_gc_r = _opimpl_setfield_gc_any
opimpl_setfield_gc_f = _opimpl_setfield_gc_any
@@ -1494,12 +1484,6 @@
self.retracing_loop_from = None
self.call_pure_results = args_dict_box()
self.heapcache = HeapCache()
- # heap cache
- # maps descrs to (from_box, to_box) tuples
- self.heap_cache = {}
- # heap array cache
- # maps descrs to {index: (from_box, to_box)} dicts
- self.heap_array_cache = {}
def perform_call(self, jitcode, boxes, greenkey=None):
# causes the metainterp to enter the given subfunction
@@ -1675,29 +1659,11 @@
# record the operation
profiler = self.staticdata.profiler
profiler.count_ops(opnum, RECORDED_OPS)
- self._invalidate_caches(opnum, descr)
+ self.heapcache.invalidate_caches(opnum, descr)
op = self.history.record(opnum, argboxes, resbox, descr)
self.attach_debug_info(op)
return resbox
- def _invalidate_caches(self, opnum, descr):
- if opnum == rop.SETFIELD_GC:
- return
- if opnum == rop.SETARRAYITEM_GC:
- return
- if rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST:
- return
- if opnum == rop.CALL:
- effectinfo = descr.get_extra_info()
- ef = effectinfo.extraeffect
- if ef == effectinfo.EF_LOOPINVARIANT or \
- ef == effectinfo.EF_ELIDABLE_CANNOT_RAISE or \
- ef == effectinfo.EF_ELIDABLE_CAN_RAISE:
- return
- if self.heap_cache:
- self.heap_cache.clear()
- if self.heap_array_cache:
- self.heap_array_cache.clear()
def attach_debug_info(self, op):
if (not we_are_translated() and op is not None
@@ -1861,8 +1827,6 @@
def reached_loop_header(self, greenboxes, redboxes, resumedescr):
self.heapcache.reset()
- self.heap_cache = {}
- self.heap_array_cache = {}
duplicates = {}
self.remove_consts_and_duplicates(redboxes, len(redboxes),
@@ -2370,17 +2334,7 @@
for i in range(len(boxes)):
if boxes[i] is oldbox:
boxes[i] = newbox
- for descr, (frombox, tobox) in self.heap_cache.iteritems():
- change = False
- if frombox is oldbox:
- change = True
- frombox = newbox
- if tobox is oldbox:
- change = True
- tobox = newbox
- if change:
- self.heap_cache[descr] = frombox, tobox
- # XXX what about self.heap_array_cache?
+ self.heapcache.replace_box(oldbox, newbox)
def find_biggest_function(self):
start_stack = []
diff --git a/pypy/jit/metainterp/test/test_heapcache.py b/pypy/jit/metainterp/test/test_heapcache.py
--- a/pypy/jit/metainterp/test/test_heapcache.py
+++ b/pypy/jit/metainterp/test/test_heapcache.py
@@ -1,4 +1,36 @@
from pypy.jit.metainterp.heapcache import HeapCache
+from pypy.jit.metainterp.resoperation import rop
+from pypy.jit.metainterp.history import ConstInt
+
+box1 = object()
+box2 = object()
+box3 = object()
+box4 = object()
+descr1 = object()
+descr2 = object()
+
+index1 = ConstInt(0)
+index2 = ConstInt(1)
+
+
+class FakeEffektinfo(object):
+ EF_ELIDABLE_CANNOT_RAISE = 0 #elidable function (and cannot raise)
+ EF_LOOPINVARIANT = 1 #special: call it only once per loop
+ EF_CANNOT_RAISE = 2 #a function which cannot raise
+ EF_ELIDABLE_CAN_RAISE = 3 #elidable function (but can raise)
+ EF_CAN_RAISE = 4 #normal function (can raise)
+ EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE = 5 #can raise and force virtualizables
+ EF_RANDOM_EFFECTS = 6 #can do whatever
+
+ def __init__(self, extraeffect):
+ self.extraeffect = extraeffect
+
+class FakeCallDescr(object):
+ def __init__(self, extraeffect):
+ self.extraeffect = extraeffect
+
+ def get_extra_info(self):
+ return FakeEffektinfo(self.extraeffect)
class TestHeapCache(object):
def test_known_class_box(self):
@@ -24,3 +56,113 @@
h.reset()
assert not h.is_nonstandard_virtualizable(1)
assert not h.is_nonstandard_virtualizable(2)
+
+
+ def test_heapcache_fields(self):
+ h = HeapCache()
+ assert h.getfield(box1, descr1) is None
+ assert h.getfield(box1, descr2) is None
+ h.setfield(box1, descr1, box2)
+ assert h.getfield(box1, descr1) is box2
+ assert h.getfield(box1, descr2) is None
+ h.setfield(box1, descr2, box3)
+ assert h.getfield(box1, descr1) is box2
+ assert h.getfield(box1, descr2) is box3
+ h.setfield(box1, descr1, box3)
+ assert h.getfield(box1, descr1) is box3
+ assert h.getfield(box1, descr2) is box3
+ h.setfield(box3, descr1, box1)
+ assert h.getfield(box3, descr1) is box1
+ assert h.getfield(box1, descr1) is None
+ assert h.getfield(box1, descr2) is box3
+
+ h.reset()
+ assert h.getfield(box1, descr1) is None
+ assert h.getfield(box1, descr2) is None
+ assert h.getfield(box3, descr1) is None
+
+ def test_heapcache_arrays(self):
+ h = HeapCache()
+ assert h.getarrayitem(box1, descr1, index1) is None
+ assert h.getarrayitem(box1, descr2, index1) is None
+ assert h.getarrayitem(box1, descr1, index2) is None
+ assert h.getarrayitem(box1, descr2, index2) is None
+
+ h.setarrayitem(box1, descr1, index1, box2)
+ assert h.getarrayitem(box1, descr1, index1) is box2
+ assert h.getarrayitem(box1, descr2, index1) is None
+ assert h.getarrayitem(box1, descr1, index2) is None
+ assert h.getarrayitem(box1, descr2, index2) is None
+ h.setarrayitem(box1, descr1, index2, box4)
+ assert h.getarrayitem(box1, descr1, index1) is box2
+ assert h.getarrayitem(box1, descr2, index1) is None
+ assert h.getarrayitem(box1, descr1, index2) is box4
+ assert h.getarrayitem(box1, descr2, index2) is None
+
+ h.setarrayitem(box1, descr2, index1, box3)
+ assert h.getarrayitem(box1, descr1, index1) is box2
+ assert h.getarrayitem(box1, descr2, index1) is box3
+ assert h.getarrayitem(box1, descr1, index2) is box4
+ assert h.getarrayitem(box1, descr2, index2) is None
+
+ h.setarrayitem(box1, descr1, index1, box3)
+ assert h.getarrayitem(box1, descr1, index1) is box3
+ assert h.getarrayitem(box1, descr2, index1) is box3
+ assert h.getarrayitem(box1, descr1, index2) is box4
+ assert h.getarrayitem(box1, descr2, index2) is None
+
+ h.setarrayitem(box3, descr1, index1, box1)
+ assert h.getarrayitem(box3, descr1, index1) is box1
+ assert h.getarrayitem(box1, descr1, index1) is None
+ assert h.getarrayitem(box1, descr2, index1) is box3
+ assert h.getarrayitem(box1, descr1, index2) is box4
+ assert h.getarrayitem(box1, descr2, index2) is None
+
+ h.reset()
+ assert h.getarrayitem(box1, descr1, index1) is None
+ assert h.getarrayitem(box1, descr2, index1) is None
+ assert h.getarrayitem(box3, descr1, index1) is None
+
+ def test_heapcache_array_nonconst_index(self):
+ h = HeapCache()
+ h.setarrayitem(box1, descr1, index1, box2)
+ h.setarrayitem(box1, descr1, index2, box4)
+ assert h.getarrayitem(box1, descr1, index1) is box2
+ assert h.getarrayitem(box1, descr1, index2) is box4
+ h.setarrayitem(box1, descr1, box2, box3)
+ assert h.getarrayitem(box1, descr1, index1) is None
+ assert h.getarrayitem(box1, descr1, index2) is None
+
+ def test_invalidate_cache(self):
+ h = HeapCache()
+ h.setfield(box1, descr1, box2)
+ h.setarrayitem(box1, descr1, index1, box2)
+ h.setarrayitem(box1, descr1, index2, box4)
+ h.invalidate_caches(rop.INT_ADD, None)
+ assert h.getfield(box1, descr1) is box2
+ assert h.getarrayitem(box1, descr1, index1) is box2
+ assert h.getarrayitem(box1, descr1, index2) is box4
+
+ h.invalidate_caches(
+ rop.CALL, FakeCallDescr(FakeEffektinfo.EF_ELIDABLE_CANNOT_RAISE))
+ assert h.getfield(box1, descr1) is box2
+ assert h.getarrayitem(box1, descr1, index1) is box2
+ assert h.getarrayitem(box1, descr1, index2) is box4
+
+
+ h.invalidate_caches(
+ rop.CALL, FakeCallDescr(FakeEffektinfo.EF_RANDOM_EFFECTS))
+ assert h.getfield(box1, descr1) is None
+ assert h.getarrayitem(box1, descr1, index1) is None
+ assert h.getarrayitem(box1, descr1, index2) is None
+
+
+ def test_replace_box(self):
+ h = HeapCache()
+ h.setfield(box1, descr1, box2)
+ h.setfield(box1, descr2, box3)
+ h.replace_box(box1, box4)
+ assert h.getfield(box1, descr1) is None
+ assert h.getfield(box1, descr2) is None
+ assert h.getfield(box4, descr1) is box2
+ assert h.getfield(box4, descr2) is box3
More information about the pypy-commit
mailing list