xref: /llvm-project/llvm/tools/opt-viewer/opt-viewer.py (revision b71edfaa4ec3c998aadb35255ce2f60bba2940b0)
12f2feebfSReid Kleckner#!/usr/bin/env python
22f2feebfSReid Kleckner
32f2feebfSReid Klecknerfrom __future__ import print_function
42f2feebfSReid Kleckner
52f2feebfSReid Klecknerimport argparse
62f2feebfSReid Klecknerimport errno
72f2feebfSReid Klecknerimport functools
84b428e8fSGianfranco Costamagnaimport html
943d9f2d1SYuanfang Chenimport io
102f2feebfSReid Klecknerfrom multiprocessing import cpu_count
112f2feebfSReid Klecknerimport os.path
122f2feebfSReid Klecknerimport re
132f2feebfSReid Klecknerimport shutil
142f2feebfSReid Klecknerimport sys
152f2feebfSReid Kleckner
162f2feebfSReid Klecknerfrom pygments import highlight
172f2feebfSReid Klecknerfrom pygments.lexers.c_cpp import CppLexer
182f2feebfSReid Klecknerfrom pygments.formatters import HtmlFormatter
192f2feebfSReid Kleckner
202f2feebfSReid Klecknerimport optpmap
212f2feebfSReid Klecknerimport optrecord
222f2feebfSReid Kleckner
232f2feebfSReid Kleckner
24*b71edfaaSTobias Hietadesc = """Generate HTML output to visualize optimization records from the YAML files
252f2feebfSReid Klecknergenerated with -fsave-optimization-record and -fdiagnostics-show-hotness.
262f2feebfSReid Kleckner
27*b71edfaaSTobias HietaThe tools requires PyYAML and Pygments Python packages."""
282f2feebfSReid Kleckner
292f2feebfSReid Kleckner
302f2feebfSReid Kleckner# This allows passing the global context to the child processes.
312f2feebfSReid Klecknerclass Context:
322f2feebfSReid Kleckner    def __init__(self, caller_loc=dict()):
332f2feebfSReid Kleckner        # Map function names to their source location for function where inlining happened
342f2feebfSReid Kleckner        self.caller_loc = caller_loc
352f2feebfSReid Kleckner
36*b71edfaaSTobias Hieta
372f2feebfSReid Klecknercontext = Context()
382f2feebfSReid Kleckner
39*b71edfaaSTobias Hieta
402f2feebfSReid Klecknerdef suppress(remark):
41*b71edfaaSTobias Hieta    if remark.Name == "sil.Specialized":
42*b71edfaaSTobias Hieta        return remark.getArgDict()["Function"][0].startswith('"Swift.')
43*b71edfaaSTobias Hieta    elif remark.Name == "sil.Inlined":
44*b71edfaaSTobias Hieta        return remark.getArgDict()["Callee"][0].startswith(
45*b71edfaaSTobias Hieta            ('"Swift.', '"specialized Swift.')
46*b71edfaaSTobias Hieta        )
472f2feebfSReid Kleckner    return False
482f2feebfSReid Kleckner
49*b71edfaaSTobias Hieta
502f2feebfSReid Klecknerclass SourceFileRenderer:
512f2feebfSReid Kleckner    def __init__(self, source_dir, output_dir, filename, no_highlight):
522f2feebfSReid Kleckner        self.filename = filename
532f2feebfSReid Kleckner        existing_filename = None
542f2feebfSReid Kleckner        if os.path.exists(filename):
552f2feebfSReid Kleckner            existing_filename = filename
562f2feebfSReid Kleckner        else:
572f2feebfSReid Kleckner            fn = os.path.join(source_dir, filename)
582f2feebfSReid Kleckner            if os.path.exists(fn):
592f2feebfSReid Kleckner                existing_filename = fn
602f2feebfSReid Kleckner
612f2feebfSReid Kleckner        self.no_highlight = no_highlight
62*b71edfaaSTobias Hieta        self.stream = io.open(
63*b71edfaaSTobias Hieta            os.path.join(output_dir, optrecord.html_file_name(filename)),
64*b71edfaaSTobias Hieta            "w",
65*b71edfaaSTobias Hieta            encoding="utf-8",
66*b71edfaaSTobias Hieta        )
672f2feebfSReid Kleckner        if existing_filename:
68*b71edfaaSTobias Hieta            self.source_stream = io.open(existing_filename, encoding="utf-8")
692f2feebfSReid Kleckner        else:
702f2feebfSReid Kleckner            self.source_stream = None
71*b71edfaaSTobias Hieta            print(
72*b71edfaaSTobias Hieta                """
732f2feebfSReid Kleckner<html>
742f2feebfSReid Kleckner<h1>Unable to locate file {}</h1>
752f2feebfSReid Kleckner</html>
76*b71edfaaSTobias Hieta            """.format(
77*b71edfaaSTobias Hieta                    filename
78*b71edfaaSTobias Hieta                ),
79*b71edfaaSTobias Hieta                file=self.stream,
80*b71edfaaSTobias Hieta            )
812f2feebfSReid Kleckner
82*b71edfaaSTobias Hieta        self.html_formatter = HtmlFormatter(encoding="utf-8")
832f2feebfSReid Kleckner        self.cpp_lexer = CppLexer(stripnl=False)
842f2feebfSReid Kleckner
852f2feebfSReid Kleckner    def render_source_lines(self, stream, line_remarks):
862f2feebfSReid Kleckner        file_text = stream.read()
872f2feebfSReid Kleckner
882f2feebfSReid Kleckner        if self.no_highlight:
892f2feebfSReid Kleckner            html_highlighted = file_text
902f2feebfSReid Kleckner        else:
91*b71edfaaSTobias Hieta            html_highlighted = highlight(file_text, self.cpp_lexer, self.html_formatter)
922f2feebfSReid Kleckner
932f2feebfSReid Kleckner            # Note that the API is different between Python 2 and 3.  On
942f2feebfSReid Kleckner            # Python 3, pygments.highlight() returns a bytes object, so we
952f2feebfSReid Kleckner            # have to decode.  On Python 2, the output is str but since we
962f2feebfSReid Kleckner            # support unicode characters and the output streams is unicode we
972f2feebfSReid Kleckner            # decode too.
98*b71edfaaSTobias Hieta            html_highlighted = html_highlighted.decode("utf-8")
992f2feebfSReid Kleckner
1002f2feebfSReid Kleckner            # Take off the header and footer, these must be
1012f2feebfSReid Kleckner            #   reapplied line-wise, within the page structure
102*b71edfaaSTobias Hieta            html_highlighted = html_highlighted.replace(
103*b71edfaaSTobias Hieta                '<div class="highlight"><pre>', ""
104*b71edfaaSTobias Hieta            )
105*b71edfaaSTobias Hieta            html_highlighted = html_highlighted.replace("</pre></div>", "")
1062f2feebfSReid Kleckner
107*b71edfaaSTobias Hieta        for (linenum, html_line) in enumerate(html_highlighted.split("\n"), start=1):
108*b71edfaaSTobias Hieta            print(
109*b71edfaaSTobias Hieta                """
1102f2feebfSReid Kleckner<tr>
1112f2feebfSReid Kleckner<td><a name=\"L{linenum}\">{linenum}</a></td>
1122f2feebfSReid Kleckner<td></td>
1132f2feebfSReid Kleckner<td></td>
1142f2feebfSReid Kleckner<td><div class="highlight"><pre>{html_line}</pre></div></td>
115*b71edfaaSTobias Hieta</tr>""".format(
116*b71edfaaSTobias Hieta                    **locals()
117*b71edfaaSTobias Hieta                ),
118*b71edfaaSTobias Hieta                file=self.stream,
119*b71edfaaSTobias Hieta            )
1202f2feebfSReid Kleckner
1212f2feebfSReid Kleckner            for remark in line_remarks.get(linenum, []):
1222f2feebfSReid Kleckner                if not suppress(remark):
1232f2feebfSReid Kleckner                    self.render_inline_remarks(remark, html_line)
1242f2feebfSReid Kleckner
1252f2feebfSReid Kleckner    def render_inline_remarks(self, r, line):
1262f2feebfSReid Kleckner        inlining_context = r.DemangledFunctionName
1272f2feebfSReid Kleckner        dl = context.caller_loc.get(r.Function)
1282f2feebfSReid Kleckner        if dl:
1292f2feebfSReid Kleckner            dl_dict = dict(list(dl))
130*b71edfaaSTobias Hieta            link = optrecord.make_link(dl_dict["File"], dl_dict["Line"] - 2)
131*b71edfaaSTobias Hieta            inlining_context = "<a href={link}>{r.DemangledFunctionName}</a>".format(
132*b71edfaaSTobias Hieta                **locals()
133*b71edfaaSTobias Hieta            )
1342f2feebfSReid Kleckner
1352f2feebfSReid Kleckner        # Column is the number of characters *including* tabs, keep those and
1362f2feebfSReid Kleckner        # replace everything else with spaces.
1372f2feebfSReid Kleckner        indent = line[: max(r.Column, 1) - 1]
138*b71edfaaSTobias Hieta        indent = re.sub("\S", " ", indent)
1392f2feebfSReid Kleckner
1402f2feebfSReid Kleckner        # Create expanded message and link if we have a multiline message.
141*b71edfaaSTobias Hieta        lines = r.message.split("\n")
1422f2feebfSReid Kleckner        if len(lines) > 1:
1432f2feebfSReid Kleckner            expand_link = '<a style="text-decoration: none;" href="" onclick="toggleExpandedMessage(this); return false;">+</a>'
1442f2feebfSReid Kleckner            message = lines[0]
145*b71edfaaSTobias Hieta            expand_message = """
1462f2feebfSReid Kleckner<div class="full-info" style="display:none;">
1472f2feebfSReid Kleckner  <div class="col-left"><pre style="display:inline">{}</pre></div>
1482f2feebfSReid Kleckner  <div class="expanded col-left"><pre>{}</pre></div>
149*b71edfaaSTobias Hieta</div>""".format(
150*b71edfaaSTobias Hieta                indent, "\n".join(lines[1:])
151*b71edfaaSTobias Hieta            )
1522f2feebfSReid Kleckner        else:
153*b71edfaaSTobias Hieta            expand_link = ""
154*b71edfaaSTobias Hieta            expand_message = ""
1552f2feebfSReid Kleckner            message = r.message
156*b71edfaaSTobias Hieta        print(
157*b71edfaaSTobias Hieta            """
1582f2feebfSReid Kleckner<tr>
1592f2feebfSReid Kleckner<td></td>
1602f2feebfSReid Kleckner<td>{r.RelativeHotness}</td>
1612f2feebfSReid Kleckner<td class=\"column-entry-{r.color}\">{r.PassWithDiffPrefix}</td>
1622f2feebfSReid Kleckner<td><pre style="display:inline">{indent}</pre><span class=\"column-entry-yellow\">{expand_link} {message}&nbsp;</span>{expand_message}</td>
1632f2feebfSReid Kleckner<td class=\"column-entry-yellow\">{inlining_context}</td>
164*b71edfaaSTobias Hieta</tr>""".format(
165*b71edfaaSTobias Hieta                **locals()
166*b71edfaaSTobias Hieta            ),
167*b71edfaaSTobias Hieta            file=self.stream,
168*b71edfaaSTobias Hieta        )
1692f2feebfSReid Kleckner
1702f2feebfSReid Kleckner    def render(self, line_remarks):
1712f2feebfSReid Kleckner        if not self.source_stream:
1722f2feebfSReid Kleckner            return
1732f2feebfSReid Kleckner
174*b71edfaaSTobias Hieta        print(
175*b71edfaaSTobias Hieta            """
1762f2feebfSReid Kleckner<html>
1772f2feebfSReid Kleckner<title>{}</title>
1782f2feebfSReid Kleckner<meta charset="utf-8" />
1792f2feebfSReid Kleckner<head>
1802f2feebfSReid Kleckner<link rel='stylesheet' type='text/css' href='style.css'>
1812f2feebfSReid Kleckner<script type="text/javascript">
1822f2feebfSReid Kleckner/* Simple helper to show/hide the expanded message of a remark. */
1832f2feebfSReid Klecknerfunction toggleExpandedMessage(e) {{
1842f2feebfSReid Kleckner  var FullTextElems = e.parentElement.parentElement.getElementsByClassName("full-info");
1852f2feebfSReid Kleckner  if (!FullTextElems || FullTextElems.length < 1) {{
1862f2feebfSReid Kleckner      return false;
1872f2feebfSReid Kleckner  }}
1882f2feebfSReid Kleckner  var FullText = FullTextElems[0];
1892f2feebfSReid Kleckner  if (FullText.style.display == 'none') {{
1902f2feebfSReid Kleckner    e.innerHTML = '-';
1912f2feebfSReid Kleckner    FullText.style.display = 'block';
1922f2feebfSReid Kleckner  }} else {{
1932f2feebfSReid Kleckner    e.innerHTML = '+';
1942f2feebfSReid Kleckner    FullText.style.display = 'none';
1952f2feebfSReid Kleckner  }}
1962f2feebfSReid Kleckner}}
1972f2feebfSReid Kleckner</script>
1982f2feebfSReid Kleckner</head>
1992f2feebfSReid Kleckner<body>
2002f2feebfSReid Kleckner<div class="centered">
2012f2feebfSReid Kleckner<table class="source">
2022f2feebfSReid Kleckner<thead>
2032f2feebfSReid Kleckner<tr>
2042f2feebfSReid Kleckner<th style="width: 2%">Line</td>
2052f2feebfSReid Kleckner<th style="width: 3%">Hotness</td>
2062f2feebfSReid Kleckner<th style="width: 10%">Optimization</td>
2072f2feebfSReid Kleckner<th style="width: 70%">Source</td>
2082f2feebfSReid Kleckner<th style="width: 15%">Inline Context</td>
2092f2feebfSReid Kleckner</tr>
2102f2feebfSReid Kleckner</thead>
211*b71edfaaSTobias Hieta<tbody>""".format(
212*b71edfaaSTobias Hieta                os.path.basename(self.filename)
213*b71edfaaSTobias Hieta            ),
214*b71edfaaSTobias Hieta            file=self.stream,
215*b71edfaaSTobias Hieta        )
2162f2feebfSReid Kleckner        self.render_source_lines(self.source_stream, line_remarks)
2172f2feebfSReid Kleckner
218*b71edfaaSTobias Hieta        print(
219*b71edfaaSTobias Hieta            """
2202f2feebfSReid Kleckner</tbody>
2212f2feebfSReid Kleckner</table>
2222f2feebfSReid Kleckner</body>
223*b71edfaaSTobias Hieta</html>""",
224*b71edfaaSTobias Hieta            file=self.stream,
225*b71edfaaSTobias Hieta        )
2262f2feebfSReid Kleckner
2272f2feebfSReid Kleckner
2282f2feebfSReid Klecknerclass IndexRenderer:
229*b71edfaaSTobias Hieta    def __init__(
230*b71edfaaSTobias Hieta        self, output_dir, should_display_hotness, max_hottest_remarks_on_index
231*b71edfaaSTobias Hieta    ):
232*b71edfaaSTobias Hieta        self.stream = io.open(
233*b71edfaaSTobias Hieta            os.path.join(output_dir, "index.html"), "w", encoding="utf-8"
234*b71edfaaSTobias Hieta        )
2352f2feebfSReid Kleckner        self.should_display_hotness = should_display_hotness
2362f2feebfSReid Kleckner        self.max_hottest_remarks_on_index = max_hottest_remarks_on_index
2372f2feebfSReid Kleckner
2382f2feebfSReid Kleckner    def render_entry(self, r, odd):
2394b428e8fSGianfranco Costamagna        escaped_name = html.escape(r.DemangledFunctionName)
240*b71edfaaSTobias Hieta        print(
241*b71edfaaSTobias Hieta            """
2422f2feebfSReid Kleckner<tr>
2432f2feebfSReid Kleckner<td class=\"column-entry-{odd}\"><a href={r.Link}>{r.DebugLocString}</a></td>
2442f2feebfSReid Kleckner<td class=\"column-entry-{odd}\">{r.RelativeHotness}</td>
2452f2feebfSReid Kleckner<td class=\"column-entry-{odd}\">{escaped_name}</td>
2462f2feebfSReid Kleckner<td class=\"column-entry-{r.color}\">{r.PassWithDiffPrefix}</td>
247*b71edfaaSTobias Hieta</tr>""".format(
248*b71edfaaSTobias Hieta                **locals()
249*b71edfaaSTobias Hieta            ),
250*b71edfaaSTobias Hieta            file=self.stream,
251*b71edfaaSTobias Hieta        )
2522f2feebfSReid Kleckner
2532f2feebfSReid Kleckner    def render(self, all_remarks):
254*b71edfaaSTobias Hieta        print(
255*b71edfaaSTobias Hieta            """
2562f2feebfSReid Kleckner<html>
2572f2feebfSReid Kleckner<meta charset="utf-8" />
2582f2feebfSReid Kleckner<head>
2592f2feebfSReid Kleckner<link rel='stylesheet' type='text/css' href='style.css'>
2602f2feebfSReid Kleckner</head>
2612f2feebfSReid Kleckner<body>
2622f2feebfSReid Kleckner<div class="centered">
2632f2feebfSReid Kleckner<table>
2642f2feebfSReid Kleckner<tr>
2652f2feebfSReid Kleckner<td>Source Location</td>
2662f2feebfSReid Kleckner<td>Hotness</td>
2672f2feebfSReid Kleckner<td>Function</td>
2682f2feebfSReid Kleckner<td>Pass</td>
269*b71edfaaSTobias Hieta</tr>""",
270*b71edfaaSTobias Hieta            file=self.stream,
271*b71edfaaSTobias Hieta        )
2722f2feebfSReid Kleckner
2732f2feebfSReid Kleckner        max_entries = None
2742f2feebfSReid Kleckner        if self.should_display_hotness:
2752f2feebfSReid Kleckner            max_entries = self.max_hottest_remarks_on_index
2762f2feebfSReid Kleckner
2772f2feebfSReid Kleckner        for i, remark in enumerate(all_remarks[:max_entries]):
2782f2feebfSReid Kleckner            if not suppress(remark):
2792f2feebfSReid Kleckner                self.render_entry(remark, i % 2)
280*b71edfaaSTobias Hieta        print(
281*b71edfaaSTobias Hieta            """
2822f2feebfSReid Kleckner</table>
2832f2feebfSReid Kleckner</body>
284*b71edfaaSTobias Hieta</html>""",
285*b71edfaaSTobias Hieta            file=self.stream,
286*b71edfaaSTobias Hieta        )
2872f2feebfSReid Kleckner
2882f2feebfSReid Kleckner
2892f2feebfSReid Klecknerdef _render_file(source_dir, output_dir, ctx, no_highlight, entry, filter_):
2902f2feebfSReid Kleckner    global context
2912f2feebfSReid Kleckner    context = ctx
2922f2feebfSReid Kleckner    filename, remarks = entry
2932f2feebfSReid Kleckner    SourceFileRenderer(source_dir, output_dir, filename, no_highlight).render(remarks)
2942f2feebfSReid Kleckner
2952f2feebfSReid Kleckner
2962f2feebfSReid Klecknerdef map_remarks(all_remarks):
2972f2feebfSReid Kleckner    # Set up a map between function names and their source location for
2982f2feebfSReid Kleckner    # function where inlining happened
2992f2feebfSReid Kleckner    for remark in optrecord.itervalues(all_remarks):
300*b71edfaaSTobias Hieta        if (
301*b71edfaaSTobias Hieta            isinstance(remark, optrecord.Passed)
302*b71edfaaSTobias Hieta            and remark.Pass == "inline"
303*b71edfaaSTobias Hieta            and remark.Name == "Inlined"
304*b71edfaaSTobias Hieta        ):
3052f2feebfSReid Kleckner            for arg in remark.Args:
3062f2feebfSReid Kleckner                arg_dict = dict(list(arg))
307*b71edfaaSTobias Hieta                caller = arg_dict.get("Caller")
3082f2feebfSReid Kleckner                if caller:
3092f2feebfSReid Kleckner                    try:
310*b71edfaaSTobias Hieta                        context.caller_loc[caller] = arg_dict["DebugLoc"]
3112f2feebfSReid Kleckner                    except KeyError:
3122f2feebfSReid Kleckner                        pass
3132f2feebfSReid Kleckner
3142f2feebfSReid Kleckner
315*b71edfaaSTobias Hietadef generate_report(
316*b71edfaaSTobias Hieta    all_remarks,
3172f2feebfSReid Kleckner    file_remarks,
3182f2feebfSReid Kleckner    source_dir,
3192f2feebfSReid Kleckner    output_dir,
3202f2feebfSReid Kleckner    no_highlight,
3212f2feebfSReid Kleckner    should_display_hotness,
3222f2feebfSReid Kleckner    max_hottest_remarks_on_index,
3232f2feebfSReid Kleckner    num_jobs,
324*b71edfaaSTobias Hieta    should_print_progress,
325*b71edfaaSTobias Hieta):
3262f2feebfSReid Kleckner    try:
3272f2feebfSReid Kleckner        os.makedirs(output_dir)
3282f2feebfSReid Kleckner    except OSError as e:
3292f2feebfSReid Kleckner        if e.errno == errno.EEXIST and os.path.isdir(output_dir):
3302f2feebfSReid Kleckner            pass
3312f2feebfSReid Kleckner        else:
3322f2feebfSReid Kleckner            raise
3332f2feebfSReid Kleckner
3342f2feebfSReid Kleckner    if should_print_progress:
335*b71edfaaSTobias Hieta        print("Rendering index page...")
3362f2feebfSReid Kleckner    if should_display_hotness:
337*b71edfaaSTobias Hieta        sorted_remarks = sorted(
338*b71edfaaSTobias Hieta            optrecord.itervalues(all_remarks),
339*b71edfaaSTobias Hieta            key=lambda r: (
340*b71edfaaSTobias Hieta                r.Hotness,
341*b71edfaaSTobias Hieta                r.File,
342*b71edfaaSTobias Hieta                r.Line,
343*b71edfaaSTobias Hieta                r.Column,
344*b71edfaaSTobias Hieta                r.PassWithDiffPrefix,
345*b71edfaaSTobias Hieta                r.yaml_tag,
346*b71edfaaSTobias Hieta                r.Function,
347*b71edfaaSTobias Hieta            ),
348*b71edfaaSTobias Hieta            reverse=True,
349*b71edfaaSTobias Hieta        )
3502f2feebfSReid Kleckner    else:
351*b71edfaaSTobias Hieta        sorted_remarks = sorted(
352*b71edfaaSTobias Hieta            optrecord.itervalues(all_remarks),
353*b71edfaaSTobias Hieta            key=lambda r: (
354*b71edfaaSTobias Hieta                r.File,
355*b71edfaaSTobias Hieta                r.Line,
356*b71edfaaSTobias Hieta                r.Column,
357*b71edfaaSTobias Hieta                r.PassWithDiffPrefix,
358*b71edfaaSTobias Hieta                r.yaml_tag,
359*b71edfaaSTobias Hieta                r.Function,
360*b71edfaaSTobias Hieta            ),
361*b71edfaaSTobias Hieta        )
362*b71edfaaSTobias Hieta    IndexRenderer(
363*b71edfaaSTobias Hieta        output_dir, should_display_hotness, max_hottest_remarks_on_index
364*b71edfaaSTobias Hieta    ).render(sorted_remarks)
3652f2feebfSReid Kleckner
366*b71edfaaSTobias Hieta    shutil.copy(
367*b71edfaaSTobias Hieta        os.path.join(os.path.dirname(os.path.realpath(__file__)), "style.css"),
368*b71edfaaSTobias Hieta        output_dir,
369*b71edfaaSTobias Hieta    )
3702f2feebfSReid Kleckner
371*b71edfaaSTobias Hieta    _render_file_bound = functools.partial(
372*b71edfaaSTobias Hieta        _render_file, source_dir, output_dir, context, no_highlight
373*b71edfaaSTobias Hieta    )
3742f2feebfSReid Kleckner    if should_print_progress:
375*b71edfaaSTobias Hieta        print("Rendering HTML files...")
376*b71edfaaSTobias Hieta    optpmap.pmap(
377*b71edfaaSTobias Hieta        _render_file_bound, file_remarks.items(), num_jobs, should_print_progress
378*b71edfaaSTobias Hieta    )
3792f2feebfSReid Kleckner
3802f2feebfSReid Kleckner
3812f2feebfSReid Klecknerdef main():
3822f2feebfSReid Kleckner    parser = argparse.ArgumentParser(description=desc)
3832f2feebfSReid Kleckner    parser.add_argument(
384*b71edfaaSTobias Hieta        "yaml_dirs_or_files",
385*b71edfaaSTobias Hieta        nargs="+",
386*b71edfaaSTobias Hieta        help="List of optimization record files or directories searched "
387*b71edfaaSTobias Hieta        "for optimization record files.",
388*b71edfaaSTobias Hieta    )
3892f2feebfSReid Kleckner    parser.add_argument(
390*b71edfaaSTobias Hieta        "--output-dir",
391*b71edfaaSTobias Hieta        "-o",
392*b71edfaaSTobias Hieta        default="html",
393*b71edfaaSTobias Hieta        help="Path to a directory where generated HTML files will be output. "
394*b71edfaaSTobias Hieta        "If the directory does not already exist, it will be created. "
395*b71edfaaSTobias Hieta        '"%(default)s" by default.',
396*b71edfaaSTobias Hieta    )
3972f2feebfSReid Kleckner    parser.add_argument(
398*b71edfaaSTobias Hieta        "--jobs",
399*b71edfaaSTobias Hieta        "-j",
4002f2feebfSReid Kleckner        default=None,
4012f2feebfSReid Kleckner        type=int,
402*b71edfaaSTobias Hieta        help="Max job count (defaults to %(default)s, the current CPU count)",
403*b71edfaaSTobias Hieta    )
404*b71edfaaSTobias Hieta    parser.add_argument("--source-dir", "-s", default="", help="set source directory")
4052f2feebfSReid Kleckner    parser.add_argument(
406*b71edfaaSTobias Hieta        "--no-progress-indicator",
407*b71edfaaSTobias Hieta        "-n",
408*b71edfaaSTobias Hieta        action="store_true",
4092f2feebfSReid Kleckner        default=False,
410*b71edfaaSTobias Hieta        help="Do not display any indicator of how many YAML files were read "
411*b71edfaaSTobias Hieta        "or rendered into HTML.",
412*b71edfaaSTobias Hieta    )
4132f2feebfSReid Kleckner    parser.add_argument(
414*b71edfaaSTobias Hieta        "--max-hottest-remarks-on-index",
4152f2feebfSReid Kleckner        default=1000,
4162f2feebfSReid Kleckner        type=int,
417*b71edfaaSTobias Hieta        help="Maximum number of the hottest remarks to appear on the index page",
418*b71edfaaSTobias Hieta    )
4192f2feebfSReid Kleckner    parser.add_argument(
420*b71edfaaSTobias Hieta        "--no-highlight",
421*b71edfaaSTobias Hieta        action="store_true",
4222f2feebfSReid Kleckner        default=False,
423*b71edfaaSTobias Hieta        help="Do not use a syntax highlighter when rendering the source code",
424*b71edfaaSTobias Hieta    )
4252f2feebfSReid Kleckner    parser.add_argument(
426*b71edfaaSTobias Hieta        "--demangler",
427*b71edfaaSTobias Hieta        help="Set the demangler to be used (defaults to %s)"
428*b71edfaaSTobias Hieta        % optrecord.Remark.default_demangler,
429*b71edfaaSTobias Hieta    )
4302f2feebfSReid Kleckner
4312f2feebfSReid Kleckner    parser.add_argument(
432*b71edfaaSTobias Hieta        "--filter",
433*b71edfaaSTobias Hieta        default="",
434*b71edfaaSTobias Hieta        help="Only display remarks from passes matching filter expression",
435*b71edfaaSTobias Hieta    )
4362f2feebfSReid Kleckner
4372f2feebfSReid Kleckner    # Do not make this a global variable.  Values needed to be propagated through
4382f2feebfSReid Kleckner    # to individual classes and functions to be portable with multiprocessing across
4392f2feebfSReid Kleckner    # Windows and non-Windows.
4402f2feebfSReid Kleckner    args = parser.parse_args()
4412f2feebfSReid Kleckner
4422f2feebfSReid Kleckner    print_progress = not args.no_progress_indicator
4432f2feebfSReid Kleckner    if args.demangler:
4442f2feebfSReid Kleckner        optrecord.Remark.set_demangler(args.demangler)
4452f2feebfSReid Kleckner
4462f2feebfSReid Kleckner    files = optrecord.find_opt_files(*args.yaml_dirs_or_files)
4472f2feebfSReid Kleckner    if not files:
4482f2feebfSReid Kleckner        parser.error("No *.opt.yaml files found")
4492f2feebfSReid Kleckner        sys.exit(1)
4502f2feebfSReid Kleckner
451*b71edfaaSTobias Hieta    all_remarks, file_remarks, should_display_hotness = optrecord.gather_results(
452*b71edfaaSTobias Hieta        files, args.jobs, print_progress, args.filter
453*b71edfaaSTobias Hieta    )
4542f2feebfSReid Kleckner
4552f2feebfSReid Kleckner    map_remarks(all_remarks)
4562f2feebfSReid Kleckner
457*b71edfaaSTobias Hieta    generate_report(
458*b71edfaaSTobias Hieta        all_remarks,
4592f2feebfSReid Kleckner        file_remarks,
4602f2feebfSReid Kleckner        args.source_dir,
4612f2feebfSReid Kleckner        args.output_dir,
4622f2feebfSReid Kleckner        args.no_highlight,
4632f2feebfSReid Kleckner        should_display_hotness,
4642f2feebfSReid Kleckner        args.max_hottest_remarks_on_index,
4652f2feebfSReid Kleckner        args.jobs,
466*b71edfaaSTobias Hieta        print_progress,
467*b71edfaaSTobias Hieta    )
4682f2feebfSReid Kleckner
469*b71edfaaSTobias Hieta
470*b71edfaaSTobias Hietaif __name__ == "__main__":
4712f2feebfSReid Kleckner    main()
472