[pypy-commit] lang-smalltalk storage: Added an option to also aggregate and log the classes of elements that cause an object to switch to another storage strategy.
anton_gulenko
noreply at buildbot.pypy.org
Mon Jul 7 13:16:53 CEST 2014
Author: Anton Gulenko <anton.gulenko at googlemail.com>
Branch: storage
Changeset: r865:13350a81184e
Date: 2014-07-03 15:37 +0200
http://bitbucket.org/pypy/lang-smalltalk/changeset/13350a81184e/
Log: Added an option to also aggregate and log the classes of elements
that cause an object to switch to another storage strategy.
diff --git a/spyvm/model.py b/spyvm/model.py
--- a/spyvm/model.py
+++ b/spyvm/model.py
@@ -612,16 +612,16 @@
assert shadow, "The shadow has not been initialized yet!"
return shadow
- def switch_shadow(self, new_shadow):
+ def switch_shadow(self, new_shadow, w_element=None):
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)
+ self.log_storage("Switched", old_shadow, w_element=w_element)
def store_with_new_storage(self, new_storage, n0, w_val):
space = self.space()
- self.switch_shadow(new_storage(space, self, self.size()))
+ self.switch_shadow(new_storage(space, self, self.size()), w_element=w_val)
self.store(space, n0, w_val)
def space(self):
diff --git a/spyvm/storage_logger.py b/spyvm/storage_logger.py
--- a/spyvm/storage_logger.py
+++ b/spyvm/storage_logger.py
@@ -1,45 +1,65 @@
+
+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):
+ 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] = [0, 0]
- tuple = self.logs[key]
- tuple[0] += size
- tuple[1] += 1
+ self.logs[key] = LogEntry()
+ entry = self.logs[key]
+ entry.add(size, element_classname)
else:
- self.output(operation, old_storage, new_storage, classname, size, 1)
+ 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, tuple in self.logs.items():
+ for key, entry in self.logs.items():
operation, old_storage, new_storage, classname = key
- slots, objects = tuple
- self.output(operation, old_storage, new_storage, classname, slots, objects)
+ 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):
+ 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 ""
- format = (operation, old_storage_string, new_storage, classname_string, slots, objects)
- print "%s (%s%s)%s size %d objects %d" % format
+ 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):
+def activate(aggregate=False, elements=False):
_logger.active = True
- _logger.aggregate = aggregate
+ _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):
+def log(w_obj, operation, old_storage_object=None, log_classname=True, w_element=None):
if not _logger.active:
return
@@ -54,6 +74,10 @@
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)
+ _logger.log(operation, old_storage, new_storage, classname, size, element_classname)
\ No newline at end of file
diff --git a/spyvm/tool/storagelog_parser.py b/spyvm/tool/storagelog_parser.py
--- a/spyvm/tool/storagelog_parser.py
+++ b/spyvm/tool/storagelog_parser.py
@@ -27,7 +27,7 @@
callback(entry)
return parsed_entries
-line_pattern = re.compile("^(?P<operation>\w+) \(((?P<old>\w+) -> )?(?P<new>\w+)\)( of (?P<classname>.+))? size (?P<size>[0-9]+)( objects (?P<objects>[0-9]+))?$")
+line_pattern = re.compile("^(?P<operation>\w+) \(((?P<old>\w+) -> )?(?P<new>\w+)\)( of (?P<classname>.+))? size (?P<size>[0-9]+)( objects (?P<objects>[0-9]+))?( elements: (?P<classnames>.+( .+)+))?$")
def parse_line(line, flags):
result = line_pattern.match(line)
@@ -41,16 +41,20 @@
classname = result.group('classname')
size = result.group('size')
objects = result.group('objects')
- return LogEntry(operation, old_storage, new_storage, classname, size, objects)
+ 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):
- def __init__(self, operation, old_storage, new_storage, classname, size, objects):
+ def __init__(self, operation, old_storage, new_storage, classname, size, objects, classnames):
self.operation = str(operation)
self.new_storage = str(new_storage)
self.classname = str(classname)
self.size = int(size)
self.objects = int(objects) if objects else 1
+ self.classnames = set(classnames) if classnames else set()
if old_storage is None:
if operation == "Filledin":
@@ -83,9 +87,10 @@
class Operations(object):
- def __init__(self, objects=0, slots=0):
+ def __init__(self, objects=0, slots=0, element_classnames=[]):
self.objects = objects
self.slots = slots
+ self.element_classnames = set(element_classnames)
def __str__(self, total=None):
if self.objects == 0:
@@ -102,7 +107,9 @@
percent_objects = ""
slots = format(self.slots, ",d")
objects = format(self.objects, ",d")
- return "%s%s slots in %s%s objects (avg size: %.1f)" % (slots, percent_slots, objects, percent_objects, avg_slots)
+ classnames = (" [ elements: %s ]" % ' '.join([str(x) for x in self.element_classnames])) \
+ if len(self.element_classnames) else ""
+ return "%s%s slots in %s%s objects (avg size: %.1f)%s" % (slots, percent_slots, objects, percent_objects, avg_slots, classnames)
def __repr__(self):
return "%s(%s)" % (self.__str__(), object.__repr__(self))
@@ -110,6 +117,7 @@
def add_log_entry(self, entry):
self.slots = self.slots + entry.size
self.objects = self.objects + entry.objects
+ self.element_classnames |= entry.classnames
def __sub__(self, other):
return Operations(self.objects - other.objects, self.slots - other.slots)
diff --git a/targetimageloadingsmalltalk.py b/targetimageloadingsmalltalk.py
--- a/targetimageloadingsmalltalk.py
+++ b/targetimageloadingsmalltalk.py
@@ -132,6 +132,7 @@
-d|--max-stack-depth [number, default %d, <= 0 disables stack protection]
-l|--storage-log
-L|--storage-log-aggregate
+ -E|--storage-log-elements
[image path, default: Squeak.image]
""" % (argv[0], constants.MAX_LOOP_DEPTH)
@@ -200,6 +201,8 @@
storage_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)
elif path is None:
path = argv[idx]
else:
More information about the pypy-commit
mailing list