[pypy-svn] r76894 - in pypy/branch/gc-module/pypy: module/gc module/gc/test rlib

arigo at codespeak.net arigo at codespeak.net
Mon Sep 6 14:18:20 CEST 2010


Author: arigo
Date: Mon Sep  6 14:18:18 2010
New Revision: 76894

Added:
   pypy/branch/gc-module/pypy/module/gc/referents.py   (contents, props changed)
   pypy/branch/gc-module/pypy/module/gc/test/test_referents.py   (contents, props changed)
Modified:
   pypy/branch/gc-module/pypy/module/gc/__init__.py
   pypy/branch/gc-module/pypy/rlib/rgc.py
Log:
Expose the interface to app-level.


Modified: pypy/branch/gc-module/pypy/module/gc/__init__.py
==============================================================================
--- pypy/branch/gc-module/pypy/module/gc/__init__.py	(original)
+++ pypy/branch/gc-module/pypy/module/gc/__init__.py	Mon Sep  6 14:18:18 2010
@@ -16,6 +16,14 @@
 
     def __init__(self, space, w_name):
         ts = space.config.translation.type_system
-        if ts == 'ootype':
-            del self.interpleveldefs['dump_heap_stats']
+        if ts == 'lltype':
+            self.interpleveldefs.update({
+                'get_rpy_objects': 'referents.get_rpy_objects',
+                'get_rpy_referents': 'referents.get_rpy_referents',
+                'get_rpy_memory_usage': 'referents.get_rpy_memory_usage',
+                'get_objects': 'referents.get_objects',
+                'get_referents': 'referents.get_referents',
+                'get_memory_usage': 'referents.get_memory_usage',
+                'GcRef': 'referents.W_GcRef',
+                })
         MixedModule.__init__(self, space, w_name)

Added: pypy/branch/gc-module/pypy/module/gc/referents.py
==============================================================================
--- (empty file)
+++ pypy/branch/gc-module/pypy/module/gc/referents.py	Mon Sep  6 14:18:18 2010
@@ -0,0 +1,100 @@
+from pypy.rlib import rgc
+from pypy.interpreter.baseobjspace import W_Root, Wrappable
+from pypy.interpreter.typedef import TypeDef
+from pypy.interpreter.gateway import ObjSpace
+from pypy.rlib.objectmodel import we_are_translated
+
+
+class W_GcRef(Wrappable):
+    def __init__(self, gcref):
+        self.gcref = gcref
+
+W_GcRef.typedef = TypeDef("GcRef")
+
+
+def wrap(space, gcref):
+    w_obj = rgc.try_cast_gcref_to_instance(W_Root, gcref)
+    if w_obj is None:
+        w_obj = space.wrap(W_GcRef(gcref))
+    return w_obj
+
+def unwrap(space, w_obj):
+    gcrefobj = space.interpclass_w(w_obj)
+    if isinstance(gcrefobj, W_GcRef):
+        gcref = gcrefobj.gcref
+    else:
+        gcref = rgc.cast_instance_to_gcref(w_obj)
+    return gcref
+
+def get_rpy_objects(space):
+    """Return a list of all objects (huge).
+    This contains a lot of GcRefs."""
+    result = rgc._get_objects()
+    return space.newlist([wrap(space, gcref) for gcref in result])
+
+def get_rpy_referents(space, w_obj):
+    """Return a list of all the referents, as reported by the GC.
+    This is likely to contain a lot of GcRefs."""
+    gcref = unwrap(space, w_obj)
+    lst = rgc._get_referents(gcref)
+    return space.newlist([wrap(space, gcref) for gcref in lst])
+
+def get_rpy_memory_usage(space, w_obj):
+    """Return the memory usage of just the given object or GcRef.
+    This does not include the internal structures of the object."""
+    gcref = unwrap(space, w_obj)
+    size = rgc._get_memory_usage(gcref)
+    return space.wrap(size)
+
+def get_objects(space):
+    """Return a list of all app-level objects."""
+    result = []
+    for gcref in rgc._get_objects():
+        w_obj = rgc.try_cast_gcref_to_instance(W_Root, gcref)
+        if w_obj is not None:
+            if we_are_translated() or hasattr(w_obj, 'typedef'):
+                result.append(w_obj)
+    return space.newlist(result)
+
+def get_referents(space, args_w):
+    """Return the list of objects that directly refer to any of objs.
+    Approximative: follow references recursively until it finds
+    app-level objects."""
+    result = []
+    pending = []
+    for w_obj in args_w:
+        pending.append(unwrap(space, w_obj))
+    i = 0
+    while i < len(pending):
+        gcref = pending[i]
+        i += 1
+        lst = rgc._get_referents(gcref)
+        for gcref in lst:
+            w_subobj = rgc.try_cast_gcref_to_instance(W_Root, gcref)
+            if w_subobj is not None:
+                result.append(w_subobj)
+            elif gcref not in pending:
+                pending.append(gcref)
+    return space.newlist(result)
+get_referents.unwrap_spec = [ObjSpace, 'args_w']
+
+def get_memory_usage(space, args_w):
+    """Return the total size of the object(s) passed as argument.
+    Approximative: follow references recursively and compute the
+    total of the sizes, stopping at other app-level objects."""
+    result = 0
+    pending = []
+    for w_obj in args_w:
+        pending.append(unwrap(space, w_obj))
+    i = 0
+    while i < len(pending):
+        gcref = pending[i]
+        i += 1
+        result += rgc._get_memory_usage(gcref)
+        lst = rgc._get_referents(gcref)
+        for gcref in lst:
+            if (rgc.try_cast_gcref_to_instance(W_Root, gcref) is None
+                and gcref not in pending):
+                pending.append(gcref)
+    return space.wrap(result)
+get_memory_usage.unwrap_spec = [ObjSpace, 'args_w']

Added: pypy/branch/gc-module/pypy/module/gc/test/test_referents.py
==============================================================================
--- (empty file)
+++ pypy/branch/gc-module/pypy/module/gc/test/test_referents.py	Mon Sep  6 14:18:18 2010
@@ -0,0 +1,74 @@
+
+
+class AppTestReferents(object):
+
+    def test_get_objects(self):
+        # XXX this test should be run first, before GcRefs are created.
+        import gc
+        x = [2, 3, 4]
+        lst = gc.get_objects()
+        for found in lst:
+            if found is x:
+                break
+        else:
+            assert 0, "'x' not found in get_rpy_objects"
+        for found in lst:
+            if type(found) is gc.GcRef:
+                assert 0, "get_objects() returned a GcRef"
+
+    def test_get_rpy_objects(self):
+        import gc
+        x = [2, 3, 4]
+        lst = gc.get_rpy_objects()
+        for found in lst:
+            if found is x:
+                break
+        else:
+            assert 0, "'x' not found in get_rpy_objects"
+        for found in lst:
+            if type(found) is gc.GcRef:
+                break
+        else:
+            assert 0, "get_rpy_objects() did not return any GcRef"
+
+    def test_get_rpy_referents(self):
+        import gc
+        y = 12345
+        x = [y]
+        lst = gc.get_rpy_referents(x)
+        # After translation, 'lst' should contain the RPython-level list
+        # (as a GcStruct).  Before translation, the 'wrappeditems' list.
+        print lst
+        lst2 = [x for x in lst if type(x) is gc.GcRef]
+        assert lst2 != []
+        # In any case, we should land on 'y' after one or two extra levels
+        # of indirection.
+        lst3 = []
+        for x in lst2: lst3 += gc.get_rpy_referents(x)
+        if y not in lst3:
+            lst4 = []
+            for x in lst3: lst4 += gc.get_rpy_referents(x)
+            if y not in lst4:
+                assert 0, "does not seem to reach 'y'"
+
+    def test_get_rpy_memory_usage(self):
+        import gc
+        n = gc.get_rpy_memory_usage(12345)
+        print n
+        assert 4 <= n <= 64
+
+    def test_get_referents(self):
+        import gc
+        y = 12345
+        z = 23456
+        x = [y, z]
+        lst = gc.get_referents(x)
+        assert y in lst and z in lst
+
+    def test_get_memory_usage(self):
+        import gc
+        x = [2, 5, 10]
+        n = gc.get_rpy_memory_usage(x)
+        m = gc.get_memory_usage(x)
+        print n, m
+        assert 4 <= n < m <= 128

Modified: pypy/branch/gc-module/pypy/rlib/rgc.py
==============================================================================
--- pypy/branch/gc-module/pypy/rlib/rgc.py	(original)
+++ pypy/branch/gc-module/pypy/rlib/rgc.py	Mon Sep  6 14:18:18 2010
@@ -321,8 +321,23 @@
     return map(_GcRef, lst)
 
 def _get_referents(gcref):
-    lst = gc.get_referents(gcref._x)
-    return map(_GcRef, lst)
+    x = gcref._x
+    if isinstance(x, list):
+        return map(_GcRef, x)
+    elif isinstance(x, dict):
+        return map(_GcRef, x.keys() + x.values())
+    else:
+        if hasattr(x, '__dict__'):
+            d = map(_GcRef, x.__dict__.values())
+        else:
+            d = []
+        if hasattr(type(x), '__slots__'):
+            for slot in type(x).__slots__:
+                try:
+                    d.append(_GcRef(getattr(x, slot)))
+                except AttributeError:
+                    pass
+        return d
 
 def _get_memory_usage(gcref):
     # approximate implementation using CPython's type info



More information about the Pypy-commit mailing list