Author: Anton Gulenko <[email protected]>
Branch: storage
Changeset: r715:0c8b9379f9d5
Date: 2014-03-28 14:01 +0100
http://bitbucket.org/pypy/lang-smalltalk/changeset/0c8b9379f9d5/
Log: Moved storage-statistics to own module, integrated with storage code
and main target. Added test. Added safety-assert to prevent storage-
access during bootstrapping phase (specialized storage like
ClassShadows cannot be used before the objects have been filled in).
Made store_w_superclass and store_w_methoddict of ClassShadow
slightly more consistent.
diff --git a/spyvm/model.py b/spyvm/model.py
--- a/spyvm/model.py
+++ b/spyvm/model.py
@@ -15,7 +15,7 @@
that create W_PointersObjects of correct size with attached shadows.
"""
import sys, weakref
-from spyvm import constants, error, version
+from spyvm import constants, error, version, storage_statistics
from spyvm.version import elidable_for_version
from rpython.rlib import rrandom, objectmodel, jit, signature
@@ -24,7 +24,6 @@
from rpython.tool.pairtype import extendabletype
from rpython.rlib.objectmodel import instantiate, compute_hash,
import_from_mixin, we_are_translated
from rpython.rtyper.lltypesystem import lltype, rffi
-from rpython.rlib.listsort import TimSort
from rsdl import RSDL, RSDL_helper
class W_Object(object):
@@ -468,6 +467,7 @@
Float)."""
_attrs_ = ['w_class']
repr_classname = "W_AbstractObjectWithClassReference"
+ w_class = None
def __init__(self, space, w_class):
if w_class is not None: # it's None only for testing and space
generation
@@ -490,10 +490,12 @@
def guess_classname(self):
if self.has_class():
- class_shadow = self.class_shadow(self.w_class.space())
- # Three question marks, because it would be highly irregular to
have
- # an initialized ClassShadow without an initialized name field.
- return class_shadow.name or "???"
+ if self.w_class.has_shadow():
+ class_shadow = self.class_shadow(self.w_class.space())
+ return class_shadow.name
+ else:
+ # We cannot access the class during the initialization
sequence.
+ return "?? (class not initialized)"
else:
return "? (no class)"
@@ -517,50 +519,12 @@
assert w_class is not None
return w_class.as_class_get_shadow(space)
-class StatsSorter(TimSort):
- def lt(self, a, b):
- if a[0] == b[0]:
- if a[1] == b[1]:
- return a[2] < b[2]
- else:
- return a[1] < b[1]
- else:
- return a[0] < b[0]
-class StrategyStatistics(object):
- # Key: (operation_name, old_strategy, new_strategy)
- # Value: [sizes]
- stats = {}
- do_log = False
- do_stats = False
- do_stats_sizes = False
-
- def stat_operation(self, operation_name, old_strategy, new_strategy, size):
- key = (operation_name, old_strategy, new_strategy)
- if not key in self.stats:
- self.stats[key] = []
- self.stats[key].append(size)
- def log_operation(self, op, new_strategy_tag, old_strategy_tag, classname,
size):
- print "%s (%s, was %s) of %s size %d" % (op, new_strategy_tag,
old_strategy_tag, classname, size)
- def sorted_keys(self):
- keys = [ x for x in self.stats ]
- StatsSorter(keys).sort()
- return keys
- def print_stats(self):
- for key in self.sorted_keys():
- sizes = self.stats[key]
- sum = 0
- for s in sizes:
- sum += s
- print "%s: %d times, avg size: %d" % (key, len(sizes),
sum/len(sizes))
- if self.do_stats_sizes:
- print " All sizes: %s" % sizes
-strategy_stats = StrategyStatistics()
-
class W_AbstractPointersObject(W_AbstractObjectWithClassReference):
"""Common object."""
_attrs_ = ['shadow']
shadow = None
repr_classname = "W_AbstractPointersObject"
+ log_storage = storage_statistics.log
@jit.unroll_safe
def __init__(self, space, w_class, size):
@@ -570,6 +534,7 @@
def initialize_storage(self, space, size):
self.store_shadow(self.empty_storage(space, size))
+ self.log_storage("Initialized")
def fillin(self, space, g_self):
W_AbstractObjectWithClassReference.fillin(self, space, g_self)
@@ -579,17 +544,28 @@
pointers = g_self.get_pointers()
self.store_shadow(self.storage_for_list(space, pointers))
self.store_all(space, pointers)
+ self.log_storage("Filledin", log_classname=False)
def empty_storage(self, space, size):
raise NotImplementedError()
def storage_for_list(self, space, vars):
raise NotImplementedError()
+ def assert_shadow(self):
+ # Failing the following assert most likely indicates a bug. The shadow
can only be absent during
+ # the bootstrapping sequence. It will be initialized in the fillin()
method. Before that, it should
+ # not be switched to a specialized shadow, and the space is also not
yet available here! Otherwise,
+ # the specialized shadow will attempt to read information from an
uninitialized object.
+ shadow = self.shadow
+ assert shadow, "The shadow has not been initialized yet!"
+ return shadow
+
def switch_shadow(self, new_shadow):
- if self.shadow is not None:
- new_shadow.copy_from(self.shadow)
+ old_shadow = self.assert_shadow()
+ new_shadow.copy_from(old_shadow)
self.store_shadow(new_shadow)
new_shadow.attach_shadow()
+ self.log_storage("Switched", old_shadow)
def store_with_new_storage(self, new_storage, n0, w_val):
space = self.space()
@@ -597,8 +573,7 @@
self.store(space, n0, w_val)
def space(self):
- assert self.shadow, "Cannot access space without a shadow!"
- return self.shadow.space
+ return self.assert_shadow().space
def __str__(self):
if self.has_shadow() and self.shadow.provides_getname:
diff --git a/spyvm/shadow.py b/spyvm/shadow.py
--- a/spyvm/shadow.py
+++ b/spyvm/shadow.py
@@ -263,8 +263,8 @@
_attrs_ = ["name", "_instance_size", "instance_varsized", "instance_kind",
"_s_methoddict", "_s_superclass", "subclass_s"]
- name = '??'
- _s_superclass = None
+ name = '??? (incomplete class info)'
+ _s_superclass = _s_methoddict = None
provides_getname = True
repr_classname = "ClassShadow"
@@ -277,10 +277,7 @@
if n0 == constants.CLASS_SUPERCLASS_INDEX:
self.store_w_superclass(w_val)
elif n0 == constants.CLASS_METHODDICT_INDEX:
- assert isinstance(w_val, model.W_PointersObject)
- if not w_val.is_same_object(self.space.w_nil):
- self._s_methoddict = w_val.as_methoddict_get_shadow(self.space)
- self._s_methoddict.s_class = self
+ self.store_w_methoddict(w_val)
elif n0 == constants.CLASS_FORMAT_INDEX:
# read and painfully decode the format
assert isinstance(w_val, model.W_SmallInteger)
@@ -340,18 +337,33 @@
self.changed()
def store_w_superclass(self, w_class):
+ superclass = self._s_superclass
if w_class is None or w_class.is_same_object(self.space.w_nil):
+ if superclass: superclass.detach_s_class(self)
self._s_superclass = None
else:
assert isinstance(w_class, model.W_PointersObject)
- s_scls = w_class.as_class_get_shadow(self.space)
- if self._s_superclass is s_scls:
+ s_new_superclass = w_class.as_class_get_shadow(self.space)
+ if superclass is s_new_superclass:
return
- if self._s_superclass is not None:
- self._s_superclass.detach_s_class(self)
- self._s_superclass = s_scls
- self._s_superclass.attach_s_class(self)
+ if superclass: superclass.detach_s_class(self)
+ self._s_superclass = s_new_superclass
+ s_new_superclass.attach_s_class(self)
+ def store_w_methoddict(self, w_methoddict):
+ methoddict = self._s_methoddict
+ if w_methoddict is None or
w_methoddict.is_same_object(self.space.w_nil):
+ if methoddict: methoddict.s_class = None
+ self._s_methoddict = None
+ else:
+ assert isinstance(w_methoddict, model.W_PointersObject)
+ s_new_methoddict =
w_methoddict.as_methoddict_get_shadow(self.space)
+ if methoddict is s_new_methoddict:
+ return
+ if methoddict: methoddict.s_class = None
+ self._s_methoddict = s_new_methoddict
+ self._s_methoddict.s_class = self
+
def attach_s_class(self, s_other):
self.subclass_s[s_other] = None
@@ -406,7 +418,7 @@
return self._s_superclass
def getname(self):
- return self.name or '?'
+ return self.name
# _______________________________________________________________
# Methods for querying the format word, taken from the blue book:
diff --git a/spyvm/storage_statistics.py b/spyvm/storage_statistics.py
new file mode 100644
--- /dev/null
+++ b/spyvm/storage_statistics.py
@@ -0,0 +1,92 @@
+
+from rpython.rlib.listsort import TimSort
+
+class StatsSorter(TimSort):
+ """Sort a tuple of 3 strings"""
+ def lt(self, a, b):
+ if a[0] == b[0]:
+ if a[1] == b[1]:
+ return a[2] < b[2]
+ else:
+ return a[1] < b[1]
+ else:
+ return a[0] < b[0]
+
+class StorageStatistics(object):
+ # Key: (operation_name, old_storage, new_storage)
+ # Value: [sizes]
+ stats = {}
+
+ do_log = False
+ do_stats = False
+ do_stats_sizes = False
+
+ def log(self, w_obj, operation, old_storage_object, log_classname):
+ if self.do_log or self.do_stats:
+ new_storage = w_obj.shadow.repr_classname
+ if old_storage_object:
+ old_storage = old_storage_object.repr_classname
+ else:
+ old_storage = None
+ size = w_obj.size()
+
+ key = self.make_key(operation, old_storage, new_storage)
+ if _stats.do_stats:
+ self.stat_operation(key, size)
+ if self.do_log:
+ if log_classname:
+ classname = w_obj.guess_classname()
+ else:
+ classname = None
+ self.log_operation(key, size, classname)
+
+ def make_key(self, operation, old_storage, new_storage):
+ return (operation, old_storage, new_storage)
+
+ def stat_operation(self, key, size):
+ if not key in self.stats:
+ self.stats[key] = []
+ self.stats[key].append(size)
+
+ def log_operation(self, key, size, classname):
+ print self.log_operation_string(key, size, classname)
+
+ def key_string(self, key):
+ if key[1]:
+ return "%s (%s -> %s)" % (key[0], key[1], key[2])
+ else:
+ return "%s (%s)" % (key[0], key[2])
+
+ def log_operation_string(self, key, size, classname):
+ if classname:
+ return "%s of %s size %d" % (self.key_string(key), classname, size)
+ else:
+ return "%s size %d" % (self.key_string(key), size)
+
+ def sorted_keys(self):
+ keys = [ x for x in self.stats ]
+ StatsSorter(keys).sort()
+ return keys
+
+ def print_stats(self):
+ for key in self.sorted_keys():
+ sizes = self.stats[key]
+ sum = 0
+ for s in sizes: sum += s
+ print "%s: %d times, avg size: %f" % (self.key_string(key),
len(sizes), sum/len(sizes))
+ if self.do_stats_sizes:
+ print " All sizes: %s" % sizes
+
+_stats = StorageStatistics()
+
+def activate_statistics(log=False, statistics=False, statstics_sizes=False):
+ _stats.do_log = _stats.do_log or log
+ _stats.do_stats = _stats.do_stats or statistics
+ _stats.do_stats_sizes = _stats.do_stats_sizes or statstics_sizes
+
+def print_statistics():
+ if _stats.do_stats:
+ _stats.print_stats()
+
+def log(w_obj, operation, old_storage=None, log_classname=True):
+ _stats.log(w_obj, operation, old_storage, log_classname)
diff --git a/spyvm/test/test_miniimage.py b/spyvm/test/test_miniimage.py
--- a/spyvm/test/test_miniimage.py
+++ b/spyvm/test/test_miniimage.py
@@ -369,7 +369,7 @@
def test_primitive_perform_with_args():
from spyvm.test.test_primitives import _prim
w_o = space.wrap_list([1, 2, 3])
- w_methoddict =
w_o.class_shadow(space)._s_superclass._s_superclass.w_methoddict()
+ w_methoddict =
w_o.class_shadow(space).s_superclass().s_superclass().w_methoddict()
w_methoddict.as_methoddict_get_shadow(space).sync_method_cache()
selectors_w = w_methoddict.shadow.methoddict.keys()
w_sel = None
diff --git a/spyvm/test/test_strategies.py b/spyvm/test/test_strategies.py
--- a/spyvm/test/test_strategies.py
+++ b/spyvm/test/test_strategies.py
@@ -1,5 +1,5 @@
import py
-from spyvm import wrapper, model, interpreter, shadow
+from spyvm import wrapper, model, interpreter, shadow, storage_statistics
from spyvm.error import WrapperException, FatalError
from .util import read_image, copy_to_module, cleanup_module
@@ -176,20 +176,27 @@
assert isinstance(a.shadow, shadow.ListStorageShadow)
check_arr(a, [1.2, 2, w_nil, w_nil, w_nil])
-def test_statistics():
- stats = model.StrategyStatistics()
- stats.stat_operation("B", "old", "new", 3)
- stats.stat_operation("B", "old", "new", 4)
- stats.stat_operation("B", "old2", "new2", 20)
- stats.stat_operation("B", "old", "new", 5)
- stats.stat_operation("A", "old", "new", 1)
- stats.stat_operation("A", "old", "new", 2)
- stats.stat_operation("C", "old", "new", 10)
- stats.stat_operation("C", "old", "new", 11)
+def test_statistics_stats():
+ stats = storage_statistics.StorageStatistics()
+ stats.stat_operation(stats.make_key("B", "old", "new"), 3)
+ stats.stat_operation(stats.make_key("B", "old", "new"), 4)
+ stats.stat_operation(stats.make_key("B", "old2", "new2"), 20)
+ stats.stat_operation(stats.make_key("B", "old", "new"), 5)
+ stats.stat_operation(stats.make_key("A", "old", "new"), 1)
+ stats.stat_operation(stats.make_key("A", "old", "new"), 2)
+ stats.stat_operation(stats.make_key("C", "old", "new"), 10)
+ stats.stat_operation(stats.make_key("C", "old", "new"), 11)
keys = stats.sorted_keys()
assert keys == [ ("A", "old", "new"), ("B", "old", "new"), ("B", "old2",
"new2"), ("C", "old", "new") ]
assert stats.stats[keys[0]] == [1, 2]
assert stats.stats[keys[1]] == [3, 4, 5]
assert stats.stats[keys[2]] == [20]
assert stats.stats[keys[3]] == [10, 11]
+
+def test_statistics_log():
+ stats = storage_statistics.StorageStatistics()
+ s = stats.log_operation_string(stats.make_key("Operation", "old_storage",
"new_storage"), 22, "classname")
+ assert s == "Operation (old_storage -> new_storage) of classname size 22"
+ s = stats.log_operation_string(stats.make_key("InitialOperation", None,
"some_new_storage"), 40, "a_classname")
+ assert s == "InitialOperation (some_new_storage) of a_classname size 40"
\ No newline at end of file
diff --git a/targetimageloadingsmalltalk.py b/targetimageloadingsmalltalk.py
--- a/targetimageloadingsmalltalk.py
+++ b/targetimageloadingsmalltalk.py
@@ -6,7 +6,7 @@
from rpython.rlib import jit, rpath
from spyvm import model, interpreter, squeakimage, objspace, wrapper,\
- error, shadow
+ error, shadow, storage_statistics
from spyvm.tool.analyseimage import create_image
from spyvm.interpreter_proxy import VirtualMachine
@@ -185,12 +185,11 @@
as_benchmark = True
idx += 1
elif arg == "--strategy-log":
- model.strategy_stats.do_log = True
+ storage_statistics.activate_statistics(log=True)
elif arg == "--strategy-stats":
- model.strategy_stats.do_stats = True
+ storage_statistics.activate_statistics(statistics=True)
elif arg == "--strategy-stats-with-sizes":
- model.strategy_stats.do_stats = True
- model.strategy_stats.do_stats_sizes = True
+ storage_statistics.activate_statistics(statistics=True,
statstics_sizes=True)
elif path is None:
path = argv[idx]
else:
@@ -224,8 +223,7 @@
else:
_run_image(interp)
result = 0
- if model.strategy_stats.do_stats:
- model.strategy_stats.print_stats()
+ storage_statistics.print_statistics()
return result
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit