#!/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 = {} for line in alloc_data: ident, allocs, calls = line.strip().split(" ") allocs = int(allocs) calls = int(calls) filename, lineno = ident.split(":") lineno = int(lineno) filedata = parsed_data.setdefault(filename, {}) filedata[lineno] = { "total_allocs": allocs, "total_calls": calls, "avg_allocs": allocs / calls, } return parsed_data @click.group() @click.pass_context @click.option("-a", "--alloc-data", type=click.File(), default="src/alloc_data.txt") @click.option("-t", "--type", type=click.Choice(("total", "avg")), default="avg") 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"]) filedata = obj.data[filename] linedata = {lineno: alloc_str(line) for lineno, line in filedata.items()} maxlen = max(len(l) for l in linedata.values()) lineno = 0 for line in open("src/" + filename): lineno += 1 linecount = linedata.get(lineno, "") 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" format_num = lambda l: "{}".format(l[2]) else: field = "avg_allocs" format_num = lambda l: "{:.2f}".format(l[1]) file_sums = _list(obj, field, reverse) 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("