diff options
| -rwxr-xr-x | scripts/parse_firrtl_transform_log.py | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/scripts/parse_firrtl_transform_log.py b/scripts/parse_firrtl_transform_log.py new file mode 100755 index 00000000..16ea77cd --- /dev/null +++ b/scripts/parse_firrtl_transform_log.py @@ -0,0 +1,148 @@ +#!/usr/bin/env python3 + +import sys +import os +import re +from itertools import * +from collections import namedtuple +import argparse + +Transform = namedtuple('Transform', ['name', 'children', 'runtime']) + +start_xform_re = re.compile(r'\s*=+\s+Starting\s+Transform\s+(\S+)\s+=+\s*') +finish_xform_re = re.compile(r'\s*=+\s+Finished\s+Transform\s+(\S+)\s+=+\s*') +time_re = re.compile(r'\s*Time:\s*(\d+(\.\d+)?)\s*ms\s*') + + +def get_start(line): + if line is not None: + m = start_xform_re.match(line) + if m: + return m.group(1) + return None + + +def get_finish(line): + m = finish_xform_re.match(line) + if m: + return m.group(1) + return None + + +def get_time(line): + m = time_re.match(line) + if m: + return m.group(1) + return None + + +def safe_next(it): + try: + return next(it) + except StopIteration: + return None + + +def non_empty(it): + return any(True for _ in it) + + +def read_transform(name, lines): + # The log may be malformed so we just catch that whenever + try: + children = [] + time = None + while True: + line = next(lines) + start_opt = get_start(line) + if start_opt is not None: + child = read_transform(start_opt, lines) + children.append(child) + else: + time_opt = get_time(line) + if time_opt is not None: + time = time_opt + else: + end_opt = get_finish(line) + if end_opt is not None: + assert end_opt == name + return Transform(name, children, time) + except StopIteration: + return None + + +def read_top_transform(it): + # Find start + lines = dropwhile(lambda line: not start_xform_re.match(line), it) + name = get_start(safe_next(lines)) + if name is not None: + return read_transform(name, lines) + else: + return None + + +def pretty_transform(xform): + time_str = " ({} ms)".format(xform.runtime) if xform.runtime is not None else "" + lines = [xform.name + time_str] + nchildren = len(xform.children) + for i in range(0, nchildren): + child = xform.children[i] + child_lines = pretty_transform(child) + if i == nchildren - 1: + branch = "└── " + indent = " " + else: + branch = "├── " + indent = "│ " + first = True + for line in child_lines: + prefix = branch if first else indent + lines.append(prefix + line) + first = False + return lines + + +def remove_time(xform): + children = [remove_time(child) for child in xform.children] + return Transform(xform.name, children, None) + + +def is_existing_file(name): + if not os.path.isfile(name): + msg = "File {} does not exist!".format(name) + raise argparse.ArgumentTypeError(msg) + else: + return name + + +def get_parser(): + parser = argparse.ArgumentParser(description='Parse FIRRTL transform log') + parser.add_argument('file', help='log file', + type=is_existing_file) + parser.add_argument('-s', '--strip-time', action='store_true', default=False, + help='Strip time values') + return parser + + +if __name__ == "__main__": + parser = get_parser() + args = parser.parse_args() + + transforms = [] + with open(args.file, "r") as f: + while True: + xform = read_top_transform(f) + if xform is None: + break + else: + transforms.append(xform) + if len(transforms) == 0: + print("{} does not contain a FIRRTL Transform log!".format(args.file)) + sys.exit(-1) + top = Transform("firrtl.stage.transforms.Compiler", transforms, None) + if args.strip_time: + top = remove_time(top) + pretty = pretty_transform(top) + for line in pretty: + print(line) + |
