[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