blob: e4ee3b59b979952f82f1178af8d642d1f9bea324 [file] [log] [blame]
#!/usr/bin/perl -w
my $instructions = "
$0
Usage:
cat dump | $0 --bin u-boot/u-boot # read from stdin, using u-boot for symbols
$0 --bin linux/vmlinux dump # read from file 'dump' using linux for symbols
Takes output from iptr sampling code, aggregate functions, sort by use and display with symbol data information.
Arguments: --bin <file> executable to read symbol table from.
--subsamples show distribution of subsample counters for each function
";
use strict;
use warnings;
use Getopt::Long;
use File::Basename;
use File::Spec;
use Cwd 'abs_path';
BEGIN {
push @INC, dirname(__FILE__);
}
use arcsymbols;
my $script_path = dirname(__FILE__);
my $swdepot = dirname(__FILE__)."/../..";
if (!caller) {
&main;
}
sub fixfunc {
my ($syms, $name, $offset, $size) = @_;
my $sym = undef;
if ($offset > 0) {
# find symbol, compare sizes; some functions are omitted in kallsyms
foreach my $bin (reverse sort keys %$syms) {
my $changed = undef;
($name, $offset, $size, $changed, $sym) = $syms->{$bin}->fixfunc($name, $offset, $size);
if ($changed == 1) {
last;
}
}
}
return ($name, $offset, $size, $sym);
}
sub main {
my $help = undef;
my @bin_path;
my @def_bin_path = `find $swdepot/drivers/ -name \*.ko`;
push(@def_bin_path, "$swdepot/linux/vmlinux");
my $subsamples = undef;
my $sort = "szweight";
my $result = GetOptions(
"help" => \$help,
"bin=s" => \@bin_path,
"subsamples" => \$subsamples,
"sort=s" => \$sort,
);
if ($help) {
die "$instructions\n";
}
my @allsyms;
if ($#bin_path < 0) {
@bin_path = @def_bin_path;
}
foreach (@bin_path) {
chomp;chomp;
push @allsyms, new arcsymbols($_);
}
my $iptr_data;
if ($#ARGV > 0) {
die "$instructions\n";
} elsif ($#ARGV == 0) {
foreach my $dump_file (@ARGV) {
open(F, $dump_file) or die "Could not load dump file: $dump_file: $!\n";
$iptr_data = &read_file_convert(*F, \@allsyms);
close(F);
}
} else {
$iptr_data = &read_file_convert(*STDIN, \@allsyms);
}
&display_iptr_samples($iptr_data, $subsamples, $sort);
}
sub getfunc {
my ($syms, $addr) = @_;
foreach my $bin (reverse sort keys %$syms) {
my $sym = $syms->{$bin}->find_symbol($addr);
if ($sym) {
return ($sym->{name}, $addr - $sym->{addr}, $sym->{size});
}
}
warn sprintf "could not find sym for addr: %x\n", $addr;
return (sprintf(" -unknown_0x%x", $addr), 0, 1);
}
sub read_file_convert {
my ($fh, $syms) = @_;
my $last_saw_parsedump_helper = 0;
my $parsedump_helper_sections = {};
my %samples;
my $total_uses = 0;
while(<$fh>) {
if ( /^parsedump\s+([\w_]+)\s+([\.\w_]+)\s+(0x[a-fA-F0-9]+)\s*$/ ) {
my $module_name = $1;
my $section_name = $2;
my $section_addr = hex($3);
$parsedump_helper_sections->{$module_name}->{$section_name} = $section_addr;
$last_saw_parsedump_helper = 1;
} else {
if ($last_saw_parsedump_helper) {
foreach my $module_name (sort keys %{$parsedump_helper_sections}) {
foreach my $mod_path (<$script_path/../../drivers/*/$module_name.ko>) {
my $mod_rel = File::Spec->abs2rel(abs_path($mod_path));
warn "$0: Loading symbols from '$mod_rel'\n";
push @{$syms}, new arcsymbols($mod_rel, $parsedump_helper_sections->{$module_name});
}
}
$last_saw_parsedump_helper = 0;
$parsedump_helper_sections = {};
}
if (/^(0x[\w\d]+)\s+(0x[\w\d]+)\s+([\w_][_\w\d]+|)\+?(0x[\w\d]+|)\/?(0x[\w\d]+|)/) {
my $addr = hex($1);
my $uses = hex($2);
foreach my $store (@{$syms}) {
my $symbol = $store->find_symbol($addr);
if ($symbol) {
my $func = $symbol->{name};
my $offset = $addr - $symbol->{addr};
my $size = $symbol->{size};
$samples{$func}->{addr} = $addr - $offset;
$samples{$func}->{size} = $size;
$samples{$func}->{samples}->{$addr}->{offset} = $offset;
$samples{$func}->{samples}->{$addr}->{uses} = $uses;
$samples{$func}->{uses} += $uses;
$samples{$func}->{pts} += 1;
$samples{$func}->{ptweight} = $samples{$func}->{uses} / $samples{$func}->{pts};
$samples{$func}->{szweight} = $samples{$func}->{uses} / $samples{$func}->{size};
$total_uses += $uses;
}
}
}
}
}
foreach my $func (keys %samples) {
$samples{$func}->{percentage} = $samples{$func}->{uses} * 100.0 / $total_uses;
}
return \%samples;
}
sub display_iptr_samples {
my ($data_ref, $subsamples, $sort) = @_;
my %data = %{$data_ref};
my $pattern = "%10s %10s %10s %10s %10s %10s %6s %s";
printf "$pattern\n", "Total Uses", "Addr", "Pts", "ptweight", "szweight", "%Pct", "Size", "Name";
foreach my $func (sort { $data{$b}->{$sort} <=> $data{$a}->{$sort} } keys %data) {
printf "$pattern\n", (
sprintf("%d", $data{$func}->{uses}),
sprintf("%x", $data{$func}->{addr}),
sprintf("%d", $data{$func}->{pts}),
sprintf("%-2.4g", $data{$func}->{ptweight}),
sprintf("%-2.4g", $data{$func}->{szweight}),
sprintf("%-2.4g", $data{$func}->{percentage}),
sprintf("%x", $data{$func}->{size}),
$func);
if ($subsamples) {
foreach my $addr (sort keys %{$data{$func}->{samples}}) {
my $uses = $data{$func}->{samples}->{$addr}->{uses};
my $objaddr;
my $offset = $addr - $data{$func}->{addr};
if ($data{$func}->{sym}) {
$objaddr = $addr - $data{$func}->{addr} + $data{$func}->{sym}->{addr};
$offset = $objaddr - $data{$func}->{sym}->{addr};
}
printf "$pattern\n", (
sprintf("%d", $uses),
sprintf("%x", $objaddr ? $objaddr : $addr),
sprintf("%x", $offset),
"",
"",
"",
"",
"");
}
}
}
}