2020-01-10 01:01:12 +00:00
|
|
|
#!/usr/bin/env perl
|
2008-08-05 13:59:15 +00:00
|
|
|
# See copyright, etc in below POD section.
|
2007-05-18 18:48:22 +00:00
|
|
|
######################################################################
|
|
|
|
|
|
|
|
require 5.006_001;
|
|
|
|
use warnings;
|
|
|
|
use Getopt::Long;
|
|
|
|
use IO::File;
|
|
|
|
use Pod::Usage;
|
2008-08-05 13:59:15 +00:00
|
|
|
eval { use Data::Dumper; $Data::Dumper::Indent = 1; }; # Debug, ok if missing
|
2007-05-18 18:48:22 +00:00
|
|
|
use strict;
|
2018-11-29 00:59:10 +00:00
|
|
|
use vars qw($Debug);
|
2007-05-18 18:48:22 +00:00
|
|
|
|
|
|
|
#======================================================================
|
|
|
|
|
|
|
|
|
|
|
|
#======================================================================
|
|
|
|
# main
|
|
|
|
|
|
|
|
$Debug = 0;
|
|
|
|
my $Opt_File;
|
|
|
|
autoflush STDOUT 1;
|
|
|
|
autoflush STDERR 1;
|
2018-11-29 00:59:10 +00:00
|
|
|
Getopt::Long::config("no_auto_abbrev");
|
2019-05-08 02:34:09 +00:00
|
|
|
if (! GetOptions(
|
|
|
|
"help" => \&usage,
|
|
|
|
"debug" => \&debug,
|
|
|
|
"<>" => \¶meter,
|
|
|
|
)) {
|
2007-05-18 18:48:22 +00:00
|
|
|
die "%Error: Bad usage, try 'verilator_profcfunc --help'\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
defined $Opt_File or die "%Error: No filename given\n";
|
|
|
|
|
|
|
|
profcfunc($Opt_File);
|
|
|
|
|
|
|
|
#----------------------------------------------------------------------
|
|
|
|
|
|
|
|
sub usage {
|
2019-10-01 03:15:10 +00:00
|
|
|
pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT);
|
|
|
|
exit(1); # Unreachable
|
2007-05-18 18:48:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sub debug {
|
|
|
|
$Debug = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub parameter {
|
|
|
|
my $param = shift;
|
|
|
|
if (!defined $Opt_File) {
|
2019-05-08 02:34:09 +00:00
|
|
|
$Opt_File = $param;
|
2008-06-10 01:25:10 +00:00
|
|
|
} else {
|
2019-05-08 02:34:09 +00:00
|
|
|
die "%Error: Unknown parameter: $param\n";
|
2007-05-18 18:48:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#######################################################################
|
|
|
|
|
|
|
|
sub profcfunc {
|
|
|
|
my $filename = shift;
|
|
|
|
# Remove hex numbers before diffing
|
|
|
|
my $fh = IO::File->new ($filename) or die "%Error: $! $filename,";
|
|
|
|
|
|
|
|
my %funcs;
|
|
|
|
|
|
|
|
while (defined (my $line=$fh->getline())) {
|
2019-05-08 02:34:09 +00:00
|
|
|
# %time cumesec selfsec calls {stuff} name
|
|
|
|
if ($line =~ /^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$/) {
|
|
|
|
my $pct=$1; my $sec=$2; my $calls=$3; my $func=$4;
|
|
|
|
$funcs{$func}{pct} += $pct;
|
|
|
|
$funcs{$func}{sec} += $sec;
|
|
|
|
$funcs{$func}{calls} += $calls;
|
|
|
|
}
|
2018-04-11 02:05:17 +00:00
|
|
|
# Older gprofs have no call column for single-call functions
|
|
|
|
# %time cumesec selfsec {stuff} name
|
|
|
|
elsif ($line =~ /^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$/) {
|
|
|
|
my $pct=$1; my $sec=$2; my $calls=1; my $func=$3;
|
|
|
|
$funcs{$func}{pct} += $pct;
|
|
|
|
$funcs{$func}{sec} += $sec;
|
|
|
|
$funcs{$func}{calls} += $calls;
|
|
|
|
}
|
2007-05-18 18:48:22 +00:00
|
|
|
}
|
|
|
|
$fh->close;
|
|
|
|
|
2007-05-22 12:15:01 +00:00
|
|
|
# Find modules
|
2008-08-05 13:59:15 +00:00
|
|
|
my %pointer_mods;
|
2007-05-22 12:15:01 +00:00
|
|
|
my %verilated_mods;
|
|
|
|
foreach my $func (keys %funcs) {
|
2019-05-08 02:34:09 +00:00
|
|
|
if ($func =~ /(.*)::_eval\(([a-zA-Z_0-9]+__Syms).*\)$/) {
|
|
|
|
$verilated_mods{$1} = qr/^$1/;
|
|
|
|
$pointer_mods{$2} = $1;
|
|
|
|
}
|
2007-05-22 12:15:01 +00:00
|
|
|
}
|
2008-08-05 13:59:15 +00:00
|
|
|
#print Dumper(\%pointer_mods, \%verilated_mods);
|
2007-05-22 12:15:01 +00:00
|
|
|
|
|
|
|
# Resort by Verilog name
|
|
|
|
my %vfuncs;
|
|
|
|
my %groups;
|
|
|
|
foreach my $func (keys %funcs) {
|
2019-05-08 02:34:09 +00:00
|
|
|
my $pct = $funcs{$func}{pct};
|
|
|
|
my $vfunc = $func;
|
|
|
|
my $design;
|
|
|
|
|
|
|
|
if ($func =~ /\(([a-zA-Z_0-9]+__Syms)/) {
|
|
|
|
$design = $pointer_mods{$1};
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach my $vde (keys %verilated_mods) {
|
|
|
|
last if $design;
|
|
|
|
if ($func =~ /$verilated_mods{$vde}/) {
|
|
|
|
$design=$vde;
|
|
|
|
last;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($vfunc =~ /__PROF__([a-zA-Z_0-9]+)__l?([0-9]+)\(/) {
|
|
|
|
$vfunc = sprintf("VBlock %s:%d", $1, $2);
|
|
|
|
$groups{type}{"Verilog Blocks under $design"} += $pct;
|
|
|
|
$groups{design}{$design} += $pct;
|
|
|
|
$groups{module}{$1} += $pct;
|
|
|
|
} else {
|
|
|
|
if ($design) {
|
|
|
|
$vfunc = sprintf("VCommon %s", $func);
|
|
|
|
$groups{type}{"Common code under $design"} += $pct;
|
|
|
|
$groups{design}{$design} += $pct;
|
|
|
|
$groups{module}{$design." common code"} += $pct;
|
|
|
|
} elsif ($func =~ /^VL_[A-Z0-9_]+/
|
|
|
|
|| $func =~ /^_?vl_[a-zA-Z0-9_]+/
|
|
|
|
|| $func =~ /^verilated/i) {
|
|
|
|
$vfunc = sprintf("VLib %s", $func);
|
|
|
|
$groups{type}{'VLib'} += $pct;
|
|
|
|
$groups{design}{'VLib'} += $pct;
|
|
|
|
$groups{module}{'VLib'} += $pct;
|
|
|
|
} elsif ($func =~ /^_mcount_private/) {
|
|
|
|
$vfunc = sprintf("Prof %s", $func);
|
|
|
|
$groups{type}{'Prof'} += $pct;
|
|
|
|
$groups{design}{'Prof'} += $pct;
|
|
|
|
$groups{module}{'Prof'} += $pct;
|
|
|
|
} else {
|
|
|
|
$vfunc = sprintf("C++ %s", $func);
|
|
|
|
$groups{type}{'C++'} += $pct;
|
|
|
|
$groups{design}{'C++'} += $pct;
|
|
|
|
$groups{module}{'C++'} += $pct;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$vfuncs{$vfunc} = $funcs{$func};
|
2007-05-22 12:15:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-08-29 02:10:39 +00:00
|
|
|
foreach my $type (qw(type design module)) {
|
2019-05-08 02:34:09 +00:00
|
|
|
my $missing = 100;
|
|
|
|
foreach (sort (keys %{$groups{$type}})) {
|
|
|
|
$missing -= $groups{$type}{$_};
|
|
|
|
}
|
|
|
|
if ($missing) {
|
|
|
|
$groups{$type}{"\377Unaccounted for/rounding error"} = $missing;
|
|
|
|
}
|
|
|
|
|
|
|
|
print("Overall summary by $type:\n");
|
|
|
|
printf(" %-6s %s\n","% time",$type);
|
|
|
|
foreach my $what (sort (keys %{$groups{$type}})) {
|
|
|
|
(my $pwhat = $what) =~ s/^\377//; # Just used to establish sort order
|
|
|
|
printf(" %6.2f %s\n", $groups{$type}{$what}, $pwhat);
|
|
|
|
}
|
|
|
|
print("\n");
|
2008-08-05 13:59:15 +00:00
|
|
|
}
|
2007-05-22 12:15:01 +00:00
|
|
|
|
|
|
|
print("Verilog code profile:\n");
|
|
|
|
print(" These are split into three categories:\n");
|
|
|
|
print(" C++: Time in non-Verilated C++ code\n");
|
2014-08-29 02:10:39 +00:00
|
|
|
print(" Prof: Time in profile overhead\n");
|
2007-05-22 12:15:01 +00:00
|
|
|
print(" VBlock: Time attributable to a block in a Verilog file and line\n");
|
|
|
|
print(" VCommon: Time in a Verilated module, due to all parts of the design\n");
|
2014-08-29 02:10:39 +00:00
|
|
|
print(" VLib: Time in Verilated common libraries, called by the Verilated code\n");
|
2007-05-22 12:15:01 +00:00
|
|
|
print("\n");
|
2007-05-18 18:48:22 +00:00
|
|
|
|
|
|
|
print(" % cumulative self \n");
|
2007-05-22 12:15:01 +00:00
|
|
|
print(" time seconds seconds calls type filename and line number\n");
|
2007-05-18 18:48:22 +00:00
|
|
|
|
|
|
|
my $cume = 0;
|
2007-05-22 12:15:01 +00:00
|
|
|
foreach my $func (sort {$vfuncs{$b}{sec} <=> $vfuncs{$a}{sec}
|
2019-05-08 02:34:09 +00:00
|
|
|
|| $a cmp $b}
|
|
|
|
(keys %vfuncs)) {
|
|
|
|
$cume += $vfuncs{$func}{sec};
|
|
|
|
printf +("%6.2f %9.2f %8.2f %8d %s\n",
|
|
|
|
$vfuncs{$func}{pct},
|
|
|
|
$cume, $vfuncs{$func}{sec},
|
|
|
|
$vfuncs{$func}{calls},
|
|
|
|
$func);
|
2007-05-18 18:48:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#######################################################################
|
|
|
|
__END__
|
|
|
|
|
|
|
|
=pod
|
|
|
|
|
|
|
|
=head1 NAME
|
|
|
|
|
2018-05-20 13:12:29 +00:00
|
|
|
verilator_profcfunc - Read gprof report created with --prof-cfuncs
|
2007-05-18 18:48:22 +00:00
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
|
2018-05-20 13:12:29 +00:00
|
|
|
verilator --prof-cfuncs ....
|
2007-05-18 18:48:22 +00:00
|
|
|
gcc --ggdb -pg ....
|
|
|
|
{run executable}
|
|
|
|
gprof
|
|
|
|
verilator_profcfuncs gprof.out
|
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
|
|
|
|
Verilator_profcfunc reads a profile report created by gprof. The names of
|
2019-05-11 22:42:27 +00:00
|
|
|
the functions are then transformed, assuming the user used Verilator's
|
2018-05-20 13:12:29 +00:00
|
|
|
--prof-cfuncs, and a report printed showing the percentage of time, etc,
|
2007-05-18 18:48:22 +00:00
|
|
|
in each Verilog block.
|
|
|
|
|
2021-04-11 22:55:06 +00:00
|
|
|
For documentation see L<https://verilator.org/verilator_doc.html>.
|
2007-05-18 18:48:22 +00:00
|
|
|
|
2021-04-11 22:55:06 +00:00
|
|
|
=head1 ARGUMENT SUMMARY
|
2007-05-18 18:48:22 +00:00
|
|
|
|
2021-04-11 22:55:06 +00:00
|
|
|
<filename> Input file (gprof.out)
|
|
|
|
--help Display this help
|
2007-05-18 18:48:22 +00:00
|
|
|
|
|
|
|
=head1 DISTRIBUTION
|
|
|
|
|
2019-11-08 03:33:59 +00:00
|
|
|
The latest version is available from L<https://verilator.org>.
|
2007-05-18 18:48:22 +00:00
|
|
|
|
2021-01-01 15:29:54 +00:00
|
|
|
Copyright 2007-2021 by Wilson Snyder. This program is free software; you
|
2020-03-21 15:24:24 +00:00
|
|
|
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
|
2007-05-18 18:48:22 +00:00
|
|
|
|
|
|
|
=head1 SEE ALSO
|
|
|
|
|
|
|
|
C<verilator>
|
|
|
|
|
2021-04-11 22:55:06 +00:00
|
|
|
and L<https://verilator.org/verilator_doc.html> for detailed documentation.
|
|
|
|
|
2007-05-18 18:48:22 +00:00
|
|
|
=cut
|
|
|
|
|
|
|
|
######################################################################
|
|
|
|
### Local Variables:
|
|
|
|
### compile-command: "$V4/bin/verilator_profcfunc $V4/test_c/obj_dir/V*_03_*.tree $V4N/test_c/obj_dir/V*_03_*.tree"
|
|
|
|
### End:
|