[pypy-svn] r69113 - in pypy/trunk/pypy: doc/jit module/gc module/gc/test rlib rpython rpython/lltypesystem rpython/memory rpython/memory/gc rpython/memory/gctransform rpython/memory/test tool translator/c/test

arigo at codespeak.net arigo at codespeak.net
Tue Nov 10 13:46:25 CET 2009


Author: arigo
Date: Tue Nov 10 13:46:24 2009
New Revision: 69113

Added:
   pypy/trunk/pypy/tool/gcdump.py
      - copied unchanged from r69112, pypy/branch/gc-dump-heap/pypy/tool/gcdump.py
Modified:
   pypy/trunk/pypy/doc/jit/pyjitpl5.txt
   pypy/trunk/pypy/module/gc/__init__.py
   pypy/trunk/pypy/module/gc/interp_gc.py
   pypy/trunk/pypy/module/gc/test/test_gc.py
   pypy/trunk/pypy/rlib/rgc.py
   pypy/trunk/pypy/rpython/llinterp.py
   pypy/trunk/pypy/rpython/lltypesystem/lloperation.py
   pypy/trunk/pypy/rpython/lltypesystem/opimpl.py
   pypy/trunk/pypy/rpython/memory/gc/base.py
   pypy/trunk/pypy/rpython/memory/gc/generation.py
   pypy/trunk/pypy/rpython/memory/gc/semispace.py
   pypy/trunk/pypy/rpython/memory/gctransform/framework.py
   pypy/trunk/pypy/rpython/memory/gctransform/transform.py
   pypy/trunk/pypy/rpython/memory/gctypelayout.py
   pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py
   pypy/trunk/pypy/translator/c/test/test_boehm.py
   pypy/trunk/pypy/translator/c/test/test_newgc.py
Log:
Merge the branch 'gc-dump-heap', adding rgc._heap_stats() that
forces a dump of stats about object usage, classified per type id.


Modified: pypy/trunk/pypy/doc/jit/pyjitpl5.txt
==============================================================================
--- pypy/trunk/pypy/doc/jit/pyjitpl5.txt	(original)
+++ pypy/trunk/pypy/doc/jit/pyjitpl5.txt	Tue Nov 10 13:46:24 2009
@@ -32,6 +32,7 @@
 longer suitable.  can_enter_jit goes at the end of a application level loop.  In
 the Python interpreter, this is the JUMP_ABSOLUTE bytecode.  The Python
 interpreter defines its hints in pypy/module/pypyjit/interp_jit.py.
+XXX by overloading default frame behavior from pyframe
 
 The interpreter wishing to use the PyPy's JIT must define a list of *green*
 variables and a list of *red* variables.  The *green* variables are loop
@@ -98,6 +99,8 @@
 contain values that may change during the running of a loop.  There are three
 kinds of normal boxes: BoxInt, BoxPtr, and BoxFloat, and four kinds of constant
 boxes: ConstInt, ConstPtr, ConstFloat, and ConstAddr.
+XXX ConstAddr is only a hack for translation not to translate pointers,
+XXX nothing more
 
 The meta-interpreter starts interpreting the JIT bytecode.  Each operation is
 executed and then recorded in a list of operations, called the trace.

Modified: pypy/trunk/pypy/module/gc/__init__.py
==============================================================================
--- pypy/trunk/pypy/module/gc/__init__.py	(original)
+++ pypy/trunk/pypy/module/gc/__init__.py	Tue Nov 10 13:46:24 2009
@@ -12,4 +12,5 @@
         'disable_finalizers': 'interp_gc.disable_finalizers',
         'estimate_heap_size': 'interp_gc.estimate_heap_size',
         'garbage' : 'space.newlist([])',
+        'dump_heap_stats': 'interp_gc.dump_heap_stats',
     }

Modified: pypy/trunk/pypy/module/gc/interp_gc.py
==============================================================================
--- pypy/trunk/pypy/module/gc/interp_gc.py	(original)
+++ pypy/trunk/pypy/module/gc/interp_gc.py	Tue Nov 10 13:46:24 2009
@@ -1,6 +1,7 @@
 from pypy.interpreter.gateway import ObjSpace
 from pypy.interpreter.error import OperationError
 from pypy.rlib import rgc
+from pypy.rlib.streamio import open_file_as_stream
 
 def collect(space):
     "Run a full collection."
@@ -52,3 +53,15 @@
     raise OperationError(space.w_RuntimeError,
                          space.wrap("can't estimate the heap size"))
 estimate_heap_size.unwrap_spec = [ObjSpace]
+
+def dump_heap_stats(space, filename):
+    tb = rgc._heap_stats()
+    if not tb:
+        raise OperationError(space.w_RuntimeError,
+                             space.wrap("Wrong GC"))
+    f = open_file_as_stream(filename, mode="w")
+    for i in range(len(tb)):
+        f.write("%d %d " % (tb[i].count, tb[i].size))
+        f.write(",".join([str(tb[i].links[j]) for j in range(len(tb))]) + "\n")
+    f.close()
+dump_heap_stats.unwrap_spec = [ObjSpace, str]

Modified: pypy/trunk/pypy/module/gc/test/test_gc.py
==============================================================================
--- pypy/trunk/pypy/module/gc/test/test_gc.py	(original)
+++ pypy/trunk/pypy/module/gc/test/test_gc.py	Tue Nov 10 13:46:24 2009
@@ -1,3 +1,5 @@
+from pypy.conftest import gettestobjspace
+
 class AppTestGC(object):
     def test_collect(self):
         import gc
@@ -72,4 +74,35 @@
         assert gc.isenabled()
         gc.enable()
         assert gc.isenabled()
+
+class AppTestGcDumpHeap(object):
+    def setup_class(cls):
+        from pypy.tool.udir import udir
+        from pypy.rlib import rgc
+        class X(object):
+            def __init__(self, count, size, links):
+                self.count = count
+                self.size = size
+                self.links = links
+        
+        def fake_heap_stats():
+            return [X(1, 12, [0, 0]), X(2, 10, [10, 0])]
         
+        cls._heap_stats = rgc._heap_stats
+        rgc._heap_stats = fake_heap_stats
+        fname = udir.join('gcdump.log')
+        cls.space = gettestobjspace()
+        cls.w_fname = cls.space.wrap(str(fname))
+        cls._fname = fname
+
+    def teardown_class(cls):
+        import py
+        from pypy.rlib import rgc
+        
+        rgc._heap_stats = cls._heap_stats
+        assert py.path.local(cls._fname).read() == '1 12 0,0\n2 10 10,0\n'
+    
+    def test_gc_heap_stats(self):
+        import gc
+        gc.dump_heap_stats(self.fname)
+

Modified: pypy/trunk/pypy/rlib/rgc.py
==============================================================================
--- pypy/trunk/pypy/rlib/rgc.py	(original)
+++ pypy/trunk/pypy/rlib/rgc.py	Tue Nov 10 13:46:24 2009
@@ -184,6 +184,25 @@
         hop.exception_cannot_occur()
         return hop.genop('gc_can_move', hop.args_v, resulttype=hop.r_result)
 
+def _heap_stats():
+    raise NotImplementedError # can't be run directly
+
+class DumpHeapEntry(ExtRegistryEntry):
+    _about_ = _heap_stats
+
+    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_is_here()
+        return hop.genop('gc_heap_stats', [], 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/trunk/pypy/rpython/llinterp.py
==============================================================================
--- pypy/trunk/pypy/rpython/llinterp.py	(original)
+++ pypy/trunk/pypy/rpython/llinterp.py	Tue Nov 10 13:46:24 2009
@@ -810,6 +810,9 @@
     def op_gc_assume_young_pointers(self, addr):
         raise NotImplementedError
 
+    def op_gc_heap_stats(self):
+        raise NotImplementedError
+
     def op_gc_obtain_free_space(self, size):
         raise NotImplementedError
 

Modified: pypy/trunk/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/lloperation.py	(original)
+++ pypy/trunk/pypy/rpython/lltypesystem/lloperation.py	Tue Nov 10 13:46:24 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 ________
 
@@ -460,6 +461,7 @@
     'gc_thread_run'       : LLOp(),
     'gc_thread_die'       : LLOp(),
     'gc_assume_young_pointers': LLOp(),
+    'gc_heap_stats'       : LLOp(canunwindgc=True),
 
     # ------- JIT & GC interaction, only for some GCs ----------
     

Modified: pypy/trunk/pypy/rpython/lltypesystem/opimpl.py
==============================================================================
--- pypy/trunk/pypy/rpython/lltypesystem/opimpl.py	(original)
+++ pypy/trunk/pypy/rpython/lltypesystem/opimpl.py	Tue Nov 10 13:46:24 2009
@@ -483,6 +483,9 @@
     return op_get_next_group_member(TYPE, grpptr, typeid, skipoffset)
 op_gc_gettypeptr_group.need_result_type = True
 
+def op_get_member_index(memberoffset):
+    raise NotImplementedError
+
 # ____________________________________________________________
 
 def get_op_impl(opname):

Modified: pypy/trunk/pypy/rpython/memory/gc/base.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gc/base.py	(original)
+++ pypy/trunk/pypy/rpython/memory/gc/base.py	Tue Nov 10 13:46:24 2009
@@ -6,6 +6,11 @@
 from pypy.rpython.memory.support import AddressDict
 from pypy.rpython.lltypesystem.llmemory import NULL, raw_malloc_usage
 
+TYPEID_MAP = lltype.GcStruct('TYPEID_MAP', ('count', lltype.Signed),
+                             ('size', lltype.Signed),
+                             ('links', lltype.Array(lltype.Signed)))
+ARRAY_TYPEID_MAP = lltype.GcArray(lltype.Ptr(TYPEID_MAP))
+
 class GCBase(object):
     _alloc_flavor_ = "raw"
     moving_gc = False
@@ -48,7 +53,8 @@
                             varsize_offset_to_variable_part,
                             varsize_offset_to_length,
                             varsize_offsets_to_gcpointers_in_var_part,
-                            weakpointer_offset):
+                            weakpointer_offset,
+                            member_index):
         self.getfinalizer = getfinalizer
         self.is_varsize = is_varsize
         self.has_gcptr_in_varsize = has_gcptr_in_varsize
@@ -60,6 +66,10 @@
         self.varsize_offset_to_length = varsize_offset_to_length
         self.varsize_offsets_to_gcpointers_in_var_part = varsize_offsets_to_gcpointers_in_var_part
         self.weakpointer_offset = weakpointer_offset
+        self.member_index = member_index
+
+    def get_member_index(self, type_id):
+        return self.member_index(type_id)
 
     def set_root_walker(self, root_walker):
         self.root_walker = root_walker

Modified: pypy/trunk/pypy/rpython/memory/gc/generation.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gc/generation.py	(original)
+++ pypy/trunk/pypy/rpython/memory/gc/generation.py	Tue Nov 10 13:46:24 2009
@@ -511,6 +511,17 @@
     def _id_grow_older(self, obj, id, ignored):
         self.objects_with_id.setitem(obj, id)
 
+    def heap_stats_walk_roots(self):
+        self.last_generation_root_objects.foreach(
+            self._track_heap_ext, None)
+        self.root_walker.walk_roots(
+            SemiSpaceGC._track_heap_root,
+            SemiSpaceGC._track_heap_root,
+            SemiSpaceGC._track_heap_root)
+
+    def _track_heap_ext(self, adr, ignored):
+        self.trace(adr, self.track_heap_parent, adr)
+
     def debug_check_object(self, obj):
         """Check the invariants about 'obj' that should be true
         between collections."""
@@ -564,6 +575,7 @@
         else:
             SemiSpaceGC.debug_check_can_copy(self, obj)
 
+
 # ____________________________________________________________
 
 import os

Modified: pypy/trunk/pypy/rpython/memory/gc/semispace.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gc/semispace.py	(original)
+++ pypy/trunk/pypy/rpython/memory/gc/semispace.py	Tue Nov 10 13:46:24 2009
@@ -10,7 +10,8 @@
 from pypy.rlib.debug import debug_print, debug_start, debug_stop
 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
 
@@ -25,7 +26,6 @@
 
 memoryError = MemoryError()
 
-
 class SemiSpaceGC(MovingGCBase):
     _alloc_flavor_ = "raw"
     inline_simple_malloc = True
@@ -623,3 +623,47 @@
                 hdr.tid |= GCFLAG_HASHTAKEN
             #
             return llmemory.cast_adr_to_int(obj)  # direct case
+
+    def track_heap_parent(self, obj, parent):
+        addr = obj.address[0]
+        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))
+        self._ll_typeid_map[parent_idx].links[idx] += 1
+        self.track_heap(addr)
+
+    def track_heap(self, adr):
+        if self._tracked_dict.contains(adr):
+            return
+        self._tracked_dict.add(adr)
+        idx = llop.get_member_index(lltype.Signed, self.get_type_id(adr))
+        self._ll_typeid_map[idx].count += 1
+        totsize = self.get_size(adr) + self.size_gc_header()
+        self._ll_typeid_map[idx].size += llmemory.raw_malloc_usage(totsize)
+        self.trace(adr, self.track_heap_parent, adr)
+
+    def _track_heap_root(self, root):
+        self.track_heap(root.address[0])
+
+    def heap_stats_walk_roots(self):
+        self.root_walker.walk_roots(
+            SemiSpaceGC._track_heap_root,
+            SemiSpaceGC._track_heap_root,
+            SemiSpaceGC._track_heap_root)
+        
+    def heap_stats(self):
+        self._tracked_dict = self.AddressDict()
+        max_tid = self.root_walker.gcdata.max_type_id
+        ll_typeid_map = lltype.malloc(ARRAY_TYPEID_MAP, max_tid, zero=True)
+        for i in range(max_tid):
+            ll_typeid_map[i] = lltype.malloc(TYPEID_MAP, max_tid, zero=True)
+        self._ll_typeid_map = ll_typeid_map
+        self._tracked_dict.add(llmemory.cast_ptr_to_adr(ll_typeid_map))
+        i = 0
+        while i < max_tid:
+            self._tracked_dict.add(llmemory.cast_ptr_to_adr(ll_typeid_map[i]))
+            i += 1
+        self.heap_stats_walk_roots()
+        self._ll_typeid_map = lltype.nullptr(ARRAY_TYPEID_MAP)
+        self._tracked_dict.delete()
+        return ll_typeid_map

Modified: pypy/trunk/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gctransform/framework.py	(original)
+++ pypy/trunk/pypy/rpython/memory/gctransform/framework.py	Tue Nov 10 13:46:24 2009
@@ -24,7 +24,6 @@
 
 TYPE_ID = rffi.USHORT
 
-
 class CollectAnalyzer(graphanalyze.BoolGraphAnalyzer):
 
     def analyze_direct_call(self, graph, seen=None):
@@ -117,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
@@ -147,6 +147,7 @@
         gcdata.static_root_start = a_random_address      # patched in finish()
         gcdata.static_root_nongcend = a_random_address   # patched in finish()
         gcdata.static_root_end = a_random_address        # patched in finish()
+        gcdata.max_type_id = 13                          # patched in finish()
         self.gcdata = gcdata
         self.malloc_fnptr_cache = {}
 
@@ -183,6 +184,9 @@
         data_classdef.generalize_attr(
             'static_root_end',
             annmodel.SomeAddress())
+        data_classdef.generalize_attr(
+            'max_type_id',
+            annmodel.SomeInteger())
 
         annhelper = annlowlevel.MixLevelHelperAnnotator(self.translator.rtyper)
 
@@ -262,6 +266,15 @@
                 [s_gc, annmodel.SomeAddress()],
                 annmodel.s_None)
 
+        if hasattr(GCClass, 'heap_stats'):
+            self.heap_stats_ptr = getfn(GCClass.heap_stats.im_func,
+                    [s_gc], annmodel.SomePtr(lltype.Ptr(ARRAY_TYPEID_MAP)),
+                    minimal_transform=False)
+            self.get_member_index_ptr = getfn(
+                GCClass.get_member_index.im_func,
+                [s_gc, annmodel.SomeInteger(knowntype=rffi.r_ushort)],
+                annmodel.SomeInteger())
+
         # in some GCs we can inline the common case of
         # malloc_fixedsize(typeid, size, True, False, False)
         if getattr(GCClass, 'inline_simple_malloc', False):
@@ -492,14 +505,15 @@
         ll_static_roots_inside = lltype.malloc(lltype.Array(llmemory.Address),
                                                len(addresses_of_static_ptrs),
                                                immortal=True)
+
         for i in range(len(addresses_of_static_ptrs)):
             ll_static_roots_inside[i] = addresses_of_static_ptrs[i]
         ll_instance.inst_static_root_start = llmemory.cast_ptr_to_adr(ll_static_roots_inside) + llmemory.ArrayItemsOffset(lltype.Array(llmemory.Address))
         ll_instance.inst_static_root_nongcend = ll_instance.inst_static_root_start + llmemory.sizeof(llmemory.Address) * len(self.layoutbuilder.addresses_of_static_ptrs_in_nongc)
         ll_instance.inst_static_root_end = ll_instance.inst_static_root_start + llmemory.sizeof(llmemory.Address) * len(addresses_of_static_ptrs)
-
         newgcdependencies = []
         newgcdependencies.append(ll_static_roots_inside)
+        ll_instance.inst_max_type_id = len(group.members)
         self.write_typeid_list()
         return newgcdependencies
 
@@ -634,6 +648,21 @@
         hop.genop("direct_call", [self.assume_young_pointers_ptr,
                                   self.c_const_gc, v_addr])
 
+    def gct_gc_heap_stats(self, hop):
+        if not hasattr(self, 'heap_stats_ptr'):
+            return GCTransformer.gct_gc_heap_stats(self, hop)
+        op = hop.spaceop
+        livevars = self.push_roots(hop)
+        hop.genop("direct_call", [self.heap_stats_ptr, self.c_const_gc],
+                  resultvar=op.result)
+        self.pop_roots(hop, livevars)
+
+    def gct_get_member_index(self, hop):
+        op = hop.spaceop
+        v_typeid = op.args[0]
+        hop.genop("direct_call", [self.get_member_index_ptr, self.c_const_gc,
+                                  v_typeid], resultvar=op.result)
+
     def gct_gc_adr_of_nursery_free(self, hop):
         if getattr(self.gcdata.gc, 'nursery_free', None) is None:
             raise NotImplementedError("gc_adr_of_nursery_free only for generational gcs")

Modified: pypy/trunk/pypy/rpython/memory/gctransform/transform.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gctransform/transform.py	(original)
+++ pypy/trunk/pypy/rpython/memory/gctransform/transform.py	Tue Nov 10 13:46:24 2009
@@ -388,6 +388,11 @@
         # this assumes a non-moving GC.  Moving GCs need to override this
         hop.rename('cast_ptr_to_int')
 
+    def gct_gc_heap_stats(self, hop):
+        from pypy.rpython.memory.gc.base import ARRAY_TYPEID_MAP
+        
+        return hop.cast_result(rmodel.inputconst(lltype.Ptr(ARRAY_TYPEID_MAP),
+                                        lltype.nullptr(ARRAY_TYPEID_MAP)))
 
 class MinimalGCTransformer(BaseGCTransformer):
     def __init__(self, parenttransformer):

Modified: pypy/trunk/pypy/rpython/memory/gctypelayout.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/gctypelayout.py	(original)
+++ pypy/trunk/pypy/rpython/memory/gctypelayout.py	Tue Nov 10 13:46:24 2009
@@ -93,6 +93,10 @@
             return weakptr_offset
         return -1
 
+    def q_member_index(self, typeid):
+        infobits = self.get(typeid).infobits
+        return infobits & T_MEMBER_INDEX
+
     def set_query_functions(self, gc):
         gc.set_query_functions(
             self.q_is_varsize,
@@ -105,23 +109,26 @@
             self.q_varsize_offset_to_variable_part,
             self.q_varsize_offset_to_length,
             self.q_varsize_offsets_to_gcpointers_in_var_part,
-            self.q_weakpointer_offset)
+            self.q_weakpointer_offset,
+            self.q_member_index)
 
 
-T_IS_VARSIZE           = 0x01
-T_HAS_GCPTR_IN_VARSIZE = 0x02
-T_IS_GCARRAY_OF_GCPTR  = 0x04
-T_IS_WEAKREF           = 0x08
+# the lowest 16bits are used to store group member index
+T_MEMBER_INDEX         = 0xffff
+T_IS_VARSIZE           = 0x10000
+T_HAS_GCPTR_IN_VARSIZE = 0x20000
+T_IS_GCARRAY_OF_GCPTR  = 0x40000
+T_IS_WEAKREF           = 0x80000
 
 def _check_typeid(typeid):
     ll_assert(llop.is_group_member_nonzero(lltype.Bool, typeid),
               "invalid type_id")
 
 
-def encode_type_shape(builder, info, TYPE):
+def encode_type_shape(builder, info, TYPE, index):
     """Encode the shape of the TYPE into the TYPE_INFO structure 'info'."""
     offsets = offsets_to_gc_pointers(TYPE)
-    infobits = 0
+    infobits = index
     info.ofstoptrs = builder.offsets2table(offsets, TYPE)
     info.finalizer = builder.make_finalizer_funcptr_for_type(TYPE)
     if not TYPE._is_varsize():
@@ -212,12 +219,12 @@
                 fullinfo = lltype.malloc(GCData.VARSIZE_TYPE_INFO,
                                          immortal=True, zero=True)
                 info = fullinfo.header
+            type_id = self.type_info_group.add_member(fullinfo)
             if self.can_encode_type_shape:
-                encode_type_shape(self, info, TYPE)
+                encode_type_shape(self, info, TYPE, type_id.index)
             else:
-                self._pending_type_shapes.append((info, TYPE))
+                self._pending_type_shapes.append((info, TYPE, type_id.index))
             # store it
-            type_id = self.type_info_group.add_member(fullinfo)
             self.id_of_type[TYPE] = type_id
             self.add_vtable_after_typeinfo(TYPE)
             return type_id
@@ -257,8 +264,8 @@
     def encode_type_shapes_now(self):
         if not self.can_encode_type_shape:
             self.can_encode_type_shape = True
-            for info, TYPE in self._pending_type_shapes:
-                encode_type_shape(self, info, TYPE)
+            for info, TYPE, index in self._pending_type_shapes:
+                encode_type_shape(self, info, TYPE, index)
             del self._pending_type_shapes
 
     def delay_encoding(self):

Modified: pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py
==============================================================================
--- pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py	(original)
+++ pypy/trunk/pypy/rpython/memory/test/test_transformed_gc.py	Tue Nov 10 13:46:24 2009
@@ -4,7 +4,7 @@
 from pypy.translator.c import gc
 from pypy.annotation import model as annmodel
 from pypy.annotation import policy as annpolicy
-from pypy.rpython.lltypesystem import lltype, llmemory, llarena
+from pypy.rpython.lltypesystem import lltype, llmemory, llarena, rffi
 from pypy.rpython.memory.gctransform import framework
 from pypy.rpython.lltypesystem.lloperation import llop, void
 from pypy.rpython.memory.gc.marksweep import X_CLONE, X_POOL, X_POOL_PTR
@@ -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
 
@@ -794,6 +795,55 @@
         run = self.runner("do_malloc_operations_in_call")
         run([])
 
+    def define_gc_heap_stats(cls):
+        S = lltype.GcStruct('S', ('x', lltype.Signed))
+        l1 = []
+        l2 = []
+        l3 = []
+        l4 = []
+        
+        def f():
+            for i in range(10):
+                s = lltype.malloc(S)
+                l1.append(s)
+                l2.append(s)
+                if i < 3:
+                    l3.append(s)
+                    l4.append(s)
+            # We cheat here and only read the table which we later on
+            # process ourselves, otherwise this test takes ages
+            llop.gc__collect(lltype.Void)
+            tb = rgc._heap_stats()
+            a = 0
+            nr = 0
+            b = 0
+            c = 0
+            d = 0
+            e = 0
+            for i in range(len(tb)):
+                if tb[i].count == 10:
+                    a += 1
+                    nr = i
+                if tb[i].count > 50:
+                    d += 1
+            for i in range(len(tb)):
+                if tb[i].count == 4:
+                    b += 1
+                    c += tb[i].links[nr]
+                    e += tb[i].size
+            return d * 1000 + c * 100 + b * 10 + a
+        return f
+
+    def test_gc_heap_stats(self):
+        run = self.runner("gc_heap_stats")
+        res = run([])
+        assert res % 10000 == 2611
+        totsize = (res / 10000)
+        size_of_int = rffi.sizeof(lltype.Signed)
+        assert (totsize - 26 * size_of_int) % 4 == 0
+        # ^^^ a crude assumption that totsize - varsize would be dividable by 4
+        #     (and give fixedsize)
+        
 # ________________________________________________________________
 
 class TestMarkSweepGC(GenericGCTests):

Modified: pypy/trunk/pypy/translator/c/test/test_boehm.py
==============================================================================
--- pypy/trunk/pypy/translator/c/test/test_boehm.py	(original)
+++ pypy/trunk/pypy/translator/c/test/test_boehm.py	Tue Nov 10 13:46:24 2009
@@ -380,6 +380,15 @@
         c_fn = self.getcompiled(fn, [])
         assert c_fn() == False
 
+    def test_heap_stats(self):
+        from pypy.rlib import rgc
+        
+        def fn():
+            return bool(rgc._heap_stats())
+
+        c_fn = self.getcompiled(fn, [])
+        assert not c_fn()
+
     def test_malloc_nonmovable(self):
         TP = lltype.GcArray(lltype.Char)
         def func():

Modified: pypy/trunk/pypy/translator/c/test/test_newgc.py
==============================================================================
--- pypy/trunk/pypy/translator/c/test/test_newgc.py	(original)
+++ pypy/trunk/pypy/translator/c/test/test_newgc.py	Tue Nov 10 13:46:24 2009
@@ -898,7 +898,41 @@
     def test_gc_set_max_heap_size(self):
         res = self.run('gc_set_max_heap_size')
         assert res == 2
+
+    def define_gc_heap_stats(cls):
+        S = lltype.GcStruct('S', ('x', lltype.Signed))
+        l1 = []
+        l2 = []
+        l3 = []
         
+        def f():
+            for i in range(10):
+                s = lltype.malloc(S)
+                l1.append(s)
+                l2.append(s)
+                l3.append(s)
+            tb = rgc._heap_stats()
+            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 == 3:
+                    b += 1
+                    c += tb[i].links[nr]
+            # we don't count b here since there can be more singletons,
+            # important one is c, a is for check
+            return c * 100 + b * 10 + a
+        return f
+
+    def test_gc_heap_stats(self):
+        res = self.run("gc_heap_stats")
+        assert res == 3011
+
     def definestr_string_builder(cls):
         def fn(_):
             s = StringBuilder()



More information about the Pypy-commit mailing list