Author: Carl Friedrich Bolz <cfb...@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 _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit