[pypy-svn] r78370 - in pypy/branch/mapdict-without-jit/pypy: module/__pypy__ module/gc module/gc/test objspace/std objspace/std/test

arigo at codespeak.net arigo at codespeak.net
Wed Oct 27 17:47:57 CEST 2010


Author: arigo
Date: Wed Oct 27 17:47:56 2010
New Revision: 78370

Modified:
   pypy/branch/mapdict-without-jit/pypy/module/__pypy__/__init__.py
   pypy/branch/mapdict-without-jit/pypy/module/__pypy__/interp_magic.py
   pypy/branch/mapdict-without-jit/pypy/module/gc/interp_gc.py
   pypy/branch/mapdict-without-jit/pypy/module/gc/test/test_gc.py
   pypy/branch/mapdict-without-jit/pypy/objspace/std/mapdict.py
   pypy/branch/mapdict-without-jit/pypy/objspace/std/test/test_dictmultiobject.py
   pypy/branch/mapdict-without-jit/pypy/objspace/std/test/test_mapdict.py
Log:
(cfbolz, arigo)
Add the IndexCache to mapdict, similar to MethodCache.


Modified: pypy/branch/mapdict-without-jit/pypy/module/__pypy__/__init__.py
==============================================================================
--- pypy/branch/mapdict-without-jit/pypy/module/__pypy__/__init__.py	(original)
+++ pypy/branch/mapdict-without-jit/pypy/module/__pypy__/__init__.py	Wed Oct 27 17:47:56 2010
@@ -23,5 +23,8 @@
                                  'interp_magic.method_cache_counter')
             self.extra_interpdef('reset_method_cache_counter',
                                  'interp_magic.reset_method_cache_counter')
+            if self.space.config.objspace.std.withmapdict:
+                self.extra_interpdef('mapdict_cache_counter',
+                                     'interp_magic.mapdict_cache_counter')
         PYC_MAGIC = get_pyc_magic(self.space)
         self.extra_interpdef('PYC_MAGIC', 'space.wrap(%d)' % PYC_MAGIC)

Modified: pypy/branch/mapdict-without-jit/pypy/module/__pypy__/interp_magic.py
==============================================================================
--- pypy/branch/mapdict-without-jit/pypy/module/__pypy__/interp_magic.py	(original)
+++ pypy/branch/mapdict-without-jit/pypy/module/__pypy__/interp_magic.py	Wed Oct 27 17:47:56 2010
@@ -2,6 +2,7 @@
 from pypy.interpreter.gateway import ObjSpace
 from pypy.rlib.objectmodel import we_are_translated
 from pypy.objspace.std.typeobject import MethodCache
+from pypy.objspace.std.mapdict import IndexCache
 
 def internal_repr(space, w_object):
     return space.wrap('%r' % (w_object,))
@@ -36,4 +37,17 @@
     cache = space.fromcache(MethodCache)
     cache.misses = {}
     cache.hits = {}
-
+    if space.config.objspace.std.withmapdict:
+        cache = space.fromcache(IndexCache)
+        cache.misses = {}
+        cache.hits = {}
+
+def mapdict_cache_counter(space, name):
+    """Return a tuple (index_cache_hits, index_cache_misses) for lookups
+    in the mapdict cache with the given attribute name."""
+    assert space.config.objspace.std.withmethodcachecounter
+    assert space.config.objspace.std.withmapdict
+    cache = space.fromcache(IndexCache)
+    return space.newtuple([space.newint(cache.hits.get(name, 0)),
+                           space.newint(cache.misses.get(name, 0))])
+mapdict_cache_counter.unwrap_spec = [ObjSpace, str]

Modified: pypy/branch/mapdict-without-jit/pypy/module/gc/interp_gc.py
==============================================================================
--- pypy/branch/mapdict-without-jit/pypy/module/gc/interp_gc.py	(original)
+++ pypy/branch/mapdict-without-jit/pypy/module/gc/interp_gc.py	Wed Oct 27 17:47:56 2010
@@ -10,6 +10,10 @@
         from pypy.objspace.std.typeobject import MethodCache
         cache = space.fromcache(MethodCache)
         cache.clear()
+        if space.config.objspace.std.withmapdict:
+            from pypy.objspace.std.mapdict import IndexCache
+            cache = space.fromcache(IndexCache)
+            cache.clear()
     rgc.collect()
     return space.wrap(0)
     

Modified: pypy/branch/mapdict-without-jit/pypy/module/gc/test/test_gc.py
==============================================================================
--- pypy/branch/mapdict-without-jit/pypy/module/gc/test/test_gc.py	(original)
+++ pypy/branch/mapdict-without-jit/pypy/module/gc/test/test_gc.py	Wed Oct 27 17:47:56 2010
@@ -122,3 +122,8 @@
         gc.collect()    # the classes C should all go away here
         for r in rlist:
             assert r() is None
+
+class AppTestGcMapDictIndexCache(AppTestGcMethodCache):
+    def setup_class(cls):
+        cls.space = gettestobjspace(**{"objspace.std.withmethodcache": True,
+                                       "objspace.std.withmapdict": True})

Modified: pypy/branch/mapdict-without-jit/pypy/objspace/std/mapdict.py
==============================================================================
--- pypy/branch/mapdict-without-jit/pypy/objspace/std/mapdict.py	(original)
+++ pypy/branch/mapdict-without-jit/pypy/objspace/std/mapdict.py	Wed Oct 27 17:47:56 2010
@@ -1,4 +1,5 @@
 from pypy.rlib import jit, objectmodel, debug
+from pypy.rlib.rarithmetic import intmask, r_uint
 
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.objspace.std.dictmultiobject import W_DictMultiObject
@@ -40,7 +41,44 @@
     def delete(self, obj, selector):
         return None
 
+    @jit.purefunction
     def index(self, selector):
+        if self.space.config.objspace.std.withmethodcache:
+            return self._index_cache(selector)
+        else:
+            return self._index(selector)
+
+    def _index_cache(self, selector):
+        space = self.space
+        cache = space.fromcache(IndexCache)
+        SHIFT2 = r_uint.BITS - space.config.objspace.std.methodcachesizeexp
+        SHIFT1 = SHIFT2 - 5
+        attrs_as_int = objectmodel.current_object_addr_as_int(self)
+        # ^^^Note: see comment in typeobject.py for
+        # _pure_lookup_where_with_method_cache()
+        hash_selector = objectmodel.compute_hash(selector)
+        product = intmask(attrs_as_int * hash_selector)
+        index_hash = (r_uint(product) ^ (r_uint(product) << SHIFT1)) >> SHIFT2
+        # ^^^Note2: same comment too
+        cached_attr = cache.attrs[index_hash]
+        if cached_attr is self:
+            cached_selector = cache.selectors[index_hash]
+            if cached_selector == selector:
+                index = cache.indices[index_hash]
+                if space.config.objspace.std.withmethodcachecounter:
+                    name = selector[0]
+                    cache.hits[name] = cache.hits.get(name, 0) + 1
+                return index
+        index = self._index(selector)
+        cache.attrs[index_hash] = self
+        cache.selectors[index_hash] = selector
+        cache.indices[index_hash] = index
+        if space.config.objspace.std.withmethodcachecounter:
+            name = selector[0]
+            cache.misses[name] = cache.misses.get(name, 0) + 1
+        return index
+
+    def _index(self, selector):
         return -1
 
     def copy(self, obj):
@@ -221,10 +259,10 @@
             self._copy_attr(obj, new_obj)
         return new_obj
 
-    def index(self, selector):
+    def _index(self, selector):
         if selector == self.selector:
             return self.position
-        return self.back.index(selector)
+        return self.back._index(selector)
 
     def copy(self, obj):
         new_obj = self.back.copy(obj)
@@ -267,6 +305,23 @@
     # RPython reasons
     w_obj._set_mapdict_storage_and_map(new_obj.storage, new_obj.map)
 
+class IndexCache(object):
+    def __init__(self, space):
+        assert space.config.objspace.std.withmethodcache
+        SIZE = 1 << space.config.objspace.std.methodcachesizeexp
+        self.attrs = [None] * SIZE
+        self.selectors = [None] * SIZE
+        self.indices = [0] * SIZE
+        if space.config.objspace.std.withmethodcachecounter:
+            self.hits = {}
+            self.misses = {}
+
+    def clear(self):
+        for i in range(len(self.attrs)):
+            self.attrs[i] = None
+        for i in range(len(self.selectors)):
+            self.selectors[i] = None
+
 # ____________________________________________________________
 # object implementation
 

Modified: pypy/branch/mapdict-without-jit/pypy/objspace/std/test/test_dictmultiobject.py
==============================================================================
--- pypy/branch/mapdict-without-jit/pypy/objspace/std/test/test_dictmultiobject.py	(original)
+++ pypy/branch/mapdict-without-jit/pypy/objspace/std/test/test_dictmultiobject.py	Wed Oct 27 17:47:56 2010
@@ -607,6 +607,7 @@
             withdictmeasurement = False
             withsmalldicts = False
             withcelldict = False
+            withmethodcache = False
         class opcodes:
             CALL_LIKELY_BUILTIN = False
 

Modified: pypy/branch/mapdict-without-jit/pypy/objspace/std/test/test_mapdict.py
==============================================================================
--- pypy/branch/mapdict-without-jit/pypy/objspace/std/test/test_mapdict.py	(original)
+++ pypy/branch/mapdict-without-jit/pypy/objspace/std/test/test_mapdict.py	Wed Oct 27 17:47:56 2010
@@ -24,7 +24,6 @@
         hasdict = False
 
 def test_plain_attribute():
-    space = " "
     w_cls = "class"
     aa = PlainAttribute(("b", DICT),
                         PlainAttribute(("a", DICT),
@@ -778,3 +777,52 @@
         assert res == (0, 0, 1)
         res = self.check(f, 'x')
         assert res == (0, 0, 1)
+
+class AppTestCaching(AppTestWithMapDict):
+    def setup_class(cls):
+        cls.space = gettestobjspace(
+            **{"objspace.std.withmethodcachecounter": True,
+               "objspace.std.withmapdict": True,
+               "objspace.opcodes.CALL_METHOD": True})
+
+    def test_mix_classes(self):
+        import __pypy__
+        class A(object):
+            def f(self):
+                return 42
+        class B(object):
+            def f(self):
+                return 43
+        class C(object):
+            def f(self):
+                return 44
+        l = [A(), B(), C()] * 10
+        __pypy__.reset_method_cache_counter()
+        # 'exec' to make sure that a.f() is compiled with CALL_METHOD
+        exec """for i, a in enumerate(l):
+                    assert a.f() == 42 + i % 3
+"""
+        cache_counter = __pypy__.mapdict_cache_counter("f")
+        assert cache_counter[0] >= 15
+        assert cache_counter[1] >= 3 # should be (27, 3)
+        assert sum(cache_counter) == 30
+
+    def test_mix_classes_attribute(self):
+        import __pypy__
+        class A(object):
+            def __init__(self):
+                self.x = 42
+        class B(object):
+            def __init__(self):
+                self.x = 43
+        class C(object):
+            def __init__(self):
+                self.x = 44
+        l = [A(), B(), C()] * 10
+        __pypy__.reset_method_cache_counter()
+        for i, a in enumerate(l):
+            assert a.x == 42 + i % 3
+        cache_counter = __pypy__.mapdict_cache_counter("x")
+        assert cache_counter[0] >= 15
+        assert cache_counter[1] >= 3 # should be (27, 3)
+        assert sum(cache_counter) == 30



More information about the Pypy-commit mailing list