mirror of
https://github.com/verilator/verilator.git
synced 2026-09-04 00:30:34 +02:00
The loops modelling the SystemVerilog scheduling regions are no longer generated. They now live in 'VerilatedEvalLoop' in the runtime library. The generated model holds one as a member, passing itself to it, and exposes each evaluation entry point to it as a pure virtual method on VerilatedModel. The model's 'eval' and 'eval_step' remain the top level entry points, and are backward compatible. V3Sched no longer emits '_eval' or '_eval_settle', etc.. Instead every evaluation entry point called from the runtime is enumerated by 'VEval', Scheduling creates all entry points, for all scheduling regions, even if they are empty, and the runtime eval loop calls everything unconditionally. If regions are empty, this is simply a call to an empty function. This will hurt performance on very small models, but should not be noticeable on anything meaningful, so it is likely best to keep to reduce complexity. A scheduling entry points evaluate a single iteration and returns whether it did any work, they are effectively the previous `_eval_phase_*` functions.
199 lines
7.7 KiB
Python
Executable File
199 lines
7.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# pylint: disable=C0103,C0114,C0116,C0209,R0914,R0912,R0915,eval-used
|
|
######################################################################
|
|
|
|
import argparse
|
|
import collections
|
|
import re
|
|
# from pprint import pprint
|
|
|
|
######################################################################
|
|
|
|
|
|
def profcfunc(filename: str) -> None:
|
|
funcs = {}
|
|
|
|
with open(filename, "r", encoding="utf8") as fh:
|
|
|
|
for line in fh:
|
|
# %time cumesec selfsec calls {stuff} name
|
|
match = re.match(
|
|
r'^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$',
|
|
line)
|
|
if match:
|
|
pct = float(match.group(1))
|
|
sec = float(match.group(2))
|
|
calls = float(match.group(3))
|
|
func = match.group(4)
|
|
if func not in funcs:
|
|
funcs[func] = {'pct': 0.0, 'sec': 0.0, 'calls': 0}
|
|
funcs[func]['pct'] += pct
|
|
funcs[func]['sec'] += sec
|
|
funcs[func]['calls'] += calls
|
|
continue
|
|
|
|
# Older gprofs have no call column for single-call functions
|
|
# %time cumesec selfsec {stuff} name
|
|
match = re.match(r'^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$',
|
|
line)
|
|
if match:
|
|
pct = float(match.group(1))
|
|
sec = float(match.group(2))
|
|
calls = 1
|
|
func = match.group(3)
|
|
if func not in funcs:
|
|
funcs[func] = {'pct': 0, 'sec': 0, 'calls': 0}
|
|
funcs[func]['pct'] += pct
|
|
funcs[func]['sec'] += sec
|
|
funcs[func]['calls'] += calls
|
|
continue
|
|
|
|
# Find modules
|
|
verilated_mods = {}
|
|
for func in funcs:
|
|
# Match only the model entry points: 'eval', 'eval_step', 'eval_end_step',
|
|
# and the 'evalXxx' region entry points, but not e.g. a user's '::evaluate'
|
|
match = re.match(r'([A-Za-z_][A-Za-z_0-9]*)::eval(_step|_end_step|[A-Z][A-Za-z_0-9]*)?\(',
|
|
func)
|
|
if match:
|
|
prefix = match.group(1)
|
|
if prefix.startswith('Verilated'): # Run-time library, not a model
|
|
continue
|
|
if Args.debug:
|
|
print("-got _eval %s prefix=%s" % (func, prefix))
|
|
verilated_mods[prefix] = re.compile(r'^' + re.escape(prefix))
|
|
# pprint(verilated_mods)
|
|
|
|
# Sort by Verilog name
|
|
vfuncs = {}
|
|
groups = {}
|
|
groups['type'] = collections.defaultdict(lambda: 0)
|
|
groups['design'] = collections.defaultdict(lambda: 0)
|
|
groups['module'] = collections.defaultdict(lambda: 0)
|
|
|
|
for func, func_item in funcs.items():
|
|
pct = func_item['pct']
|
|
vfunc = func
|
|
|
|
funcarg = re.sub(r'^.*\(', '', func)
|
|
|
|
design = None
|
|
for vde, vde_item in verilated_mods.items():
|
|
if vde_item.match(func) or vde_item.match(funcarg):
|
|
design = vde
|
|
break
|
|
|
|
vdesign = "-"
|
|
|
|
prof_match = re.search(r'__PROF__([a-zA-Z_0-9]+)__l?([0-9]+)\(', vfunc)
|
|
if design and prof_match:
|
|
linefunc = prof_match.group(1)
|
|
lineno = int(prof_match.group(2))
|
|
vfunc = "VBlock %s:%d" % (linefunc, lineno)
|
|
vdesign = design
|
|
groups['type']["Verilog Blocks under " + design] += pct
|
|
groups['design'][design] += pct
|
|
groups['module'][linefunc] += pct
|
|
elif design:
|
|
vfunc = "VCommon " + func
|
|
vdesign = design
|
|
groups['type']["Common code under " + design] += pct
|
|
groups['design'][design] += pct
|
|
groups['module'][design + " common code"] += pct
|
|
elif re.match(r'(VL_[A-Z0-9_]+|_?vl_[a-zA-Z0-9_]+|Verilated)', vfunc):
|
|
vfunc = "VLib " + func
|
|
groups['type']['VLib'] += pct
|
|
groups['design']['VLib'] += pct
|
|
groups['module']['VLib'] += pct
|
|
elif re.match(r'^_mcount_private', vfunc):
|
|
vfunc = "Prof " + func
|
|
groups['type']['Prof'] += pct
|
|
groups['design']['Prof'] += pct
|
|
groups['module']['Prof'] += pct
|
|
else:
|
|
vfunc = "C++ " + func
|
|
groups['type']['C++'] += pct
|
|
groups['design']['C++'] += pct
|
|
groups['module']['C++'] += pct
|
|
|
|
if vfunc not in vfuncs:
|
|
vfuncs[vfunc] = func_item
|
|
vfuncs[vfunc]['design'] = vdesign
|
|
else:
|
|
vfuncs[vfunc]['pct'] += func_item['pct']
|
|
vfuncs[vfunc]['calls'] += func_item['calls']
|
|
vfuncs[vfunc]['sec'] += func_item['sec']
|
|
|
|
for ftype in ['type', 'design', 'module']:
|
|
missing = 100
|
|
for item in groups[ftype].keys():
|
|
missing -= groups[ftype][item]
|
|
groups[ftype]["\377Unaccounted for/rounding error"] = missing
|
|
|
|
print("Overall summary by %s:" % ftype)
|
|
print(" %-6s %s" % ("% time", ftype))
|
|
for what in sorted(groups[ftype].keys()):
|
|
# \377 used to establish sort order
|
|
pwhat = re.sub(r'^\377', '', what)
|
|
print(" %6.2f %s" % (groups[ftype][what], pwhat))
|
|
print()
|
|
|
|
design_width = 1
|
|
for func, func_item in vfuncs.items():
|
|
design_width = max(design_width, len(func_item['design']))
|
|
|
|
print("Verilog code profile:")
|
|
print(" These are split into three categories:")
|
|
print(" C++: Time in non-Verilated C++ code")
|
|
print(" Prof: Time in profile overhead")
|
|
print(" VBlock: Time attributable to a block in a" + " Verilog file and line")
|
|
print(" VCommon: Time in a Verilated module," + " due to all parts of the design")
|
|
print(" VLib: Time in Verilated common libraries," + " called by the Verilated code")
|
|
print()
|
|
|
|
print(" % cumulative self ")
|
|
print((" time seconds seconds calls %-" + str(design_width) +
|
|
"s type filename and line number") % "design")
|
|
|
|
cume = 0.0
|
|
for func in sorted(vfuncs.keys(), key=lambda f: vfuncs[f]['sec'], reverse=True):
|
|
cume += vfuncs[func]['sec']
|
|
print(("%6.2f %9.2f %8.2f %10d %-" + str(design_width) + "s %s") %
|
|
(vfuncs[func]['pct'], cume, vfuncs[func]['sec'], vfuncs[func]['calls'],
|
|
vfuncs[func]['design'], func))
|
|
|
|
|
|
######################################################################
|
|
######################################################################
|
|
|
|
parser = argparse.ArgumentParser(
|
|
allow_abbrev=False,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
description="""Read gprof report created with Verilator --prof-cfuncs
|
|
|
|
Verilator_profcfunc reads a profile report created by gprof. The names of
|
|
the functions are then transformed, assuming the user used Verilator's
|
|
--prof-cfuncs, and a report printed showing the percentage of time, etc,
|
|
in each Verilog block.
|
|
|
|
For documentation see
|
|
https://verilator.org/guide/latest/exe_verilator_profcfunc.html""",
|
|
epilog="""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-FileCopyrightText: 2002-2026 Wilson Snyder
|
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
""")
|
|
|
|
parser.add_argument('--debug', action='store_const', const=9, help='enable debug')
|
|
parser.add_argument('filename', help='input gprof output to process')
|
|
|
|
Args = parser.parse_args()
|
|
profcfunc(Args.filename)
|
|
|
|
######################################################################
|
|
# Local Variables:
|
|
# compile-command: "./verilator_profcfunc ../test_regress/t/t_profcfunc.gprof"
|
|
# End:
|