Index: tools/opt-viewer/opt-diff.py
===================================================================
--- tools/opt-viewer/opt-diff.py
+++ tools/opt-viewer/opt-diff.py
@@ -60,5 +60,10 @@
r.Added = True
for r in removed:
r.Added = False
+
+ result = added | removed
+ for r in result:
+ r.recover_yaml_structure()
+
with open(args.output, 'w') as stream:
- yaml.dump_all(added | removed, stream)
+ yaml.dump_all(result, stream)
Index: tools/opt-viewer/opt-viewer.py
===================================================================
--- tools/opt-viewer/opt-viewer.py
+++ tools/opt-viewer/opt-viewer.py
@@ -82,7 +82,8 @@
inlining_context = r.DemangledFunctionName
dl = context.caller_loc.get(r.Function)
if dl:
- link = optrecord.make_link(dl['File'], dl['Line'] - 2)
+ dl_dict = dict(list(dl))
+ link = optrecord.make_link(dl_dict['File'], dl_dict['Line'] - 2)
inlining_context = "{r.DemangledFunctionName}".format(**locals())
# Column is the number of characters *including* tabs, keep those and
@@ -176,10 +177,11 @@
for remark in optrecord.itervalues(all_remarks):
if isinstance(remark, optrecord.Passed) and remark.Pass == "inline" and remark.Name == "Inlined":
for arg in remark.Args:
- caller = arg.get('Caller')
+ arg_dict = dict(list(arg))
+ caller = arg_dict.get('Caller')
if caller:
try:
- context.caller_loc[caller] = arg['DebugLoc']
+ context.caller_loc[caller] = arg_dict['DebugLoc']
except KeyError:
pass
Index: tools/opt-viewer/optrecord.py
===================================================================
--- tools/opt-viewer/optrecord.py
+++ tools/opt-viewer/optrecord.py
@@ -60,14 +60,19 @@
# Work-around for http://pyyaml.org/ticket/154.
yaml_loader = Loader
- def _intern_strings(self):
+ # Intern all strings since we have lot of duplication across filenames,
+ # remark text.
+ #
+ # Change Args from a list of dicts to a tuple of tuples. This saves
+ # memory in two ways. One, a small tuple is significantly smaller than a
+ # small dict. Two, using tuple instead of list allows Args to be directly
+ # used as part of the key (in Python only immutable types are hashable).
+ def _reduce_memory(self):
self.Pass = intern(self.Pass)
self.Name = intern(self.Name)
self.Function = intern(self.Function)
- # Intern key and value if string and recurse if value is a dictionary.
- # This handels [{'Caller': ..., 'DebugLoc': { 'File': ... }}]
- def _intern_dict(old_dict):
+ def _reduce_memory_dict(old_dict):
new_dict = dict()
for (k, v) in old_dict.iteritems():
if type(k) is str:
@@ -76,18 +81,33 @@
if type(v) is str:
v = intern(v)
elif type(v) is dict:
- v = _intern_dict(v)
+ # This handels [{'Caller': ..., 'DebugLoc': { 'File': ... }}]
+ v = _reduce_memory_dict(v)
new_dict[k] = v
- return new_dict
+ return tuple(new_dict.items())
- self.Args = [_intern_dict(arg_dict) for arg_dict in self.Args]
+ self.Args = tuple([_reduce_memory_dict(arg_dict) for arg_dict in self.Args])
+
+ # The inverse operation of the dictonary-related memory optimization in
+ # _reduce_memory_dict. E.g.
+ # (('DebugLoc', (('File', ...) ... ))) -> [{'DebugLoc': {'File': ...} ....}]
+ def recover_yaml_structure(self):
+ def tuple_to_dict(t):
+ d = dict()
+ for (k, v) in t:
+ if type(v) is tuple:
+ v = tuple_to_dict(v)
+ d[k] = v
+ return d
+
+ self.Args = [tuple_to_dict(arg_tuple) for arg_tuple in self.Args]
def canonicalize(self):
if not hasattr(self, 'Hotness'):
self.Hotness = 0
if not hasattr(self, 'Args'):
self.Args = []
- self._intern_strings()
+ self._reduce_memory()
@property
def File(self):
@@ -114,7 +134,7 @@
return make_link(self.File, self.Line)
def getArgString(self, mapping):
- mapping = mapping.copy()
+ mapping = dict(list(mapping))
dl = mapping.get('DebugLoc')
if dl:
del mapping['DebugLoc']
@@ -126,8 +146,9 @@
value = cgi.escape(demangle(value))
if dl and key != 'Caller':
+ dl_dict = dict(list(dl))
return "{}".format(
- make_link(dl['File'], dl['Line']), value)
+ make_link(dl_dict['File'], dl_dict['Line']), value)
else:
return value
@@ -158,13 +179,8 @@
@property
def key(self):
- k = (self.__class__, self.PassWithDiffPrefix, self.Name, self.File, self.Line, self.Column, self.Function)
- for arg in self.Args:
- for (key, value) in iteritems(arg):
- if type(value) is dict:
- value = tuple(value.items())
- k += (key, value)
- return k
+ return (self.__class__, self.PassWithDiffPrefix, self.Name, self.File,
+ self.Line, self.Column, self.Function, self.Args)
def __hash__(self):
return hash(self.key)