4 print STDERR
("Error: @_\n");
9 print STDERR
("Warning: @_\n");
12 # string (filename.map)
13 # return hash(string:hash(string:number))
15 open(MAP_FILE
,$_[0]) || error
("Couldn't open a map $_[0]");
19 my @parts = split(/[[:space:]]+/);
23 if ($parts[1] =~ m/\.(text|data|rodata|bss|icode|idata|irodata|ibss)/) {
24 my $region = $parts[1];
25 my $number = $parts[2];
26 @parts = split(/\//,$parts[4]);
27 @parts = split(/[\(\)]/,$parts[$#parts]);
28 my $library = $retval{$parts[0]};
29 my %library = %$library;
30 my $object = $parts[$#parts];
31 $library{$object . $region} = $number;
32 $retval{$parts[0]} = \
%library;
39 # string (filename.(a|o|elf)), hash(number:string), string(objdump_tool)
40 # return hash(number:string)
42 open(OBJECT_FILE
,"$_[2] -t $_[0] |") ||
43 error
("Couldn't pipe objdump for $_[0]\nCommand was: $_[2] -t $_[0]");
45 my %library = %$library;
48 while (<OBJECT_FILE
>) {
50 my @parts = split(/[[:space:]]+/);
51 if ($parts[0] =~ m/:$/) {
59 if ($parts[0] eq "") {
62 if ($parts[3] eq $parts[5]) {
65 if ($parts[3] =~ m/\.(text|data|rodata|bss|icode|idata|irodata|ibss|iram)/) {
66 my $region = $parts[3];
67 my $symbolOffset = hex("0x" . $parts[0]);
68 my $sectionOffset = hex($library{$object . $region});
69 my $location = $symbolOffset + $sectionOffset;
70 $retval{$location} = $parts[5] . "(" . $object . ")";
77 # string (0xFFFFFFFF), hash(number:string)
80 my $location = hex($_[0]);
82 my %offsets = %$offsets;
83 if (exists $offsets{$location}) {
84 return $offsets{$location};
87 $retval =~ y/[A-Z]/[a-z]/;
88 warning
("No symbol found for $retval");
93 # string (filename), hash(number:string)
94 # return array(array(number,number,string))
96 open(PROFILE_FILE
,$_[0]) ||
97 error
("Could not open profile file: $profile_file");
101 while (<PROFILE_FILE
>) {
109 my @parts = split(/[[:space:]]+/);
110 if ($parts[0] =~ m/^0x/) {
111 my $callName = get_name
($parts[0],$offsets);
112 my $calls = $parts[1];
113 my $ticks = $parts[2];
114 my @pfd = ($calls,$ticks,$callName);
115 if (exists $pfds{$callName}) {
116 my $old_pfd = $pfds{$callName};
117 $pfd[0]+=@
$old_pfd[0];
118 $pfd[1]+=@
$old_pfd[1];
120 $pfds{$callName} = \
@pfd;
127 # print("FUNCTIONS\tTOTAL_CALLS\tTOTAL_TICKS\n");
128 # printf(" %4d\t %8d\t %8d\n",$pfds,$totalCalls,$totalTicks);
129 return values(%pfds);
132 # array(array(number,number,string)), number (sort element)
136 my $sort_index = $_[1];
143 # we use a key sort, which means numerical fields need to be
144 # numerically sortable by an alphanumeric sort - we can simply
145 # do this by giving the numeric keys trailing zeros. Note that
146 # simple string concatenation (what this used to do) would not do this
147 foreach $element(@pfds) {
149 @
$ne[0] = sprintf( "%08d", @
$element[0]);
150 @
$ne[1] = sprintf( "%08d", @
$element[1]);
151 $elements{@
$ne[$sort_index] . @
$element[2]} = $element;
153 $totalCalls += @
$element[0];
154 $totalTicks += @
$element[1];
156 my @keys = sort(keys(%elements));
157 print("FUNCTIONS\tTOTAL_CALLS\tTOTAL_TICKS\n");
158 printf(" %4d\t %8d\t %8d\n",$pfds,$totalCalls,$totalTicks);
159 foreach $key(@keys) {
160 my $element = $elements{$key};
162 printf("Calls: %7.2f%% Ticks: %7.2f%% Symbol: %s\n",
163 @
$element[0]/$totalCalls*100,
164 @
$element[1]/$totalTicks*100,
167 printf("Calls: %08d Ticks: %08d Symbol: %s\n",
177 return (%$hash1,%$hash2);
182 print STDERR
("Error: @_\n");
184 print STDERR
("USAGE:\n");
185 print STDERR
("$0 profile.out objdump_tool map obj[...] [map obj[...]...] sort[...]\n");
187 ("\tprofile.out output from the profiler, extension is .out\n");
189 ("\tobjdump_tool name of objdump executable for this platform\n");
191 ("\t e.g. arm-elf-objdump\n");
193 ("\tmap map file, extension is .map\n");
195 ("\tobj library or object file, extension is .a or .o or .elf\n");
197 ("\tformat 0-2[_p] 0: by calls, 1: by ticks, 2: by name\n");
199 ("\t _p shows percents instead of counts\n");
200 print STDERR
("NOTES:\n");
202 ("\tmaps and objects come in sets, one map then many objects\n");
207 if ($ARGV[0] =~ m/-(h|help|-help)/) {
211 usage
("Requires at least 3 arguments");
213 if ($ARGV[0] !~ m/\.out$/) {
214 usage
("Profile file must end in .out");
220 for (; $i < @ARGV; $i++) {
221 my $file = $ARGV[$i];
222 if ($file =~ m/\.map$/) {
223 %map = read_map
($file);
224 } elsif ($file =~ m/\.(a|o|elf)$/) {
226 usage
("No map file found before first object file");
228 my @parts = split(/\//,$file);
229 my %new_symbols = read_library
($file,$map{$parts[$#parts]},$ARGV[1]);
230 %symbols = merge_hashes
(\
%symbols,\
%new_symbols);
237 warning
("No symbols found");
240 error
("You forgot to specify any sort ordering on output (e.g. 0, 1_p, 2)");
242 my @pfds = create_list
($ARGV[0],\
%symbols);
243 for (; $i < @ARGV; $i++) {
244 print_sorted
(\
@pfds,split("_",$ARGV[$i]));