diff options
Diffstat (limited to 'tools/opt-viewer/opt-viewer.py')
| -rwxr-xr-x | tools/opt-viewer/opt-viewer.py | 108 | 
1 files changed, 81 insertions, 27 deletions
diff --git a/tools/opt-viewer/opt-viewer.py b/tools/opt-viewer/opt-viewer.py index 69bcaedb7669..27b36064ced9 100755 --- a/tools/opt-viewer/opt-viewer.py +++ b/tools/opt-viewer/opt-viewer.py @@ -4,12 +4,14 @@ 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 @@ -33,6 +35,13 @@ class Context:  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 @@ -43,7 +52,7 @@ class SourceFileRenderer:              if os.path.exists(fn):                  existing_filename = fn -        self.stream = open(os.path.join(output_dir, optrecord.html_file_name(filename)), 'w') +        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: @@ -59,15 +68,29 @@ class SourceFileRenderer:      def render_source_lines(self, stream, line_remarks):          file_text = stream.read() -        html_highlighted = highlight(file_text, self.cpp_lexer, self.html_formatter) -        # 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>', '') +        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(''' +            print(u'''  <tr>  <td><a name=\"L{linenum}\">{linenum}</a></td>  <td></td> @@ -76,13 +99,15 @@ class SourceFileRenderer:  </tr>'''.format(**locals()), file=self.stream)              for remark in line_remarks.get(linenum, []): -                self.render_inline_remarks(remark, html_line) +                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: -            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 = "<a href={link}>{r.DemangledFunctionName}</a>".format(**locals())          # Column is the number of characters *including* tabs, keep those and @@ -90,7 +115,7 @@ class SourceFileRenderer:          indent = line[:max(r.Column, 1) - 1]          indent = re.sub('\S', ' ', indent) -        print(''' +        print(u'''  <tr>  <td></td>  <td>{r.RelativeHotness}</td> @@ -105,34 +130,40 @@ class SourceFileRenderer:          print('''  <html> +<meta charset="utf-8" />  <head>  <link rel='stylesheet' type='text/css' href='style.css'>  </head>  <body>  <div class="centered"> -<table> +<table class="source"> +<thead>  <tr> -<td>Line</td> -<td>Hotness</td> -<td>Optimization</td> -<td>Source</td> -<td>Inline Context</td> -</tr>''', file=self.stream) +<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): -        self.stream = open(os.path.join(output_dir, 'index.html'), 'w') +    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(''' +        print(u'''  <tr>  <td class=\"column-entry-{odd}\"><a href={r.Link}>{r.DebugLocString}</a></td>  <td class=\"column-entry-{odd}\">{r.RelativeHotness}</td> @@ -143,6 +174,7 @@ class IndexRenderer:      def render(self, all_remarks):          print('''  <html> +<meta charset="utf-8" />  <head>  <link rel='stylesheet' type='text/css' href='style.css'>  </head> @@ -155,8 +187,14 @@ class IndexRenderer:  <td>Function</td>  <td>Pass</td>  </tr>''', file=self.stream) -        for i, remark in enumerate(all_remarks): -            self.render_entry(remark, i % 2) + +        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> @@ -176,10 +214,11 @@ def map_remarks(all_remarks):      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 @@ -211,7 +250,7 @@ def generate_report(all_remarks,          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).render(sorted_remarks) +    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) @@ -238,7 +277,7 @@ if __name__ == '__main__':          type=int,          help='Max job count (defaults to %(default)s, the current CPU count)')      parser.add_argument( -        '-source-dir', +        '--source-dir',          '-s',          default='',          help='set source directory') @@ -249,11 +288,26 @@ if __name__ == '__main__':          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) +    files = optrecord.find_opt_files(*args.yaml_dirs_or_files)      if not files:          parser.error("No *.opt.yaml files found")          sys.exit(1)  | 
