[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