forked from github/verilator
98 lines
3.2 KiB
Python
Executable File
98 lines
3.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# pylint: disable=C0103,C0114,C0115,C0116,C0123,C0209,C0301,R0902,R0913,R0914,R0912,R0915,W0621
|
|
######################################################################
|
|
|
|
import argparse
|
|
import collections
|
|
import pathlib
|
|
import re
|
|
|
|
from datetime import datetime
|
|
|
|
parser = argparse.ArgumentParser(
|
|
allow_abbrev=False,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
description="""Report ccache behavior of a Verilated model build.
|
|
|
|
For documentation see
|
|
https://verilator.org/guide/latest/exe_verilator_ccache_report.html""",
|
|
epilog=
|
|
"""Copyright 2002-2023 by Wilson Snyder. This program is free software; you
|
|
can redistribute it and/or modify it under the terms of either the GNU
|
|
Lesser General Public License Version 3 or the Perl Artistic License
|
|
Version 2.0.
|
|
|
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
|
|
|
parser.add_argument('-o',
|
|
type=argparse.FileType('w'),
|
|
metavar="OUTFILE",
|
|
required=True,
|
|
help='output file')
|
|
parser.add_argument('logdir', type=pathlib.Path, help='log directory')
|
|
|
|
args = parser.parse_args()
|
|
|
|
results = {}
|
|
elapsed = {}
|
|
|
|
|
|
def toDateTime(s):
|
|
return datetime.strptime(s, "%Y-%m-%dT%H:%M:%S.%f")
|
|
|
|
|
|
for logfile in args.logdir.iterdir():
|
|
with logfile.open() as fh:
|
|
start = None
|
|
obj = None
|
|
for line in fh:
|
|
line = line.strip()
|
|
match = re.match(r'\[(\S+)\s.*Object file: (.*)$', line)
|
|
if match:
|
|
start = toDateTime(match.group(1))
|
|
obj = match.group(2)
|
|
match = re.match(r'\[(\S+)\s.*Result: (.*)$', line)
|
|
if match:
|
|
assert obj is not None
|
|
elapsed[obj] = toDateTime(match.group(1)) - start
|
|
results[obj] = match.group(2)
|
|
|
|
args.o.write("#" * 80 + "\n")
|
|
args.o.write("ccache report (from verilator_ccache_report) :\n")
|
|
|
|
if not results:
|
|
args.o.write("\nAll object files up to date\n")
|
|
else:
|
|
args.o.write("\nCompiled object files:\n")
|
|
wnames = max(len(_) for _ in results) + 1
|
|
wresults = max(len(_) for _ in results.values()) + 1
|
|
for k in sorted(results.keys()):
|
|
args.o.write("{:{wnames}} : {:{wresults}} : {}s\n".format(
|
|
k,
|
|
results[k],
|
|
elapsed[k].total_seconds(),
|
|
wnames=wnames,
|
|
wresults=wresults))
|
|
|
|
args.o.write("\nSummary:\n")
|
|
counts = collections.Counter(_ for _ in results.values())
|
|
total = sum(counts.values())
|
|
for k in sorted(counts.keys()):
|
|
c = counts[k]
|
|
args.o.write("{:{width}}| {} ({:.2%})\n".format(k,
|
|
c,
|
|
c / total,
|
|
width=wresults))
|
|
|
|
args.o.write("\nLongest:\n")
|
|
longest = sorted(list(elapsed.items()),
|
|
key=lambda kv: -kv[1].total_seconds())
|
|
for i, (k, v) in enumerate(longest):
|
|
args.o.write("{:{width}}| {}s\n".format(k,
|
|
v.total_seconds(),
|
|
width=wnames))
|
|
if i > 4:
|
|
break
|
|
|
|
args.o.write("#" * 80 + "\n")
|