[pypy-commit] pypy statistics-maps: add some code to print statistics about maps
cfbolz
pypy.commits at gmail.com
Tue Feb 9 03:30:30 EST 2016
Author: Carl Friedrich Bolz <cfbolz at gmx.de>
Branch: statistics-maps
Changeset: r82121:8b18aadfc032
Date: 2016-02-09 09:18 +0100
http://bitbucket.org/pypy/pypy/changeset/8b18aadfc032/
Log: add some code to print statistics about maps
diff --git a/pypy/bin/pyinteractive.py b/pypy/bin/pyinteractive.py
--- a/pypy/bin/pyinteractive.py
+++ b/pypy/bin/pyinteractive.py
@@ -192,6 +192,8 @@
exit_status = 0
finally:
def doit():
+ from pypy.objspace.std.mapdict import _print_stats
+ _print_stats(space)
space.finish()
main.run_toplevel(space, doit, verbose=interactiveconfig.verbose)
diff --git a/pypy/goal/targetpypystandalone.py b/pypy/goal/targetpypystandalone.py
--- a/pypy/goal/targetpypystandalone.py
+++ b/pypy/goal/targetpypystandalone.py
@@ -69,6 +69,8 @@
debug(" operror-value: " + space.str_w(space.str(e.get_w_value(space))))
return 1
finally:
+ from pypy.objspace.std.mapdict import _print_stats
+ _print_stats(space)
try:
space.finish()
except OperationError, e:
diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py
--- a/pypy/objspace/std/mapdict.py
+++ b/pypy/objspace/std/mapdict.py
@@ -1,4 +1,4 @@
-import weakref
+import weakref, os
from rpython.rlib import jit, objectmodel, debug, rerased
from rpython.rlib.rarithmetic import intmask, r_uint
@@ -22,15 +22,110 @@
# note: we use "x * NUM_DIGITS_POW2" instead of "x << NUM_DIGITS" because
# we want to propagate knowledge that the result cannot be negative
+class All(object):
+ def __init__(self):
+ self.all = []
+
+ at objectmodel.specialize.argtype(1)
+def _print_line(key, value, indent=0):
+ from pypy.objspace.std.bytesobject import string_escape_encode
+ if isinstance(value, int):
+ value = str(value)
+ else:
+ value = string_escape_encode(str(value), '"')
+ return "%s%s: %s," % (" " * (indent * 4), string_escape_encode(key, '"'), value)
+
+def _print_stats(space):
+ fn = space.bytes_w(space.getitem(space.getattr(space.sys, space.wrap('argv')), space.wrap(0)))
+ if fn.endswith(".py"):
+ end = len(fn) - len('.py')
+ assert end >= 0
+ fn = fn[:end]
+ elif fn.endswith(".pyc"):
+ end = len(fn) - len('.pyc')
+ assert end >= 0
+ fn = fn[:end]
+ if "/" in fn:
+ index = fn.rfind("/")
+ assert index >= 0
+ fn = fn[index+1:]
+ f = file("mapstats-%s-%s.txt" % (fn, os.getpid(), ), "w")
+ try:
+ f.write("[\n")
+ for map in AbstractAttribute._all_maps.all:
+ map.print_counts(f)
+ f.write("]\n")
+ finally:
+ f.close()
+
class AbstractAttribute(object):
_immutable_fields_ = ['terminator']
cache_attrs = None
_size_estimate = 0
+ _number_instantiated = 0
+ _number_unnecessary_writes = 0
+ _number_writes = None
+ _number_reads = None
+ _number_transitions = None
+ _all_maps = All()
def __init__(self, space, terminator):
self.space = space
assert isinstance(terminator, Terminator)
self.terminator = terminator
+ self._number_reads = {}
+ self._number_writes = {}
+ self._number_transitions = {}
+ self._all_maps.all.append(self)
+
+ def _count_read(self, name, index):
+ key = (name, index)
+ self._number_reads[key] = self._number_reads.get(key, 0) + 1
+
+ def _count_write(self, name, index, w_value):
+ key = (name, index, w_value.__class__.__name__)
+ self._number_writes[key] = self._number_writes.get(key, 0) + 1
+
+ def _count_transition(self, key):
+ self._number_transitions[key] = self._number_transitions.get(key, 0) + 1
+
+ def print_counts(self, f):
+ lines = ["{"]
+ lines.append(_print_line('type', self.__class__.__name__, 1))
+ lines.append(_print_line('id', str(objectmodel.compute_unique_id(self)), 1))
+ lines.append(_print_line('instances', self._number_instantiated, 1))
+ if isinstance(self, PlainAttribute):
+ lines.append(_print_line('back', str(objectmodel.compute_unique_id(self.back)), 1))
+ lines.append(_print_line('name', self.name, 1))
+ lines.append(_print_line('index', self.index, 1))
+ lines.append(_print_line('ever_mutated', self.ever_mutated, 1))
+ lines.append(_print_line('can_contain_mutable_cell', self.can_contain_mutable_cell, 1))
+ lines.append(_print_line('number_unnecessary_writes', self._number_unnecessary_writes, 1))
+ lines.append(_print_line('_hprof_status', str(self._hprof_status), 1))
+ if self.class_is_known():
+ lines.append(_print_line('_hprof_const_cls', self.read_constant_cls().__name__, 1))
+ elif isinstance(self, Terminator):
+ if self.w_cls is not None:
+ lines.append(_print_line('w_cls', self.w_cls.name, 1))
+ if self._number_reads:
+ lines.append(' "reads": {')
+ for key, value in self._number_reads.items():
+ lines.append(_print_line(str(key), value, 2))
+ lines.append(" },")
+ if self._number_writes:
+ lines.append(' "writes": {')
+ for key, value in self._number_writes.items():
+ lines.append(_print_line(str(key), value, 2))
+ lines.append(" },")
+ if self._number_transitions:
+ lines.append(' "transitions": {')
+ for key, value in self._number_transitions.items():
+ lines.append(_print_line(str(objectmodel.compute_unique_id(key)), value, 2))
+ lines.append(" },")
+ lines.append("},")
+ lines.append("")
+ lines.append("")
+ f.write("\n".join(lines))
def read(self, obj, name, index):
from pypy.objspace.std.intobject import W_IntObject
@@ -38,6 +133,7 @@
attr = self.find_map_attr(name, index)
if attr is None:
return self.terminator._read_terminator(obj, name, index)
+ attr._count_read(name, index)
# XXX move to PlainAttribute?
if jit.we_are_jitted():
if attr.can_fold_read_int():
@@ -74,11 +170,13 @@
attr = self.find_map_attr(name, index)
if attr is None:
return self.terminator._write_terminator(obj, name, index, w_value)
+ attr._count_write(name, index, w_value)
# if the write is not necessary, the storage is already filled from the
# time we did the map transition. Therefore, if the value profiler says
# so, we can not do the write
write_necessary = attr.write_necessary(w_value)
if not write_necessary:
+ self._number_unnecessary_writes += 1
return True
if not attr.ever_mutated:
attr.ever_mutated = True
@@ -206,6 +304,7 @@
def add_attr(self, obj, name, index, w_value):
# grumble, jit needs this
attr = self._get_new_attr(name, index)
+ attr._count_write(name, index, w_value)
oldattr = obj._get_mapdict_map()
if not jit.we_are_jitted():
size_est = (oldattr._size_estimate + attr.size_estimate()
@@ -501,18 +600,24 @@
def _get_mapdict_map(self):
return jit.promote(self.map)
def _set_mapdict_map(self, map):
+ old = self.map
+ if old is not map and map:
+ old._count_transition(map)
self.map = map
# _____________________________________________
# objspace interface
def getdictvalue(self, space, attrname):
- return self._get_mapdict_map().read(self, attrname, DICT)
+ map = self._get_mapdict_map()
+ return map.read(self, attrname, DICT)
def setdictvalue(self, space, attrname, w_value):
- return self._get_mapdict_map().write(self, attrname, DICT, w_value)
+ map = self._get_mapdict_map()
+ return map.write(self, attrname, DICT, w_value)
def deldictvalue(self, space, attrname):
- new_obj = self._get_mapdict_map().delete(self, attrname, DICT)
+ map = self._get_mapdict_map()
+ new_obj = map.delete(self, attrname, DICT)
if new_obj is None:
return False
self._become(new_obj)
@@ -558,6 +663,7 @@
self.space = space
assert (not self.typedef.hasdict or
self.typedef is W_InstanceObject.typedef)
+ w_subtype.terminator._number_instantiated += 1
self._init_empty(w_subtype.terminator)
def getslotvalue(self, slotindex):
@@ -615,7 +721,7 @@
return len(self.storage)
def _set_mapdict_storage_and_map(self, storage, map):
self.storage = storage
- self.map = map
+ self._set_mapdict_map(map)
class Object(ObjectMixin, BaseMapdictObject, W_Root):
pass # mainly for tests
@@ -705,7 +811,7 @@
return n
def _set_mapdict_storage_and_map(self, storage, map):
- self.map = map
+ self._set_mapdict_map(map)
len_storage = len(storage)
for i in rangenmin1:
if i < len_storage:
@@ -980,7 +1086,7 @@
# used if we_are_jitted().
entry = pycode._mapdict_caches[nameindex]
map = w_obj._get_mapdict_map()
- if entry.is_valid_for_map(map) and entry.w_method is None:
+ if False: #entry.is_valid_for_map(map) and entry.w_method is None:
# everything matches, it's incredibly fast
return unwrap_cell(
map.space, w_obj._mapdict_read_storage(entry.storageindex))
@@ -1026,6 +1132,7 @@
if index != INVALID:
attr = map.find_map_attr(attrname, index)
if attr is not None:
+ attr._count_read(attrname, index)
# Note that if map.terminator is a DevolvedDictTerminator,
# map.find_map_attr will always return None if index==DICT.
_fill_cache(pycode, nameindex, map, version_tag, attr.storageindex)
More information about the pypy-commit
mailing list