1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
|
#!/usr/bin/env python3
# SPDX-License-Identifier: Apache-2.0
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)
|