OSDN Git Service

New tool: opt-diff.py
authorAdam Nemet <anemet@apple.com>
Thu, 2 Mar 2017 17:00:59 +0000 (17:00 +0000)
committerAdam Nemet <anemet@apple.com>
Thu, 2 Mar 2017 17:00:59 +0000 (17:00 +0000)
This tool allows generating the different between two optimization record
files.  The result is a YAML file too that can be visualized with opt-viewer.

This is very useful to see what optimization were added and removed by a
change.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@296767 91177308-0d34-0410-b5e6-96231b3b80d8

utils/opt-viewer/opt-diff.py [new file with mode: 0755]
utils/opt-viewer/opt-viewer.py
utils/opt-viewer/optrecord.py

diff --git a/utils/opt-viewer/opt-diff.py b/utils/opt-viewer/opt-diff.py
new file mode 100755 (executable)
index 0000000..c51e05e
--- /dev/null
@@ -0,0 +1,68 @@
+#!/usr/bin/env python2.7
+
+from __future__ import print_function
+
+desc = '''Generate the difference of two YAML files into a new YAML file (works on
+pair of directories too).  A new attribute 'Added' is set to True or False
+depending whether the entry is added or removed from the first input to the
+next.
+
+The tools requires PyYAML.'''
+
+import yaml
+# Try to use the C parser.
+try:
+    from yaml import CLoader as Loader
+except ImportError:
+    from yaml import Loader
+
+import optrecord
+import argparse
+from collections import defaultdict
+from multiprocessing import cpu_count, Pool
+import os, os.path
+
+def find_files(dir_or_file):
+    if os.path.isfile(dir_or_file):
+        return [dir_or_file]
+
+    all = []
+    for dir, subdirs, files in os.walk(dir_or_file):
+        for file in files:
+            all.append( os.path.join(dir, file))
+    return all
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(description=desc)
+    parser.add_argument('yaml_dir_or_file_1')
+    parser.add_argument('yaml_dir_or_file_2')
+    parser.add_argument(
+        '--jobs',
+        '-j',
+        default=cpu_count(),
+        type=int,
+        help='Max job count (defaults to current CPU count)')
+    parser.add_argument('--output', '-o', default='diff.opt.yaml')
+    args = parser.parse_args()
+
+    if args.jobs == 1:
+        pmap = map
+    else:
+        pool = Pool(processes=args.jobs)
+        pmap = pool.map
+
+    files1 = find_files(args.yaml_dir_or_file_1)
+    files2 = find_files(args.yaml_dir_or_file_2)
+
+    all_remarks1, _, _ = optrecord.gather_results(pmap, files1)
+    all_remarks2, _, _ = optrecord.gather_results(pmap, files2)
+
+    added = set(all_remarks2.values()) - set(all_remarks1.values())
+    removed = set(all_remarks1.values()) - set(all_remarks2.values())
+
+    for r in added:
+        r.Added = True
+    for r in removed:
+        r.Added = False
+    stream = file(args.output, 'w')
+    yaml.dump_all(added | removed, stream)
index 0b7eaa8..a14aee5 100755 (executable)
@@ -90,7 +90,7 @@ class SourceFileRenderer:
 <tr>
 <td></td>
 <td>{r.RelativeHotness}</td>
-<td class=\"column-entry-{r.color}\">{r.Pass}</td>
+<td class=\"column-entry-{r.color}\">{r.PassWithDiffPrefix}</td>
 <td><pre style="display:inline">{indent}</pre><span class=\"column-entry-yellow\"> {r.message}&nbsp;</span></td>
 <td class=\"column-entry-yellow\">{inlining_context}</td>
 </tr>'''.format(**locals()), file=self.stream)
@@ -133,7 +133,7 @@ class IndexRenderer:
 <td class=\"column-entry-{odd}\"><a href={r.Link}>{r.DebugLocString}</a></td>
 <td class=\"column-entry-{odd}\">{r.RelativeHotness}</td>
 <td class=\"column-entry-{odd}\">{escaped_name}</td>
-<td class=\"column-entry-{r.color}\">{r.Pass}</td>
+<td class=\"column-entry-{r.color}\">{r.PassWithDiffPrefix}</td>
 </tr>'''.format(**locals()), file=self.stream)
 
     def render(self, all_remarks):
index 8b33c0a..3dc77e9 100644 (file)
@@ -88,6 +88,18 @@ class Remark(yaml.YAMLObject):
         else:
             return value
 
+    def getDiffPrefix(self):
+        if hasattr(self, 'Added'):
+            if self.Added:
+                return '+'
+            else:
+                return '-'
+        return ''
+
+    @property
+    def PassWithDiffPrefix(self):
+        return self.getDiffPrefix() + self.Pass
+
     @property
     def message(self):
         # Args is a list of mappings (dictionaries)
@@ -103,7 +115,7 @@ class Remark(yaml.YAMLObject):
 
     @property
     def key(self):
-        k = (self.__class__, self.Pass, self.Name, self.File, self.Line, self.Column, self.Function)
+        k = (self.__class__, self.PassWithDiffPrefix, self.Name, self.File, self.Line, self.Column, self.Function)
         for arg in self.Args:
             for (key, value) in arg.iteritems():
                 if type(value) is dict:
@@ -169,6 +181,11 @@ def get_remarks(input_file):
 
             file_remarks[remark.File][remark.Line].append(remark)
 
+            # If we're reading a back a diff yaml file, max_hotness is already
+            # captured which may actually be less than the max hotness found
+            # in the file.
+            if hasattr(remark, 'max_hotness'):
+                max_hotness = remark.max_hotness
             max_hotness = max(max_hotness, remark.Hotness)
 
     return max_hotness, all_remarks, file_remarks