[pypy-svn] r68739 - in pypy/branch/gc-dump-heap/pypy: rlib rpython rpython/lltypesystem rpython/memory/gc rpython/memory/gctransform rpython/memory/test

fijal at codespeak.net fijal at codespeak.net
Sun Oct 25 21:00:09 CET 2009


Author: fijal
Date: Sun Oct 25 21:00:07 2009
New Revision: 68739

Modified:
   pypy/branch/gc-dump-heap/pypy/rlib/rgc.py
   pypy/branch/gc-dump-heap/pypy/rpython/llinterp.py
   pypy/branch/gc-dump-heap/pypy/rpython/lltypesystem/lloperation.py
   pypy/branch/gc-dump-heap/pypy/rpython/lltypesystem/opimpl.py
   pypy/branch/gc-dump-heap/pypy/rpython/memory/gc/base.py
   pypy/branch/gc-dump-heap/pypy/rpython/memory/gc/semispace.py
   pypy/branch/gc-dump-heap/pypy/rpython/memory/gctransform/framework.py
   pypy/branch/gc-dump-heap/pypy/rpython/memory/test/test_gc.py
   pypy/branch/gc-dump-heap/pypy/rpython/memory/test/test_transformed_gc.py
Log:
Implement heap dumping for a semispace gc. fails with generation and hybrid
for now. Also explodes on C backend.

Introduce a new operation llop.get_member_index which returns an index
in memberoffset


Modified: pypy/branch/gc-dump-heap/pypy/rlib/rgc.py
==============================================================================
--- pypy/branch/gc-dump-heap/pypy/rlib/rgc.py	(original)
+++ pypy/branch/gc-dump-heap/pypy/rlib/rgc.py	Sun Oct 25 21:00:07 2009
@@ -184,6 +184,41 @@
         hop.exception_cannot_occur()
         return hop.genop('gc_can_move', hop.args_v, resulttype=hop.r_result)
 
+def dump_heap(fd):
+    import os
+    
+    tb = _dump_heap()
+    for i in range(len(tb)):
+        next = tb[i]
+        os.write(fd, str(next.count) + " " + ",".join([
+            str(next.links[j]) for j in range(len(tb))]) + "\n")
+    _clear_dump_heap(tb)
+
+def _clear_dump_heap(tb):
+    from pypy.rpython.lltypesystem import lltype
+    for i in range(len(tb)):
+        lltype.free(tb[i].links, flavor='raw')
+    lltype.free(tb, flavor='raw')
+
+def _dump_heap():
+    raise NotImplementedError # can't be run directly
+
+class DumpHeapEntry(ExtRegistryEntry):
+    _about_ = _dump_heap
+
+    def compute_result_annotation(self):
+        from pypy.annotation import model as annmodel
+        from pypy.rpython.memory.gc.base import ARRAY_TYPEID_MAP
+        from pypy.rpython.lltypesystem import lltype
+        return annmodel.SomePtr(lltype.Ptr(ARRAY_TYPEID_MAP))
+
+    def specialize_call(self, hop):
+        from pypy.rpython.lltypesystem import lltype
+        from pypy.rpython.memory.gc.base import ARRAY_TYPEID_MAP
+        from pypy.rpython.lltypesystem import lltype
+        hop.exception_cannot_occur()
+        return hop.genop('gc_dump_heap', [], resulttype=hop.r_result)
+
 def malloc_nonmovable(TP, n=None, zero=False):
     """ Allocate a non-moving buffer or return nullptr.
     When running directly, will pretend that gc is always

Modified: pypy/branch/gc-dump-heap/pypy/rpython/llinterp.py
==============================================================================
--- pypy/branch/gc-dump-heap/pypy/rpython/llinterp.py	(original)
+++ pypy/branch/gc-dump-heap/pypy/rpython/llinterp.py	Sun Oct 25 21:00:07 2009
@@ -824,8 +824,8 @@
     def op_gc_assume_young_pointers(self, addr):
         raise NotImplementedError
 
-    def op_gc_dump_heap(self, fd):
-        raise NotImplementedError # impossible
+    def op_gc_dump_heap(self):
+        raise NotImplementedError
 
     def op_gc_obtain_free_space(self, size):
         raise NotImplementedError

Modified: pypy/branch/gc-dump-heap/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/branch/gc-dump-heap/pypy/rpython/lltypesystem/lloperation.py	(original)
+++ pypy/branch/gc-dump-heap/pypy/rpython/lltypesystem/lloperation.py	Sun Oct 25 21:00:07 2009
@@ -422,6 +422,7 @@
     'extract_ushort':       LLOp(canfold=True),
     'combine_ushort':       LLOp(canfold=True),
     'gc_gettypeptr_group':  LLOp(canfold=True),
+    'get_member_index':     LLOp(canfold=True),
 
     # __________ used by the JIT ________
 

Modified: pypy/branch/gc-dump-heap/pypy/rpython/lltypesystem/opimpl.py
==============================================================================
--- pypy/branch/gc-dump-heap/pypy/rpython/lltypesystem/opimpl.py	(original)
+++ pypy/branch/gc-dump-heap/pypy/rpython/lltypesystem/opimpl.py	Sun Oct 25 21:00:07 2009
@@ -429,6 +429,11 @@
     return lltype.cast_pointer(TYPE, member)
 op_get_group_member.need_result_type = True
 
+def op_get_member_index(memberoffset):
+    from pypy.rpython.lltypesystem import llgroup
+    assert isinstance(memberoffset, llgroup.GroupMemberOffset)
+    return memberoffset.index
+
 def op_get_next_group_member(TYPE, grpptr, memberoffset, skipoffset):
     from pypy.rpython.lltypesystem import llgroup
     assert isinstance(memberoffset, llgroup.GroupMemberOffset)

Modified: pypy/branch/gc-dump-heap/pypy/rpython/memory/gc/base.py
==============================================================================
--- pypy/branch/gc-dump-heap/pypy/rpython/memory/gc/base.py	(original)
+++ pypy/branch/gc-dump-heap/pypy/rpython/memory/gc/base.py	Sun Oct 25 21:00:07 2009
@@ -6,6 +6,10 @@
 from pypy.rpython.memory.support import AddressDict
 from pypy.rpython.lltypesystem.llmemory import NULL, raw_malloc_usage
 
+TYPEID_MAP = lltype.Struct('TYPEID_MAP', ('count', lltype.Signed),
+                           ('links', lltype.Array(lltype.Signed)))
+ARRAY_TYPEID_MAP = lltype.Array(lltype.Ptr(TYPEID_MAP))
+
 class GCBase(object):
     _alloc_flavor_ = "raw"
     moving_gc = False

Modified: pypy/branch/gc-dump-heap/pypy/rpython/memory/gc/semispace.py
==============================================================================
--- pypy/branch/gc-dump-heap/pypy/rpython/memory/gc/semispace.py	(original)
+++ pypy/branch/gc-dump-heap/pypy/rpython/memory/gc/semispace.py	Sun Oct 25 21:00:07 2009
@@ -9,7 +9,8 @@
 from pypy.rlib.debug import ll_assert
 from pypy.rpython.lltypesystem.lloperation import llop
 from pypy.rlib.rarithmetic import ovfcheck
-from pypy.rpython.memory.gc.base import MovingGCBase
+from pypy.rpython.memory.gc.base import MovingGCBase, ARRAY_TYPEID_MAP,\
+     TYPEID_MAP
 
 import sys, os, time
 
@@ -24,9 +25,6 @@
 
 memoryError = MemoryError()
 
-ARRAY_OF_SIGNED = lltype.Array(lltype.Signed)
-
-
 class SemiSpaceGC(MovingGCBase):
     _alloc_flavor_ = "raw"
     inline_simple_malloc = True
@@ -639,24 +637,38 @@
             #
             return llmemory.cast_adr_to_int(obj)  # direct case
 
-    def _dump_heap_extraarg(self, addr, ignored):
+    def _dump_heap_extraarg(self, addr, parent):
+        parent_idx = llop.get_member_index(lltype.Signed,
+                                           self.get_type_id(parent))
+        idx = llop.get_member_index(lltype.Signed,
+                                    self.get_type_id(addr.address[0]))
+        self._ll_typeid_map[parent_idx].links[idx] += 1
         self._dump_heap(addr)
 
-    def _dump_heap(self, addr):
-        os.write(self._fd_dump, "X")
-        self.trace(addr, self._dump_heap_extraarg, None)
-
-    def dump_heap(self, fd):
-        ll_typeid_usage = lltype.nullptr(ARRAY_OF_SIGNED)
-        self._fd_dump = fd
-        try:
-            ll_typeid_usage = lltype.malloc(ARRAY_OF_SIGNED,
-                             self.root_walker.gcdata.max_type_id, flavor='raw')
-            self.root_walker.walk_roots(
-                SemiSpaceGC._dump_heap,  # stack roots
-                SemiSpaceGC._dump_heap,  # static in prebuilt non-gc structures
-                SemiSpaceGC._dump_heap)  # static in prebuilt gc objects
-        finally:
-            if ll_typeid_usage:
-                lltype.free(ll_typeid_usage, flavor='raw')
-            self._fd_dump = -1
+    def _dump_heap(self, root):
+        adr = root.address[0]
+        idx = llop.get_member_index(lltype.Signed, self.get_type_id(adr))
+        self._ll_typeid_map[idx].count += 1
+        self.trace(adr, self._dump_heap_extraarg, adr)
+
+    def dump_heap(self):
+        max_tid = self.root_walker.gcdata.max_type_id
+        ll_typeid_map = lltype.malloc(ARRAY_TYPEID_MAP, max_tid,
+                                        flavor='raw')
+        i = 0
+        while i < max_tid:
+            ll_typeid_map[i] = lltype.malloc(TYPEID_MAP, max_tid,
+                                             flavor='raw')
+            ll_typeid_map[i].count = 0
+            j = 0
+            while j < max_tid:
+                ll_typeid_map[i].links[j] = 0
+                j += 1
+            i += 1
+        self._ll_typeid_map = ll_typeid_map
+        self.root_walker.walk_roots(
+            SemiSpaceGC._dump_heap,  # stack roots
+            SemiSpaceGC._dump_heap,  # static in prebuilt non-gc structures
+            SemiSpaceGC._dump_heap)  # static in prebuilt gc objects
+        self._ll_typeid_map = lltype.nullptr(ARRAY_TYPEID_MAP)
+        return ll_typeid_map

Modified: pypy/branch/gc-dump-heap/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/branch/gc-dump-heap/pypy/rpython/memory/gctransform/framework.py	(original)
+++ pypy/branch/gc-dump-heap/pypy/rpython/memory/gctransform/framework.py	Sun Oct 25 21:00:07 2009
@@ -116,6 +116,7 @@
 
     def __init__(self, translator):
         from pypy.rpython.memory.gc.base import choose_gc_from_config
+        from pypy.rpython.memory.gc.base import ARRAY_TYPEID_MAP
         super(FrameworkGCTransformer, self).__init__(translator, inline=True)
         if hasattr(self, 'GC_PARAMS'):
             # for tests: the GC choice can be specified as class attributes
@@ -271,10 +272,8 @@
                 annmodel.s_None)
 
         if hasattr(GCClass, 'dump_heap'):
-            self.dump_heap_ptr = getfn(
-                GCClass.dump_heap.im_func,
-                [s_gc, annmodel.SomeInteger()],
-                annmodel.s_None)
+            self.dump_heap_ptr = getfn(GCClass.dump_heap.im_func,
+                    [s_gc], annmodel.SomePtr(lltype.Ptr(ARRAY_TYPEID_MAP)))
 
         # in some GCs we can inline the common case of
         # malloc_fixedsize(typeid, size, True, False, False)
@@ -647,9 +646,8 @@
 
     def gct_gc_dump_heap(self, hop):
         op = hop.spaceop
-        v_fd = op.args[0]
-        hop.genop("direct_call", [self.dump_heap_ptr,
-                                  self.c_const_gc, v_fd])
+        hop.genop("direct_call", [self.dump_heap_ptr, self.c_const_gc],
+                  resultvar=op.result)
 
     def gct_gc_adr_of_nursery_free(self, hop):
         if getattr(self.gcdata.gc, 'nursery_free', None) is None:

Modified: pypy/branch/gc-dump-heap/pypy/rpython/memory/test/test_gc.py
==============================================================================
--- pypy/branch/gc-dump-heap/pypy/rpython/memory/test/test_gc.py	(original)
+++ pypy/branch/gc-dump-heap/pypy/rpython/memory/test/test_gc.py	Sun Oct 25 21:00:07 2009
@@ -552,6 +552,27 @@
         assert res == 111
 
 
+    def test_gc_dump_heap(self):
+        if getattr(self.GCClass, 'dump_heap', None) is None:
+            py.test.skip("unsupported gc")
+        S = lltype.GcStruct('S', ('x', lltype.Signed))
+        
+        def fun(fd):
+            l = []
+            for i in range(10):
+                l.append(lltype.malloc(S))
+            rgc.dump_heap(fd)
+            keepalive_until_here(l)
+            return 0
+
+        from pypy.tool.udir import udir
+        f = udir.join("gcdump_direct.log")
+        handle = open(str(f), "w")
+        run = self.interpret(fun, [handle.fileno()])
+        handle.close()
+        assert f.read() == 'xxx'
+
+
 from pypy.rlib.objectmodel import UnboxedValue
 
 class TaggedBase(object):

Modified: pypy/branch/gc-dump-heap/pypy/rpython/memory/test/test_transformed_gc.py
==============================================================================
--- pypy/branch/gc-dump-heap/pypy/rpython/memory/test/test_transformed_gc.py	(original)
+++ pypy/branch/gc-dump-heap/pypy/rpython/memory/test/test_transformed_gc.py	Sun Oct 25 21:00:07 2009
@@ -13,6 +13,7 @@
 from pypy.rlib import rgc
 from pypy import conftest
 from pypy.rlib.rstring import StringBuilder
+from pypy.rlib.objectmodel import keepalive_until_here
 
 INT_SIZE = struct.calcsize("i")   # only for estimates
 
@@ -798,23 +799,34 @@
 
     def define_gc_dump_heap(cls):
         S = lltype.GcStruct('S', ('x', lltype.Signed))
+        l = []
         
-        def f(fd, ign):
-            l = []
+        def f():
             for i in range(10):
                 l.append(lltype.malloc(S))
-            rgc.dump_heap(fd)
-            return 0
+            # We cheat here and only read the table which we later on
+            # process ourselves, otherwise this test takes ages
+            tb = rgc._dump_heap()
+            a = 0
+            nr = 0
+            b = 0
+            c = 0
+            for i in range(len(tb)):
+                if tb[i].count == 10:
+                    a += 1
+                    nr = i
+            for i in range(len(tb)):
+                if tb[i].count == 1:
+                    b += 1
+                    c = tb[i].links[nr]
+            rgc._clear_dump_heap(tb)
+            return c * 100 + b * 10 + a
         return f
 
     def test_gc_dump_heap(self):
-        from pypy.tool.udir import udir
-        f = udir.join("gcdump.log")
-        handle = open(str(f), "w")
         run = self.runner("gc_dump_heap")
-        run([handle.fileno(), 0])
-        handle.close()
-        assert f.read() == 'xxx'
+        res = run([])
+        assert res == 1011
         
 # ________________________________________________________________
 



More information about the Pypy-commit mailing list