From 62a80e1332836bdf0abc1f16b935f568c48a185b Mon Sep 17 00:00:00 2001 From: Martin Milata Date: Mon, 26 Oct 2020 21:31:10 +0100 Subject: [PATCH] feat(core): tools/alloc.py: generate html --- core/tools/alloc.py | 117 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 103 insertions(+), 14 deletions(-) diff --git a/core/tools/alloc.py b/core/tools/alloc.py index 729acbee1..a50e7c9f6 100755 --- a/core/tools/alloc.py +++ b/core/tools/alloc.py @@ -1,8 +1,11 @@ #!/usr/bin/env python3 +from pathlib import Path from types import SimpleNamespace import click +HERE = Path(__file__).parent.resolve() + def parse_alloc_data(alloc_data): parsed_data = {} @@ -30,17 +33,23 @@ def cli(ctx, alloc_data, type): ctx.obj = SimpleNamespace(data=parse_alloc_data(alloc_data), type=type) +def _normalize_filename(filename): + if filename.startswith("src/"): + return filename[4:] + return filename + + @cli.command() @click.pass_obj @click.argument("filename") def annotate(obj, filename): + filename = _normalize_filename(filename) + if obj.type == "total": alloc_str = lambda line: str(line["total_allocs"]) else: alloc_str = lambda line: "{:.2f}".format(line["avg_allocs"]) - if filename.startswith("src/"): - filename = filename[4:] filedata = obj.data[filename] linedata = {lineno: alloc_str(line) for lineno, line in filedata.items()} @@ -53,30 +62,110 @@ def annotate(obj, filename): print(f"{linecount:>{maxlen}} {line}", end="") +def _list(obj, sort_by="avg_allocs", reverse=False): + return sorted( + ( + ( + filename, + sum(line["avg_allocs"] for line in lines.values()), + sum(line["total_allocs"] for line in lines.values()), + ) + for filename, lines in obj.data.items() + ), + key=lambda x: x[1 if sort_by == "avg_allocs" else 2], + reverse=reverse, + ) + + @cli.command() @click.pass_obj @click.option("-r", "--reverse", is_flag=True) def list(obj, reverse): if obj.type == "total": field = "total_allocs" - field_fmt = "{}" + format_num = lambda l: "{}".format(l[2]) else: field = "avg_allocs" - field_fmt = "{:.2f}" - - file_sums = { - filename: sum(line[field] for line in lines.values()) - for filename, lines in obj.data.items() - } + format_num = lambda l: "{:.2f}".format(l[1]) - maxlen = max(len(field_fmt.format(l)) for l in file_sums.values()) + file_sums = _list(obj, field, reverse) - for filename, file_sum in sorted( - file_sums.items(), key=lambda x: x[1], reverse=reverse - ): - num_str = field_fmt.format(file_sum) + maxlen = max(len(format_num(l)) for l in file_sums) + for l in file_sums: + num_str = format_num(l) + filename = l[0] print(f"{num_str:>{maxlen}} {filename}") +class HtmlTable: + def __init__(self, f): + self.f = f + + def __enter__(self): + self.f.write("") + return self + + def __exit__(self, type, value, traceback): + self.f.write("
") + + def tr(self, *tds): + self.f.write("") + for td in tds: + if isinstance(td, tuple): + self.f.write("{}".format(td[0], td[1])) + else: + self.f.write(f"{td}") + self.f.write("") + + +@cli.command() +@click.pass_obj +@click.argument("htmldir") +def html(obj, htmldir): + file_sums = _list(obj, "total_allocs", reverse=True) + style_grey = "style='color: grey'" + style_right = "style='text-align: right'" + + with open(f"{htmldir}/index.html", "w") as f: + f.write("") + with HtmlTable(f) as table: + table.tr((style_right, "avg"), (style_right, "total"), "") + for filename, avg_sum, total_sum in file_sums: + table.tr( + (style_right, f"{avg_sum:.2f}"), + (style_right, total_sum), + f"{filename}", + ) + f.write("") + + for filename in file_sums: + filename = _normalize_filename(filename[0]) + htmlfile = Path(htmldir) / filename + htmlfile.parent.mkdir(parents=True, exist_ok=True) + + with open(str(htmlfile) + ".html", "w") as f: + filedata = obj.data[filename] + f.write(f"{filename}") + with HtmlTable(f) as table: + table.tr( + (style_grey, "#"), (style_right, "avg"), (style_right, "total"), "" + ) + + lineno = 0 + for line in open(HERE.parent / "src" / filename): + line = line.rstrip("\n").replace(" ", " ") + lineno += 1 + total = filedata.get(lineno, {}).get("total_allocs", 0) + avg = filedata.get(lineno, {}).get("avg_allocs", 0) + + table.tr( + (style_grey, lineno), + (style_right, f"{avg:.2f}"), + (style_right, total), + line, + ) + f.write("") + + if __name__ == "__main__": cli()