summaryrefslogtreecommitdiffstats
path: root/llvm/utils/opt-viewer/opt-viewer.py
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/utils/opt-viewer/opt-viewer.py')
-rwxr-xr-xllvm/utils/opt-viewer/opt-viewer.py189
1 files changed, 189 insertions, 0 deletions
diff --git a/llvm/utils/opt-viewer/opt-viewer.py b/llvm/utils/opt-viewer/opt-viewer.py
new file mode 100755
index 00000000000..edfef85816f
--- /dev/null
+++ b/llvm/utils/opt-viewer/opt-viewer.py
@@ -0,0 +1,189 @@
+#!/usr/bin/env python2.7
+
+from __future__ import print_function
+
+desc = '''Generate HTML output to visualize optimization records from the YAML files
+generated with -fsave-optimization-record and -fdiagnostics-show-hotness.
+
+The tools requires PyYAML to be installed.'''
+
+import yaml
+import argparse
+import os.path
+import subprocess
+import shutil
+
+parser = argparse.ArgumentParser(description=desc)
+parser.add_argument('yaml_files', nargs='+')
+parser.add_argument('output_dir')
+args = parser.parse_args()
+
+p = subprocess.Popen(['c++filt', '-n'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
+def demangle(name):
+ p.stdin.write(name + '\n')
+ return p.stdout.readline().rstrip()
+
+class Remark(yaml.YAMLObject):
+ @property
+ def File(self):
+ return self.DebugLoc['File']
+
+ @property
+ def Line(self):
+ return int(self.DebugLoc['Line'])
+
+ @property
+ def Column(self):
+ return self.DebugLoc['Column']
+
+ def getDebugLoc(self):
+ return "{}:{}:{}".format(self.File, self.Line, self.Column)
+
+ def getLink(self):
+ return "{}#L{}".format(SourceFileRenderer.html_file_name(self.File), self.Line)
+
+ def getArgString(self, pair):
+ if pair[0] == 'Callee' or pair[0] == 'Caller':
+ return demangle(pair[1])
+ return pair[1]
+
+ @property
+ def message(self):
+ # Args is a list of mappings (dictionaries) with each dictionary with
+ # exactly one key-value pair.
+ values = [self.getArgString(mapping.items()[0]) for mapping in self.Args]
+ return demangle("".join(values))
+
+class Analysis(Remark):
+ yaml_tag = '!Analysis'
+
+ @property
+ def color(self): return "white"
+
+class AnalysisFPCommute(Analysis):
+ yaml_tag = '!AnalysisFPCommute'
+
+class AnalysisAliasing(Analysis):
+ yaml_tag = '!AnalysisAliasing'
+
+class Passed(Remark):
+ yaml_tag = '!Passed'
+
+ @property
+ def color(self): return "green"
+
+class Missed(Remark):
+ yaml_tag = '!Missed'
+
+ @property
+ def color(self): return "red"
+
+class SourceFileRenderer:
+ def __init__(self, filename):
+ self.source_stream = open(filename)
+ self.stream = open(os.path.join(args.output_dir, SourceFileRenderer.html_file_name(filename)), 'w')
+
+ def render_source_line(self, linenum, line):
+ print('''
+<tr>
+<td><a name=\"L{linenum}\">{linenum}</a></td>
+<td></td>
+<td></td>
+<td><pre>{line}</pre></td>
+</tr>'''.format(**locals()), file=self.stream)
+
+ def render_inline_remarks(self, r):
+ print('''
+<tr>
+<td></td>
+<td>{r.Hotness}</td>
+<td class=\"column-entry-{r.color}\">{r.Pass}</td>
+<td class=\"column-entry-yellow\">{r.message}</td>
+</tr>'''.format(**locals()), file=self.stream)
+
+ def render(self, line_remarks):
+ print('''
+<html>
+<head>
+<link rel='stylesheet' type='text/css' href='style.css'>
+</head>
+<body>
+<div class="centered">
+<table>
+<tr>
+<td>Line</td>
+<td>Hotness</td>
+<td>Optimization</td>
+<td>Source</td>
+</tr>''', file=self.stream)
+ for (linenum, line) in enumerate(self.source_stream.readlines(), start=1):
+ self.render_source_line(linenum, line)
+ for remark in line_remarks.get(linenum, []):
+ self.render_inline_remarks(remark)
+ print('''
+</table>
+</body>
+</html>''', file=self.stream)
+
+ @classmethod
+ def html_file_name(cls, filename):
+ return filename.replace('/', '_') + ".html"
+
+class IndexRenderer:
+ def __init__(self):
+ self.stream = open(os.path.join(args.output_dir, 'index.html'), 'w')
+
+ def render_entry(self, remark):
+ html = SourceFileRenderer.html_file_name(remark.File)
+ link = "<a href={}>{}</a>".format(remark.getLink(), remark.getDebugLoc())
+
+ dem_name = demangle(remark.Function)
+ print("<tr><td>{}<td>{}<td>{}<td class=\"column-entry-{}\">{}</tr>".format(
+ link,
+ remark.Hotness, dem_name, remark.color, remark.Pass), file=self.stream)
+
+ def render(self, all_remarks):
+ print('''
+<html>
+<head>
+<link rel='stylesheet' type='text/css' href='style.css'>
+</head>
+<body>
+<div class="centered">
+<table>
+<tr>
+<td>Source Location</td>
+<td>Hotness</td>
+<td>Function</td>
+<td>Pass</td>
+</tr>''', file=self.stream)
+ for remark in all_remarks:
+ self.render_entry(remark)
+ print('''
+</table>
+</body>
+</html>''', file=self.stream)
+
+
+all_remarks = []
+file_remarks = dict()
+
+for input_file in args.yaml_files:
+ f = open(input_file)
+ docs = yaml.load_all(f)
+ for remark in docs:
+ if hasattr(remark, 'Hotness'):
+ file_remarks.setdefault(remark.File, dict()).setdefault(remark.Line, []).append(remark);
+ all_remarks.append(remark)
+
+all_remarks = sorted(all_remarks, key=lambda r: r.Hotness, reverse=True)
+
+if not os.path.exists(args.output_dir):
+ os.mkdir(args.output_dir)
+
+for (filename, remarks) in file_remarks.iteritems():
+ SourceFileRenderer(filename).render(remarks)
+
+IndexRenderer().render(all_remarks)
+
+shutil.copy(os.path.join(os.path.dirname(os.path.realpath(__file__)), "style.css"), args.output_dir)
OpenPOWER on IntegriCloud