You've already forked linux-packaging-mono
Imported Upstream version 5.18.0.167
Former-commit-id: 289509151e0fee68a1b591a20c9f109c3c789d3a
This commit is contained in:
parent
e19d552987
commit
b084638f15
13
external/llvm/tools/opt-viewer/CMakeLists.txt
vendored
13
external/llvm/tools/opt-viewer/CMakeLists.txt
vendored
@ -1,13 +0,0 @@
|
||||
set (files
|
||||
"opt-diff.py"
|
||||
"opt-stats.py"
|
||||
"opt-viewer.py"
|
||||
"optpmap.py"
|
||||
"optrecord.py"
|
||||
"style.css")
|
||||
|
||||
foreach (file ${files})
|
||||
install(PROGRAMS ${file}
|
||||
DESTINATION share/opt-viewer
|
||||
COMPONENT opt-viewer)
|
||||
endforeach (file)
|
69
external/llvm/tools/opt-viewer/opt-diff.py
vendored
69
external/llvm/tools/opt-viewer/opt-diff.py
vendored
@ -1,69 +0,0 @@
|
||||
#!/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
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description=desc)
|
||||
parser.add_argument(
|
||||
'yaml_dir_or_file_1',
|
||||
help='An optimization record file or a directory searched for optimization '
|
||||
'record files that are used as the old version for the comparison')
|
||||
parser.add_argument(
|
||||
'yaml_dir_or_file_2',
|
||||
help='An optimization record file or a directory searched for optimization '
|
||||
'record files that are used as the new version for the comparison')
|
||||
parser.add_argument(
|
||||
'--jobs',
|
||||
'-j',
|
||||
default=cpu_count(),
|
||||
type=int,
|
||||
help='Max job count (defaults to %(default)s, the current CPU count)')
|
||||
parser.add_argument(
|
||||
'--no-progress-indicator',
|
||||
'-n',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Do not display any indicator of how many YAML files were read.')
|
||||
parser.add_argument('--output', '-o', default='diff.opt.yaml')
|
||||
args = parser.parse_args()
|
||||
|
||||
files1 = optrecord.find_opt_files(args.yaml_dir_or_file_1)
|
||||
files2 = optrecord.find_opt_files(args.yaml_dir_or_file_2)
|
||||
|
||||
print_progress = not args.no_progress_indicator
|
||||
all_remarks1, _, _ = optrecord.gather_results(files1, args.jobs, print_progress)
|
||||
all_remarks2, _, _ = optrecord.gather_results(files2, args.jobs, print_progress)
|
||||
|
||||
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
|
||||
|
||||
result = added | removed
|
||||
for r in result:
|
||||
r.recover_yaml_structure()
|
||||
|
||||
with open(args.output, 'w') as stream:
|
||||
yaml.dump_all(result, stream)
|
78
external/llvm/tools/opt-viewer/opt-stats.py
vendored
78
external/llvm/tools/opt-viewer/opt-stats.py
vendored
@ -1,78 +0,0 @@
|
||||
#!/usr/bin/env python2.7
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
desc = '''Generate statistics about optimization records from the YAML files
|
||||
generated with -fsave-optimization-record and -fdiagnostics-show-hotness.
|
||||
|
||||
The tools requires PyYAML and Pygments Python packages.'''
|
||||
|
||||
import optrecord
|
||||
import argparse
|
||||
import operator
|
||||
from collections import defaultdict
|
||||
from multiprocessing import cpu_count, Pool
|
||||
|
||||
try:
|
||||
from guppy import hpy
|
||||
hp = hpy()
|
||||
except ImportError:
|
||||
print("Memory consumption not shown because guppy is not installed")
|
||||
hp = None
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description=desc)
|
||||
parser.add_argument(
|
||||
'yaml_dirs_or_files',
|
||||
nargs='+',
|
||||
help='List of optimization record files or directories searched '
|
||||
'for optimization record files.')
|
||||
parser.add_argument(
|
||||
'--jobs',
|
||||
'-j',
|
||||
default=cpu_count(),
|
||||
type=int,
|
||||
help='Max job count (defaults to %(default)s, the current CPU count)')
|
||||
parser.add_argument(
|
||||
'--no-progress-indicator',
|
||||
'-n',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Do not display any indicator of how many YAML files were read.')
|
||||
args = parser.parse_args()
|
||||
|
||||
print_progress = not args.no_progress_indicator
|
||||
|
||||
files = optrecord.find_opt_files(*args.yaml_dirs_or_files)
|
||||
if not files:
|
||||
parser.error("No *.opt.yaml files found")
|
||||
sys.exit(1)
|
||||
|
||||
all_remarks, file_remarks, _ = optrecord.gather_results(
|
||||
files, args.jobs, print_progress)
|
||||
if print_progress:
|
||||
print('\n')
|
||||
|
||||
bypass = defaultdict(int)
|
||||
byname = defaultdict(int)
|
||||
for r in optrecord.itervalues(all_remarks):
|
||||
bypass[r.Pass] += 1
|
||||
byname[r.Pass + "/" + r.Name] += 1
|
||||
|
||||
total = len(all_remarks)
|
||||
print("{:24s} {:10d}".format("Total number of remarks", total))
|
||||
if hp:
|
||||
h = hp.heap()
|
||||
print("{:24s} {:10d}".format("Memory per remark",
|
||||
h.size / len(all_remarks)))
|
||||
print('\n')
|
||||
|
||||
print("Top 10 remarks by pass:")
|
||||
for (passname, count) in sorted(bypass.items(), key=operator.itemgetter(1),
|
||||
reverse=True)[:10]:
|
||||
print(" {:30s} {:2.0f}%". format(passname, count * 100. / total))
|
||||
|
||||
print("\nTop 10 remarks:")
|
||||
for (name, count) in sorted(byname.items(), key=operator.itemgetter(1),
|
||||
reverse=True)[:10]:
|
||||
print(" {:30s} {:2.0f}%". format(name, count * 100. / total))
|
326
external/llvm/tools/opt-viewer/opt-viewer.py
vendored
326
external/llvm/tools/opt-viewer/opt-viewer.py
vendored
@ -1,326 +0,0 @@
|
||||
#!/usr/bin/env python2.7
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import argparse
|
||||
import cgi
|
||||
import codecs
|
||||
import errno
|
||||
import functools
|
||||
from multiprocessing import cpu_count
|
||||
import os.path
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
from pygments import highlight
|
||||
from pygments.lexers.c_cpp import CppLexer
|
||||
from pygments.formatters import HtmlFormatter
|
||||
|
||||
import optpmap
|
||||
import optrecord
|
||||
|
||||
|
||||
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 and Pygments Python packages.'''
|
||||
|
||||
|
||||
# This allows passing the global context to the child processes.
|
||||
class Context:
|
||||
def __init__(self, caller_loc = dict()):
|
||||
# Map function names to their source location for function where inlining happened
|
||||
self.caller_loc = caller_loc
|
||||
|
||||
context = Context()
|
||||
|
||||
def suppress(remark):
|
||||
if remark.Name == 'sil.Specialized':
|
||||
return remark.getArgDict()['Function'][0].startswith('\"Swift.')
|
||||
elif remark.Name == 'sil.Inlined':
|
||||
return remark.getArgDict()['Callee'][0].startswith(('\"Swift.', '\"specialized Swift.'))
|
||||
return False
|
||||
|
||||
class SourceFileRenderer:
|
||||
def __init__(self, source_dir, output_dir, filename):
|
||||
existing_filename = None
|
||||
if os.path.exists(filename):
|
||||
existing_filename = filename
|
||||
else:
|
||||
fn = os.path.join(source_dir, filename)
|
||||
if os.path.exists(fn):
|
||||
existing_filename = fn
|
||||
|
||||
self.stream = codecs.open(os.path.join(output_dir, optrecord.html_file_name(filename)), 'w', encoding='utf-8')
|
||||
if existing_filename:
|
||||
self.source_stream = open(existing_filename)
|
||||
else:
|
||||
self.source_stream = None
|
||||
print('''
|
||||
<html>
|
||||
<h1>Unable to locate file {}</h1>
|
||||
</html>
|
||||
'''.format(filename), file=self.stream)
|
||||
|
||||
self.html_formatter = HtmlFormatter(encoding='utf-8')
|
||||
self.cpp_lexer = CppLexer(stripnl=False)
|
||||
|
||||
def render_source_lines(self, stream, line_remarks):
|
||||
file_text = stream.read()
|
||||
|
||||
if args.no_highlight:
|
||||
html_highlighted = file_text.decode('utf-8')
|
||||
else:
|
||||
html_highlighted = highlight(
|
||||
file_text,
|
||||
self.cpp_lexer,
|
||||
self.html_formatter)
|
||||
|
||||
# Note that the API is different between Python 2 and 3. On
|
||||
# Python 3, pygments.highlight() returns a bytes object, so we
|
||||
# have to decode. On Python 2, the output is str but since we
|
||||
# support unicode characters and the output streams is unicode we
|
||||
# decode too.
|
||||
html_highlighted = html_highlighted.decode('utf-8')
|
||||
|
||||
# Take off the header and footer, these must be
|
||||
# reapplied line-wise, within the page structure
|
||||
html_highlighted = html_highlighted.replace('<div class="highlight"><pre>', '')
|
||||
html_highlighted = html_highlighted.replace('</pre></div>', '')
|
||||
|
||||
for (linenum, html_line) in enumerate(html_highlighted.split('\n'), start=1):
|
||||
print(u'''
|
||||
<tr>
|
||||
<td><a name=\"L{linenum}\">{linenum}</a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td><div class="highlight"><pre>{html_line}</pre></div></td>
|
||||
</tr>'''.format(**locals()), file=self.stream)
|
||||
|
||||
for remark in line_remarks.get(linenum, []):
|
||||
if not suppress(remark):
|
||||
self.render_inline_remarks(remark, html_line)
|
||||
|
||||
def render_inline_remarks(self, r, line):
|
||||
inlining_context = r.DemangledFunctionName
|
||||
dl = context.caller_loc.get(r.Function)
|
||||
if dl:
|
||||
dl_dict = dict(list(dl))
|
||||
link = optrecord.make_link(dl_dict['File'], dl_dict['Line'] - 2)
|
||||
inlining_context = "<a href={link}>{r.DemangledFunctionName}</a>".format(**locals())
|
||||
|
||||
# Column is the number of characters *including* tabs, keep those and
|
||||
# replace everything else with spaces.
|
||||
indent = line[:max(r.Column, 1) - 1]
|
||||
indent = re.sub('\S', ' ', indent)
|
||||
|
||||
print(u'''
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>{r.RelativeHotness}</td>
|
||||
<td class=\"column-entry-{r.color}\">{r.PassWithDiffPrefix}</td>
|
||||
<td><pre style="display:inline">{indent}</pre><span class=\"column-entry-yellow\"> {r.message} </span></td>
|
||||
<td class=\"column-entry-yellow\">{inlining_context}</td>
|
||||
</tr>'''.format(**locals()), file=self.stream)
|
||||
|
||||
def render(self, line_remarks):
|
||||
if not self.source_stream:
|
||||
return
|
||||
|
||||
print('''
|
||||
<html>
|
||||
<meta charset="utf-8" />
|
||||
<head>
|
||||
<link rel='stylesheet' type='text/css' href='style.css'>
|
||||
</head>
|
||||
<body>
|
||||
<div class="centered">
|
||||
<table class="source">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 2%">Line</td>
|
||||
<th style="width: 3%">Hotness</td>
|
||||
<th style="width: 10%">Optimization</td>
|
||||
<th style="width: 70%">Source</td>
|
||||
<th style="width: 15%">Inline Context</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>''', file=self.stream)
|
||||
self.render_source_lines(self.source_stream, line_remarks)
|
||||
|
||||
print('''
|
||||
</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>''', file=self.stream)
|
||||
|
||||
|
||||
class IndexRenderer:
|
||||
def __init__(self, output_dir, should_display_hotness):
|
||||
self.stream = codecs.open(os.path.join(output_dir, 'index.html'), 'w', encoding='utf-8')
|
||||
self.should_display_hotness = should_display_hotness
|
||||
|
||||
def render_entry(self, r, odd):
|
||||
escaped_name = cgi.escape(r.DemangledFunctionName)
|
||||
print(u'''
|
||||
<tr>
|
||||
<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.PassWithDiffPrefix}</td>
|
||||
</tr>'''.format(**locals()), file=self.stream)
|
||||
|
||||
def render(self, all_remarks):
|
||||
print('''
|
||||
<html>
|
||||
<meta charset="utf-8" />
|
||||
<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)
|
||||
|
||||
max_entries = None
|
||||
if should_display_hotness:
|
||||
max_entries = args.max_hottest_remarks_on_index
|
||||
|
||||
for i, remark in enumerate(all_remarks[:max_entries]):
|
||||
if not suppress(remark):
|
||||
self.render_entry(remark, i % 2)
|
||||
print('''
|
||||
</table>
|
||||
</body>
|
||||
</html>''', file=self.stream)
|
||||
|
||||
|
||||
def _render_file(source_dir, output_dir, ctx, entry):
|
||||
global context
|
||||
context = ctx
|
||||
filename, remarks = entry
|
||||
SourceFileRenderer(source_dir, output_dir, filename).render(remarks)
|
||||
|
||||
|
||||
def map_remarks(all_remarks):
|
||||
# Set up a map between function names and their source location for
|
||||
# function where inlining happened
|
||||
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:
|
||||
arg_dict = dict(list(arg))
|
||||
caller = arg_dict.get('Caller')
|
||||
if caller:
|
||||
try:
|
||||
context.caller_loc[caller] = arg_dict['DebugLoc']
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
||||
def generate_report(all_remarks,
|
||||
file_remarks,
|
||||
source_dir,
|
||||
output_dir,
|
||||
should_display_hotness,
|
||||
num_jobs,
|
||||
should_print_progress):
|
||||
try:
|
||||
os.makedirs(output_dir)
|
||||
except OSError as e:
|
||||
if e.errno == errno.EEXIST and os.path.isdir(output_dir):
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
|
||||
_render_file_bound = functools.partial(_render_file, source_dir, output_dir, context)
|
||||
if should_print_progress:
|
||||
print('Rendering HTML files...')
|
||||
optpmap.pmap(_render_file_bound,
|
||||
file_remarks.items(),
|
||||
num_jobs,
|
||||
should_print_progress)
|
||||
|
||||
if should_display_hotness:
|
||||
sorted_remarks = sorted(optrecord.itervalues(all_remarks), key=lambda r: (r.Hotness, r.File, r.Line, r.Column, r.PassWithDiffPrefix, r.yaml_tag, r.Function), reverse=True)
|
||||
else:
|
||||
sorted_remarks = sorted(optrecord.itervalues(all_remarks), key=lambda r: (r.File, r.Line, r.Column, r.PassWithDiffPrefix, r.yaml_tag, r.Function))
|
||||
IndexRenderer(args.output_dir, should_display_hotness).render(sorted_remarks)
|
||||
|
||||
shutil.copy(os.path.join(os.path.dirname(os.path.realpath(__file__)),
|
||||
"style.css"), output_dir)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description=desc)
|
||||
parser.add_argument(
|
||||
'yaml_dirs_or_files',
|
||||
nargs='+',
|
||||
help='List of optimization record files or directories searched '
|
||||
'for optimization record files.')
|
||||
parser.add_argument(
|
||||
'--output-dir',
|
||||
'-o',
|
||||
default='html',
|
||||
help='Path to a directory where generated HTML files will be output. '
|
||||
'If the directory does not already exist, it will be created. '
|
||||
'"%(default)s" by default.')
|
||||
parser.add_argument(
|
||||
'--jobs',
|
||||
'-j',
|
||||
default=cpu_count(),
|
||||
type=int,
|
||||
help='Max job count (defaults to %(default)s, the current CPU count)')
|
||||
parser.add_argument(
|
||||
'--source-dir',
|
||||
'-s',
|
||||
default='',
|
||||
help='set source directory')
|
||||
parser.add_argument(
|
||||
'--no-progress-indicator',
|
||||
'-n',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Do not display any indicator of how many YAML files were read '
|
||||
'or rendered into HTML.')
|
||||
parser.add_argument(
|
||||
'--max-hottest-remarks-on-index',
|
||||
default=1000,
|
||||
type=int,
|
||||
help='Maximum number of the hottest remarks to appear on the index page')
|
||||
parser.add_argument(
|
||||
'--no-highlight',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Do not use a syntax highlighter when rendering the source code')
|
||||
parser.add_argument(
|
||||
'--demangler',
|
||||
help='Set the demangler to be used (defaults to %s)' % optrecord.Remark.default_demangler)
|
||||
args = parser.parse_args()
|
||||
|
||||
print_progress = not args.no_progress_indicator
|
||||
if args.demangler:
|
||||
optrecord.Remark.set_demangler(args.demangler)
|
||||
|
||||
files = optrecord.find_opt_files(*args.yaml_dirs_or_files)
|
||||
if not files:
|
||||
parser.error("No *.opt.yaml files found")
|
||||
sys.exit(1)
|
||||
|
||||
all_remarks, file_remarks, should_display_hotness = \
|
||||
optrecord.gather_results(files, args.jobs, print_progress)
|
||||
|
||||
map_remarks(all_remarks)
|
||||
|
||||
generate_report(all_remarks,
|
||||
file_remarks,
|
||||
args.source_dir,
|
||||
args.output_dir,
|
||||
should_display_hotness,
|
||||
args.jobs,
|
||||
print_progress)
|
54
external/llvm/tools/opt-viewer/optpmap.py
vendored
54
external/llvm/tools/opt-viewer/optpmap.py
vendored
@ -1,54 +0,0 @@
|
||||
import sys
|
||||
import multiprocessing
|
||||
|
||||
|
||||
_current = None
|
||||
_total = None
|
||||
|
||||
|
||||
def _init(current, total):
|
||||
global _current
|
||||
global _total
|
||||
_current = current
|
||||
_total = total
|
||||
|
||||
|
||||
def _wrapped_func(func_and_args):
|
||||
func, argument, should_print_progress = func_and_args
|
||||
|
||||
if should_print_progress:
|
||||
with _current.get_lock():
|
||||
_current.value += 1
|
||||
sys.stdout.write('\r\t{} of {}'.format(_current.value, _total.value))
|
||||
sys.stdout.flush()
|
||||
|
||||
return func(argument)
|
||||
|
||||
|
||||
def pmap(func, iterable, processes, should_print_progress, *args, **kwargs):
|
||||
"""
|
||||
A parallel map function that reports on its progress.
|
||||
|
||||
Applies `func` to every item of `iterable` and return a list of the
|
||||
results. If `processes` is greater than one, a process pool is used to run
|
||||
the functions in parallel. `should_print_progress` is a boolean value that
|
||||
indicates whether a string 'N of M' should be printed to indicate how many
|
||||
of the functions have finished being run.
|
||||
"""
|
||||
global _current
|
||||
global _total
|
||||
_current = multiprocessing.Value('i', 0)
|
||||
_total = multiprocessing.Value('i', len(iterable))
|
||||
|
||||
func_and_args = [(func, arg, should_print_progress,) for arg in iterable]
|
||||
if processes <= 1:
|
||||
result = map(_wrapped_func, func_and_args, *args, **kwargs)
|
||||
else:
|
||||
pool = multiprocessing.Pool(initializer=_init,
|
||||
initargs=(_current, _total,),
|
||||
processes=processes)
|
||||
result = pool.map(_wrapped_func, func_and_args, *args, **kwargs)
|
||||
|
||||
if should_print_progress:
|
||||
sys.stdout.write('\r')
|
||||
return result
|
333
external/llvm/tools/opt-viewer/optrecord.py
vendored
333
external/llvm/tools/opt-viewer/optrecord.py
vendored
@ -1,333 +0,0 @@
|
||||
#!/usr/bin/env python2.7
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import yaml
|
||||
# Try to use the C parser.
|
||||
try:
|
||||
from yaml import CLoader as Loader
|
||||
except ImportError:
|
||||
print("For faster parsing, you may want to install libYAML for PyYAML")
|
||||
from yaml import Loader
|
||||
|
||||
import cgi
|
||||
from collections import defaultdict
|
||||
import fnmatch
|
||||
import functools
|
||||
from multiprocessing import Lock
|
||||
import os, os.path
|
||||
import subprocess
|
||||
try:
|
||||
# The previously builtin function `intern()` was moved
|
||||
# to the `sys` module in Python 3.
|
||||
from sys import intern
|
||||
except:
|
||||
pass
|
||||
|
||||
import optpmap
|
||||
|
||||
try:
|
||||
dict.iteritems
|
||||
except AttributeError:
|
||||
# Python 3
|
||||
def itervalues(d):
|
||||
return iter(d.values())
|
||||
def iteritems(d):
|
||||
return iter(d.items())
|
||||
else:
|
||||
# Python 2
|
||||
def itervalues(d):
|
||||
return d.itervalues()
|
||||
def iteritems(d):
|
||||
return d.iteritems()
|
||||
|
||||
|
||||
def html_file_name(filename):
|
||||
return filename.replace('/', '_').replace('#', '_') + ".html"
|
||||
|
||||
|
||||
def make_link(File, Line):
|
||||
return "\"{}#L{}\"".format(html_file_name(File), Line)
|
||||
|
||||
|
||||
class Remark(yaml.YAMLObject):
|
||||
# Work-around for http://pyyaml.org/ticket/154.
|
||||
yaml_loader = Loader
|
||||
|
||||
default_demangler = 'c++filt -n'
|
||||
demangler_proc = None
|
||||
|
||||
@classmethod
|
||||
def set_demangler(cls, demangler):
|
||||
cls.demangler_proc = subprocess.Popen(demangler.split(), stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||
cls.demangler_lock = Lock()
|
||||
|
||||
@classmethod
|
||||
def demangle(cls, name):
|
||||
with cls.demangler_lock:
|
||||
cls.demangler_proc.stdin.write((name + '\n').encode('utf-8'))
|
||||
cls.demangler_proc.stdin.flush()
|
||||
return cls.demangler_proc.stdout.readline().rstrip().decode('utf-8')
|
||||
|
||||
# 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)
|
||||
try:
|
||||
# Can't intern unicode strings.
|
||||
self.Function = intern(self.Function)
|
||||
except:
|
||||
pass
|
||||
|
||||
def _reduce_memory_dict(old_dict):
|
||||
new_dict = dict()
|
||||
for (k, v) in iteritems(old_dict):
|
||||
if type(k) is str:
|
||||
k = intern(k)
|
||||
|
||||
if type(v) is str:
|
||||
v = intern(v)
|
||||
elif type(v) is dict:
|
||||
# This handles [{'Caller': ..., 'DebugLoc': { 'File': ... }}]
|
||||
v = _reduce_memory_dict(v)
|
||||
new_dict[k] = v
|
||||
return tuple(new_dict.items())
|
||||
|
||||
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._reduce_memory()
|
||||
|
||||
@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']
|
||||
|
||||
@property
|
||||
def DebugLocString(self):
|
||||
return "{}:{}:{}".format(self.File, self.Line, self.Column)
|
||||
|
||||
@property
|
||||
def DemangledFunctionName(self):
|
||||
return self.demangle(self.Function)
|
||||
|
||||
@property
|
||||
def Link(self):
|
||||
return make_link(self.File, self.Line)
|
||||
|
||||
def getArgString(self, mapping):
|
||||
mapping = dict(list(mapping))
|
||||
dl = mapping.get('DebugLoc')
|
||||
if dl:
|
||||
del mapping['DebugLoc']
|
||||
|
||||
assert(len(mapping) == 1)
|
||||
(key, value) = list(mapping.items())[0]
|
||||
|
||||
if key == 'Caller' or key == 'Callee' or key == 'DirectCallee':
|
||||
value = cgi.escape(self.demangle(value))
|
||||
|
||||
if dl and key != 'Caller':
|
||||
dl_dict = dict(list(dl))
|
||||
return u"<a href={}>{}</a>".format(
|
||||
make_link(dl_dict['File'], dl_dict['Line']), value)
|
||||
else:
|
||||
return value
|
||||
|
||||
# Return a cached dictionary for the arguments. The key for each entry is
|
||||
# the argument key (e.g. 'Callee' for inlining remarks. The value is a
|
||||
# list containing the value (e.g. for 'Callee' the function) and
|
||||
# optionally a DebugLoc.
|
||||
def getArgDict(self):
|
||||
if hasattr(self, 'ArgDict'):
|
||||
return self.ArgDict
|
||||
self.ArgDict = {}
|
||||
for arg in self.Args:
|
||||
if len(arg) == 2:
|
||||
if arg[0][0] == 'DebugLoc':
|
||||
dbgidx = 0
|
||||
else:
|
||||
assert(arg[1][0] == 'DebugLoc')
|
||||
dbgidx = 1
|
||||
|
||||
key = arg[1 - dbgidx][0]
|
||||
entry = (arg[1 - dbgidx][1], arg[dbgidx][1])
|
||||
else:
|
||||
arg = arg[0]
|
||||
key = arg[0]
|
||||
entry = (arg[1], )
|
||||
|
||||
self.ArgDict[key] = entry
|
||||
return self.ArgDict
|
||||
|
||||
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)
|
||||
values = [self.getArgString(mapping) for mapping in self.Args]
|
||||
return "".join(values)
|
||||
|
||||
@property
|
||||
def RelativeHotness(self):
|
||||
if self.max_hotness:
|
||||
return "{0:.2f}%".format(self.Hotness * 100. / self.max_hotness)
|
||||
else:
|
||||
return ''
|
||||
|
||||
@property
|
||||
def key(self):
|
||||
return (self.__class__, self.PassWithDiffPrefix, self.Name, self.File,
|
||||
self.Line, self.Column, self.Function, self.Args)
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.key)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.key == other.key
|
||||
|
||||
def __repr__(self):
|
||||
return str(self.key)
|
||||
|
||||
|
||||
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"
|
||||
|
||||
|
||||
def get_remarks(input_file):
|
||||
max_hotness = 0
|
||||
all_remarks = dict()
|
||||
file_remarks = defaultdict(functools.partial(defaultdict, list))
|
||||
|
||||
with open(input_file) as f:
|
||||
docs = yaml.load_all(f, Loader=Loader)
|
||||
for remark in docs:
|
||||
remark.canonicalize()
|
||||
# Avoid remarks withoug debug location or if they are duplicated
|
||||
if not hasattr(remark, 'DebugLoc') or remark.key in all_remarks:
|
||||
continue
|
||||
all_remarks[remark.key] = remark
|
||||
|
||||
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
|
||||
|
||||
|
||||
def gather_results(filenames, num_jobs, should_print_progress):
|
||||
if should_print_progress:
|
||||
print('Reading YAML files...')
|
||||
if not Remark.demangler_proc:
|
||||
Remark.set_demangler(Remark.default_demangler)
|
||||
remarks = optpmap.pmap(
|
||||
get_remarks, filenames, num_jobs, should_print_progress)
|
||||
max_hotness = max(entry[0] for entry in remarks)
|
||||
|
||||
def merge_file_remarks(file_remarks_job, all_remarks, merged):
|
||||
for filename, d in iteritems(file_remarks_job):
|
||||
for line, remarks in iteritems(d):
|
||||
for remark in remarks:
|
||||
# Bring max_hotness into the remarks so that
|
||||
# RelativeHotness does not depend on an external global.
|
||||
remark.max_hotness = max_hotness
|
||||
if remark.key not in all_remarks:
|
||||
merged[filename][line].append(remark)
|
||||
|
||||
all_remarks = dict()
|
||||
file_remarks = defaultdict(functools.partial(defaultdict, list))
|
||||
for _, all_remarks_job, file_remarks_job in remarks:
|
||||
merge_file_remarks(file_remarks_job, all_remarks, file_remarks)
|
||||
all_remarks.update(all_remarks_job)
|
||||
|
||||
return all_remarks, file_remarks, max_hotness != 0
|
||||
|
||||
|
||||
def find_opt_files(*dirs_or_files):
|
||||
all = []
|
||||
for dir_or_file in dirs_or_files:
|
||||
if os.path.isfile(dir_or_file):
|
||||
all.append(dir_or_file)
|
||||
else:
|
||||
for dir, subdirs, files in os.walk(dir_or_file):
|
||||
# Exclude mounted directories and symlinks (os.walk default).
|
||||
subdirs[:] = [d for d in subdirs
|
||||
if not os.path.ismount(os.path.join(dir, d))]
|
||||
for file in files:
|
||||
if fnmatch.fnmatch(file, "*.opt.yaml"):
|
||||
all.append(os.path.join(dir, file))
|
||||
return all
|
208
external/llvm/tools/opt-viewer/style.css
vendored
208
external/llvm/tools/opt-viewer/style.css
vendored
@ -1,208 +0,0 @@
|
||||
.source {
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.source td {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.red {
|
||||
background-color: #ffd0d0;
|
||||
}
|
||||
.cyan {
|
||||
background-color: cyan;
|
||||
}
|
||||
body {
|
||||
font-family: -apple-system, sans-serif;
|
||||
}
|
||||
pre {
|
||||
margin-top: 0px !important;
|
||||
margin-bottom: 0px !important;
|
||||
}
|
||||
.source-name-title {
|
||||
padding: 5px 10px;
|
||||
border-bottom: 1px solid #dbdbdb;
|
||||
background-color: #eee;
|
||||
line-height: 35px;
|
||||
}
|
||||
.centered {
|
||||
display: table;
|
||||
margin-left: left;
|
||||
margin-right: auto;
|
||||
border: 1px solid #dbdbdb;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.expansion-view {
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
margin-left: 0px;
|
||||
margin-top: 5px;
|
||||
margin-right: 5px;
|
||||
margin-bottom: 5px;
|
||||
border: 1px solid #dbdbdb;
|
||||
border-radius: 3px;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.light-row {
|
||||
background: #ffffff;
|
||||
border: 1px solid #dbdbdb;
|
||||
}
|
||||
.column-entry {
|
||||
text-align: right;
|
||||
}
|
||||
.column-entry-left {
|
||||
text-align: left;
|
||||
}
|
||||
.column-entry-white {
|
||||
text-align: right;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
.column-entry-red {
|
||||
text-align: right;
|
||||
background-color: #ffd0d0;
|
||||
}
|
||||
.column-entry-green {
|
||||
text-align: right;
|
||||
background-color: #d0ffd0;
|
||||
}
|
||||
.column-entry-yellow {
|
||||
text-align: left;
|
||||
background-color: #ffe1a6;
|
||||
}
|
||||
.column-entry-0 {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
.column-entry-1 {
|
||||
background-color: #eeeeee;
|
||||
}
|
||||
.line-number {
|
||||
text-align: right;
|
||||
color: #aaa;
|
||||
}
|
||||
.covered-line {
|
||||
text-align: right;
|
||||
color: #0080ff;
|
||||
}
|
||||
.uncovered-line {
|
||||
text-align: right;
|
||||
color: #ff3300;
|
||||
}
|
||||
.tooltip {
|
||||
position: relative;
|
||||
display: inline;
|
||||
background-color: #b3e6ff;
|
||||
text-decoration: none;
|
||||
}
|
||||
.tooltip span.tooltip-content {
|
||||
position: absolute;
|
||||
width: 100px;
|
||||
margin-left: -50px;
|
||||
color: #FFFFFF;
|
||||
background: #000000;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
visibility: hidden;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.tooltip span.tooltip-content:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
margin-left: -8px;
|
||||
width: 0; height: 0;
|
||||
border-top: 8px solid #000000;
|
||||
border-right: 8px solid transparent;
|
||||
border-left: 8px solid transparent;
|
||||
}
|
||||
:hover.tooltip span.tooltip-content {
|
||||
visibility: visible;
|
||||
opacity: 0.8;
|
||||
bottom: 30px;
|
||||
left: 50%;
|
||||
z-index: 999;
|
||||
}
|
||||
th, td {
|
||||
vertical-align: top;
|
||||
padding: 2px 5px;
|
||||
border-collapse: collapse;
|
||||
border-right: solid 1px #eee;
|
||||
border-left: solid 1px #eee;
|
||||
}
|
||||
td:first-child {
|
||||
border-left: none;
|
||||
}
|
||||
td:last-child {
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
/* Generated with pygmentize -S colorful -f html >> style.css */
|
||||
|
||||
.hll { background-color: #ffffcc }
|
||||
.c { color: #888888 } /* Comment */
|
||||
.err { color: #FF0000; background-color: #FFAAAA } /* Error */
|
||||
.k { color: #008800; font-weight: bold } /* Keyword */
|
||||
.o { color: #333333 } /* Operator */
|
||||
.ch { color: #888888 } /* Comment.Hashbang */
|
||||
.cm { color: #888888 } /* Comment.Multiline */
|
||||
.cp { color: #557799 } /* Comment.Preproc */
|
||||
.cpf { color: #888888 } /* Comment.PreprocFile */
|
||||
.c1 { color: #888888 } /* Comment.Single */
|
||||
.cs { color: #cc0000; font-weight: bold } /* Comment.Special */
|
||||
.gd { color: #A00000 } /* Generic.Deleted */
|
||||
.ge { font-style: italic } /* Generic.Emph */
|
||||
.gr { color: #FF0000 } /* Generic.Error */
|
||||
.gh { color: #000080; font-weight: bold } /* Generic.Heading */
|
||||
.gi { color: #00A000 } /* Generic.Inserted */
|
||||
.go { color: #888888 } /* Generic.Output */
|
||||
.gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
|
||||
.gs { font-weight: bold } /* Generic.Strong */
|
||||
.gu { color: #800080; font-weight: bold } /* Generic.Subheading */
|
||||
.gt { color: #0044DD } /* Generic.Traceback */
|
||||
.kc { color: #008800; font-weight: bold } /* Keyword.Constant */
|
||||
.kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
|
||||
.kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
|
||||
.kp { color: #003388; font-weight: bold } /* Keyword.Pseudo */
|
||||
.kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
|
||||
.kt { color: #333399; font-weight: bold } /* Keyword.Type */
|
||||
.m { color: #6600EE; font-weight: bold } /* Literal.Number */
|
||||
.s { background-color: #fff0f0 } /* Literal.String */
|
||||
.na { color: #0000CC } /* Name.Attribute */
|
||||
.nb { color: #007020 } /* Name.Builtin */
|
||||
.nc { color: #BB0066; font-weight: bold } /* Name.Class */
|
||||
.no { color: #003366; font-weight: bold } /* Name.Constant */
|
||||
.nd { color: #555555; font-weight: bold } /* Name.Decorator */
|
||||
.ni { color: #880000; font-weight: bold } /* Name.Entity */
|
||||
.ne { color: #FF0000; font-weight: bold } /* Name.Exception */
|
||||
.nf { color: #0066BB; font-weight: bold } /* Name.Function */
|
||||
.nl { color: #997700; font-weight: bold } /* Name.Label */
|
||||
.nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
|
||||
.nt { color: #007700 } /* Name.Tag */
|
||||
.nv { color: #996633 } /* Name.Variable */
|
||||
.ow { color: #000000; font-weight: bold } /* Operator.Word */
|
||||
.w { color: #bbbbbb } /* Text.Whitespace */
|
||||
.mb { color: #6600EE; font-weight: bold } /* Literal.Number.Bin */
|
||||
.mf { color: #6600EE; font-weight: bold } /* Literal.Number.Float */
|
||||
.mh { color: #005588; font-weight: bold } /* Literal.Number.Hex */
|
||||
.mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
|
||||
.mo { color: #4400EE; font-weight: bold } /* Literal.Number.Oct */
|
||||
.sb { background-color: #fff0f0 } /* Literal.String.Backtick */
|
||||
.sc { color: #0044DD } /* Literal.String.Char */
|
||||
.sd { color: #DD4422 } /* Literal.String.Doc */
|
||||
.s2 { background-color: #fff0f0 } /* Literal.String.Double */
|
||||
.se { color: #666666; font-weight: bold; background-color: #fff0f0 } /* Literal.String.Escape */
|
||||
.sh { background-color: #fff0f0 } /* Literal.String.Heredoc */
|
||||
.si { background-color: #eeeeee } /* Literal.String.Interpol */
|
||||
.sx { color: #DD2200; background-color: #fff0f0 } /* Literal.String.Other */
|
||||
.sr { color: #000000; background-color: #fff0ff } /* Literal.String.Regex */
|
||||
.s1 { background-color: #fff0f0 } /* Literal.String.Single */
|
||||
.ss { color: #AA6600 } /* Literal.String.Symbol */
|
||||
.bp { color: #007020 } /* Name.Builtin.Pseudo */
|
||||
.vc { color: #336699 } /* Name.Variable.Class */
|
||||
.vg { color: #dd7700; font-weight: bold } /* Name.Variable.Global */
|
||||
.vi { color: #3333BB } /* Name.Variable.Instance */
|
||||
.il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
|
Reference in New Issue
Block a user