[pypy-commit] lang-smalltalk rstrategies: Moved the storage logging facility into the rstrategies library (including log parser).
anton_gulenko
noreply at buildbot.pypy.org
Thu Oct 16 16:56:53 CEST 2014
Author: Anton Gulenko <anton.gulenko at googlemail.com>
Branch: rstrategies
Changeset: r1054:40c39046883a
Date: 2014-09-25 10:09 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/40c39046883a/
Log: Moved the storage logging facility into the rstrategies library
(including log parser).
diff --git a/rstrategies.py b/rstrategies.py
--- a/rstrategies.py
+++ b/rstrategies.py
@@ -1,5 +1,6 @@
import weakref
+import rstrategies_logger
from rpython.rlib import jit
class StrategyMetaclass(type):
@@ -17,12 +18,13 @@
return subclasses
class StrategyFactory(object):
- _immutable_fields_ = ["strategies[*]"]
+ _immutable_fields_ = ["strategies[*]", "logger"]
def __init__(self, root_class, all_strategy_classes=None):
if all_strategy_classes is None:
all_strategy_classes = collect_subclasses(root_class)
self.strategies = []
+ self.logger = rstrategies_logger.Logger()
for strategy_class in all_strategy_classes:
if hasattr(strategy_class, "_is_strategy") and strategy_class._is_strategy:
@@ -76,10 +78,23 @@
def instantiate_empty(self, strategy_type):
raise NotImplementedError("Abstract method")
- def switch_strategy(self, old_strategy, new_strategy_type):
+ # This can be overwritten into a more appropriate call to self.logger.log
+ def log(self, new_strategy, old_strategy=None, new_element=None):
+ str = lambda obj: obj.__str__().replace(" ", "").replace("\n", "") if obj else None
+ new_strategy_str = str(new_strategy)
+ old_strategy_str = str(old_strategy)
+ element_typename = str(new_element)
+ size = new_strategy.size()
+ typename = None
+ cause = "SwitchedStrategy"
+ self.logger.log(new_strategy_str, size, cause, old_strategy_str, typename, element_typename)
+
+ def switch_strategy(self, old_strategy, new_strategy_type, new_element=None):
new_instance = self.instantiate_and_switch(old_strategy, old_strategy.size(), new_strategy_type)
old_strategy.initiate_copy_into(new_instance)
new_instance.strategy_switched()
+ if self.logger.active:
+ self.log(new_instance, old_strategy, new_element)
return new_instance
@jit.unroll_safe
@@ -100,7 +115,7 @@
def cannot_handle_value(self, old_strategy, index0, value):
strategy_type = old_strategy.generalized_strategy_for(value)
- new_instance = self.switch_strategy(old_strategy, strategy_type)
+ new_instance = self.switch_strategy(old_strategy, strategy_type, new_element=value)
new_instance.store(index0, value)
def _freeze_(self):
diff --git a/rstrategies_logger.py b/rstrategies_logger.py
new file mode 100644
--- /dev/null
+++ b/rstrategies_logger.py
@@ -0,0 +1,56 @@
+
+class LogEntry(object):
+ def __init__(self):
+ self.slots = 0
+ self.objects = 0
+ self.element_typenames = {}
+
+ def add(self, size, element_typename):
+ self.slots += size
+ self.objects += 1
+ if element_typename:
+ self.element_typenames[element_typename] = None
+
+ def classnames(self):
+ if len(self.element_typenames) > 0:
+ return self.element_typenames.keys()
+ return None
+
+class Logger(object):
+ _attrs_ = ["active", "aggregate", "logs"]
+ _immutable_fields_ = ["active?", "aggregate?", "logs"]
+
+ def __init__(self):
+ self.active = False
+ self.aggregate = False
+ self.logs = {}
+
+ def activate(self, aggregate=False):
+ self.active = True
+ self.aggregate = self.aggregate or aggregate
+
+ def log(self, new_strategy, size, cause=None, old_strategy=None, typename=None, element_typename=None):
+ if self.aggregate:
+ key = (cause, old_strategy, new_strategy, typename)
+ if key not in self.logs:
+ self.logs[key] = LogEntry()
+ entry = self.logs[key]
+ entry.add(size, element_typename)
+ else:
+ element_typenames = [ element_typename ] if element_typename else None
+ self.output(cause, old_strategy, new_strategy, typename, size, 1, element_typenames)
+
+ def print_aggregated_log(self):
+ if not self.aggregate:
+ return
+ for key, entry in self.logs.items():
+ cause, old_strategy, new_strategy, typename = key
+ slots, objects, element_typenames = entry.slots, entry.objects, entry.classnames()
+ self.output(cause, old_strategy, new_strategy, typename, slots, objects, element_typenames)
+
+ def output(self, cause, old_strategy, new_strategy, typename, slots, objects, element_typenames):
+ old_strategy_string = "%s -> " % old_strategy if old_strategy else ""
+ classname_string = " of %s" % typename if typename else ""
+ element_string = (" elements: " + " ".join(element_typenames)) if element_typenames else ""
+ format = (cause, old_strategy_string, new_strategy, classname_string, slots, objects, element_string)
+ print "%s (%s%s)%s size %d objects %d%s" % format
diff --git a/spyvm/tools/storagelog_parser.py b/rstrategies_logparser.py
rename from spyvm/tools/storagelog_parser.py
rename to rstrategies_logparser.py
--- a/spyvm/tools/storagelog_parser.py
+++ b/rstrategies_logparser.py
@@ -1,6 +1,7 @@
import re, os, sys, operator
+# TODO generalize this - read all operations occuring in the logfile
OPERATIONS = ["Filledin", "Initialized", "Switched"]
IMAGE_LOADING_STORAGE = " Image Loading Storage" # Space to be sorted to the beginning
@@ -44,6 +45,7 @@
classnames = result.group('classnames')
if classnames is not None:
classnames = classnames.split(' ')
+
return LogEntry(operation, old_storage, new_storage, classname, size, objects, classnames)
class LogEntry(object):
@@ -64,6 +66,7 @@
else:
assert False, "old_storage has to be available in a Switched operation"
self.old_storage = str(old_storage)
+ assert old_storage != new_storage, "old and new storage identical in log entry: %s" % self
def clear_old_storage(self):
if self.old_storage in (IMAGE_LOADING_STORAGE, OBJECT_CREATION_STORAGE):
@@ -75,6 +78,9 @@
def __lt__(self, other):
return self.classname < other.classname
+ def __repr__(self):
+ return "%s(%s)" % (self.__str__(), object.__repr__(self))
+
def __str__(self):
old_storage_string = "%s -> " % self.old_storage if self.old_storage else ""
classname_string = " of %s" % self.classname if self.classname else ""
@@ -178,6 +184,9 @@
self.classes = ClassOperations()
self.origin = origin
self.target = target
+
+ if self.origin is not None and self.origin is self.target and self.operation != "Filledin":
+ import pdb; pdb.set_trace()
def full_key(self):
return (self.operation, self.origin.name, self.target.name)
@@ -198,7 +207,7 @@
def as_log_entries(self):
entries = []
for classname, ops in self.classes.classes.items():
- entry = LogEntry(self.operation, self.origin.name, self.target.name, classname, ops.slots, ops.objects)
+ entry = LogEntry(self.operation, self.origin.name, self.target.name, classname, ops.slots, ops.objects, ops.element_classnames)
entry.clear_old_storage()
entries.append(entry)
return entries
diff --git a/spyvm/model.py b/spyvm/model.py
--- a/spyvm/model.py
+++ b/spyvm/model.py
@@ -12,7 +12,7 @@
W_CompiledMethod
"""
import sys
-from spyvm import constants, error, storage_logger
+from spyvm import constants, error
from spyvm.util.version import constant_for_version, constant_for_version_arg, VersionMixin
from rpython.rlib import rrandom, objectmodel, jit, signature
@@ -566,7 +566,6 @@
_attrs_ = ['shadow']
shadow = None
repr_classname = "W_PointersObject"
- log_storage = storage_logger.log
@jit.unroll_safe
def __init__(self, space, w_class, size, weak=False):
@@ -576,7 +575,7 @@
def initialize_storage(self, space, size, weak=False):
storage = space.strategy_factory.empty_storage(self, size, weak)
- self.store_shadow(storage, operation="Initialized")
+ self.store_shadow(storage)
def fillin(self, space, g_self):
W_AbstractObjectWithClassReference.fillin(self, space, g_self)
@@ -587,7 +586,7 @@
storage_type = space.strategy_factory.strategy_type_for(pointers, g_self.isweak())
storage = storage_type(space, self, len(pointers))
assert self.shadow is None, "Shadow should not be initialized yet!"
- self.store_shadow(storage, operation="Filledin", log_classname=False)
+ self.store_shadow(storage)
self.store_all(space, pointers)
def is_weak(self):
@@ -667,10 +666,9 @@
def instsize(self):
return self.class_shadow(self.space()).instsize()
- def store_shadow(self, shadow, operation="Switched", w_element=None, log_classname=True):
+ def store_shadow(self, shadow):
old_shadow = self.shadow
self.shadow = shadow
- self.log_storage(operation, old_shadow, log_classname, w_element)
def _get_shadow(self):
return self.shadow
diff --git a/spyvm/storage.py b/spyvm/storage.py
--- a/spyvm/storage.py
+++ b/spyvm/storage.py
@@ -91,7 +91,7 @@
def value(self): return self.space.w_nil
class StrategyFactory(rstrat.StrategyFactory):
- _immutable_fields_ = ["space", "no_specialized_storage?"]
+ _immutable_fields_ = ["space", "no_specialized_storage"]
def __init__(self, space):
from spyvm import objspace
self.space = space
@@ -120,7 +120,21 @@
def instantiate_empty(self, strategy_type):
return strategy_type(self.space, None, 0)
-
+
+ def log(self, new_strategy, old_strategy=None, new_element=None):
+ # Gather information to be logged
+ image_loaded = self.space.image_loaded.is_set()
+ size = new_strategy.size()
+ new_strategy_str = new_strategy.repr_classname
+ old_strategy_str = old_strategy.repr_classname if old_strategy else None
+ classname = new_strategy.w_self().guess_classname() if image_loaded else None
+ element_classname = new_element.guess_classname() if new_element and image_loaded else None
+ if image_loaded:
+ cause = "Switched" if old_strategy else "Initialized"
+ else:
+ cause = "Filledin"
+ self.logger.log(new_strategy_str, size, cause, old_strategy_str, classname, element_classname)
+
# ========== Other storage classes, non-strategies ==========
class AbstractRedirectingShadow(AbstractShadow):
diff --git a/spyvm/storage_logger.py b/spyvm/storage_logger.py
deleted file mode 100644
--- a/spyvm/storage_logger.py
+++ /dev/null
@@ -1,83 +0,0 @@
-
-class LogEntry(object):
- def __init__(self):
- self.slots = 0
- self.objects = 0
- self.element_classnames = {}
-
- def add(self, size, element_classname):
- self.slots += size
- self.objects += 1
- if element_classname:
- self.element_classnames[element_classname] = None
-
- def classnames(self):
- if len(self.element_classnames) > 0:
- return self.element_classnames.keys()
- return None
-
-class Logger(object):
- def __init__(self):
- self.active = False
- self.aggregate = False
- self.elements = False
- self.logs = {}
-
- def log(self, operation, old_storage, new_storage, classname, size, element_classname):
- if self.aggregate:
- key = (operation, old_storage, new_storage, classname)
- if key not in self.logs:
- self.logs[key] = LogEntry()
- entry = self.logs[key]
- entry.add(size, element_classname)
- else:
- element_classnames = [ element_classname ] if element_classname else None
- self.output(operation, old_storage, new_storage, classname, size, 1, element_classnames)
-
- def print_aggregated_log(self):
- if not self.aggregate:
- return
- for key, entry in self.logs.items():
- operation, old_storage, new_storage, classname = key
- slots, objects, element_classnames = entry.slots, entry.objects, entry.classnames()
- self.output(operation, old_storage, new_storage, classname, slots, objects, element_classnames)
-
- def output(self, operation, old_storage, new_storage, classname, slots, objects, element_classnames):
- old_storage_string = "%s -> " % old_storage if old_storage else ""
- classname_string = " of %s" % classname if classname else ""
- element_string = (" elements: " + " ".join(element_classnames)) if element_classnames else ""
- format = (operation, old_storage_string, new_storage, classname_string, slots, objects, element_string)
- print "%s (%s%s)%s size %d objects %d%s" % format
-
-_logger = Logger()
-
-def activate(aggregate=False, elements=False):
- _logger.active = True
- _logger.aggregate = _logger.aggregate or aggregate
- _logger.elements = _logger.elements or elements
-
-def print_aggregated_log():
- _logger.print_aggregated_log()
-
-def log(w_obj, operation, old_storage_object=None, log_classname=True, w_element=None):
- if not _logger.active:
- return
-
- # Gather information to be logged
- 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()
- if log_classname:
- classname = w_obj.guess_classname()
- else:
- classname = None
- if _logger.elements and w_element and log_classname:
- element_classname = w_element.guess_classname()
- else:
- element_classname = None
-
- _logger.log(operation, old_storage, new_storage, classname, size, element_classname)
-
\ No newline at end of file
diff --git a/targetimageloadingsmalltalk.py b/targetimageloadingsmalltalk.py
--- a/targetimageloadingsmalltalk.py
+++ b/targetimageloadingsmalltalk.py
@@ -2,7 +2,7 @@
import sys, time, os
from rpython.rlib import jit, rpath, objectmodel
-from spyvm import model, interpreter, squeakimage, objspace, wrapper, error, storage_logger
+from spyvm import model, interpreter, squeakimage, objspace, wrapper, error
def _usage(argv):
print """
@@ -38,7 +38,6 @@
-s|--safe-trace - If tracing is active, omit printing contents of BytesObjects
-l|--storage-log - Output a log of storage operations.
-L|--storage-log-aggregate - Output an aggregated storage log at the end of execution.
- -E|--storage-log-elements - Include classnames of elements into the storage log.
""" % argv[0]
@@ -75,6 +74,8 @@
import traceback
traceback.print_exc()
return -1
+ finally:
+ prebuilt_space.strategy_factory.logger.print_aggregated_log()
def entry_point(argv):
# == Main execution parameters
@@ -132,11 +133,9 @@
from spyvm.plugins.vmdebugging import stop_ui_process
stop_ui_process()
elif arg in ["-l", "--storage-log"]:
- storage_logger.activate()
+ space.strategy_factory.logger.activate()
elif arg in ["-L", "--storage-log-aggregate"]:
- storage_logger.activate(aggregate=True)
- elif arg in ["-E", "--storage-log-elements"]:
- storage_logger.activate(elements=True)
+ space.strategy_factory.logger.activate(aggregate=True)
elif path is None:
path = arg
else:
@@ -186,7 +185,6 @@
w_result = execute_context(interp, context)
print result_string(w_result)
- storage_logger.print_aggregated_log()
return 0
def result_string(w_result):
More information about the pypy-commit
mailing list