summaryrefslogtreecommitdiff
path: root/tools/profile_reader/profile_reader.pl
diff options
context:
space:
mode:
Diffstat (limited to 'tools/profile_reader/profile_reader.pl')
-rwxr-xr-xtools/profile_reader/profile_reader.pl236
1 files changed, 236 insertions, 0 deletions
diff --git a/tools/profile_reader/profile_reader.pl b/tools/profile_reader/profile_reader.pl
new file mode 100755
index 0000000000..088ba7186e
--- /dev/null
+++ b/tools/profile_reader/profile_reader.pl
@@ -0,0 +1,236 @@
1#!/usr/bin/perl
2
3sub error {
4 print STDERR ("Error: @_\n");
5 exit(1);
6}
7
8sub warning {
9 print STDERR ("Warning: @_\n");
10}
11
12# string (filename.map)
13# return hash(string:hash(string:number))
14sub read_map {
15 open(MAP_FILE,$_[0]) || error("Couldn't open a map $_[0]");
16 my %retval;
17 while (<MAP_FILE>) {
18 chomp;
19 my @parts = split(/[[:space:]]+/);
20 if (@parts != 5) {
21 next;
22 }
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;
33 }
34 }
35 close(MAP_FILE);
36 return %retval;
37}
38
39# string (filename.[ao]), hash(string:number)
40# return hash(number:string)
41sub read_library {
42 open(OBJECT_FILE,"objdump -t $_[0] |") ||
43 error("Couldn't pipe objdump for $_[0]");
44 my $library = $_[1];
45 my %library = %$library;
46 my %retval;
47 my $object;
48 while (<OBJECT_FILE>) {
49 chomp;
50 my @parts = split(/[[:space:]]+/);
51 if ($parts[0] =~ m/:$/) {
52 $object = $parts[0];
53 $object =~ s/:$//;
54 next;
55 }
56 if (@parts != 6) {
57 next;
58 }
59 if ($parts[0] eq "") {
60 next;
61 }
62 if ($parts[3] eq $parts[5]) {
63 next;
64 }
65 if ($parts[3] =~ m/\.(text|data|rodata|bss|icode|idata|irodata|ibss)/) {
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 . ")";
71 }
72 }
73 close(OBJECT_FILE);
74 return %retval;
75}
76
77# string (0xFFFFFFFF), hash(number:string)
78# return string
79sub get_name {
80 my $location = hex($_[0]);
81 my $offsets = $_[1];
82 my %offsets = %$offsets;
83 if (exists $offsets{$location}) {
84 return $offsets{$location};
85 } else {
86 my $retval = $_[0];
87 $retval =~ y/[A-Z]/a-z/;
88 warning("No symbol found for $retval");
89 return $retval;
90 }
91}
92
93# string (filename), hash(number:string)
94# return array(array(number,number,string))
95sub create_list {
96 open(PROFILE_FILE,$_[0]) ||
97 error("Could not open profile file: $profile_file");
98 my $offsets = $_[1];
99 my $started = 0;
100 my %pfds;
101# my $totalCalls = 0;
102# my $totalTicks = 0;
103# my $pfds = 0;
104 while (<PROFILE_FILE>) {
105 if ($started == 0) {
106 if (m/^0x/) {
107 $started = 1;
108 } else {
109 next;
110 }
111 }
112 my @parts = split(/[[:space:]]+/);
113 if ($parts[0] =~ m/^0x/) {
114 my $callName = get_name($parts[0],$offsets);
115 my $calls = $parts[1];
116 my $ticks = $parts[2];
117 my @pfd = ($calls,$ticks,$callName);
118 if (exists $pfds{$callName}) {
119 my $old_pfd = $pfds{$callName};
120 $pfd[0]+=@$old_pfd[0];
121 $pfd[1]+=@$old_pfd[1];
122 }
123 $pfds{$callName} = \@pfd;
124# $pfds++;
125# $totalCalls+=$calls;
126# $totalTicks+=$ticks;
127 } else {
128 last;
129 }
130
131 }
132 close(PROFILE_FILE);
133# print("FUNCTIONS\tTOTAL_CALLS\tTOTAL_TICKS\n");
134# printf(" %4d\t %8d\t %8d\n",$pfds,$totalCalls,$totalTicks);
135 return values(%pfds);
136}
137
138# array(array(number,number,string)), number (sort element)
139sub print_sorted {
140 my $pfds = $_[0];
141 my @pfds = @$pfds;
142 my $sort_index = $_[1];
143 my $percent = $_[2];
144 my %elements;
145 my $totalCalls = 0;
146 my $totalTicks = 0;
147 $pfds = 0;
148 foreach $element(@pfds) {
149 $elements{@$element[$sort_index] . @$element[2]} = $element;
150 $pfds++;
151 $totalCalls += @$element[0];
152 $totalTicks += @$element[1];
153 }
154 my @keys = sort(keys(%elements));
155 print("FUNCTIONS\tTOTAL_CALLS\tTOTAL_TICKS\n");
156 printf(" %4d\t %8d\t %8d\n",$pfds,$totalCalls,$totalTicks);
157 foreach $key(@keys) {
158 my $element = $elements{$key};
159 if ($percent) {
160 printf("Calls: %7.2f%% Ticks: %7.2f%% Symbol: %s\n",
161 @$element[0]/$totalCalls*100,
162 @$element[1]/$totalTicks*100,
163 @$element[2]);
164 } else {
165 printf("Calls: %08d Ticks: %08d Symbol: %s\n",
166 @$element);
167 }
168 }
169}
170
171# merges two hashes
172sub merge_hashes {
173 my $hash1 = $_[0];
174 my $hash2 = $_[1];
175 return (%$hash1,%$hash2);
176}
177
178sub usage {
179 if (@_) {
180 print STDERR ("Error: @_\n");
181 }
182 print STDERR ("USAGE:\n");
183 print STDERR ("$0 profile.out map obj[...] [map obj[...]...] sort[...]\n");
184 print STDERR
185 ("\tprofile.out output from the profiler, extension is .out\n");
186 print STDERR
187 ("\tmap map file, extension is .map\n");
188 print STDERR
189 ("\tobj library or object file, extension is .a or .o\n");
190 print STDERR
191 ("\tformat 0-2[_p] 0: by calls, 1: by ticks, 2: by name\n");
192 print STDERR
193 ("\t _p shows percents instead of counts\n");
194 print STDERR ("NOTES:\n");
195 print STDERR
196 ("\tmaps and objects come in sets, one map then many objects\n");
197 exit(1);
198}
199
200
201if ($ARGV[0] =~ m/-(h|help|-help)/) {
202 usage();
203}
204if (@ARGV < 2) {
205 usage("Requires at least 2 arguments");
206}
207if ($ARGV[0] !~ m/\.out$/) {
208 usage("Profile file must end in .out");
209}
210my $i = 1;
211my %symbols;
212{
213 my %map;
214 for (; $i < @ARGV; $i++) {
215 my $file = $ARGV[$i];
216 if ($file =~ m/\.map$/) {
217 %map = read_map($file);
218 } elsif ($file =~ m/\.[ao]$/) {
219 if (!%map) {
220 usage("No map file found before first object file");
221 }
222 my @parts = split(/\//,$file);
223 my %new_symbols = read_library($file,$map{$parts[$#parts]});
224 %symbols = merge_hashes(\%symbols,\%new_symbols);
225 } else {
226 last;
227 }
228 }
229}
230if (!%symbols) {
231 warning("No symbols found");
232}
233my @pfds = create_list($ARGV[0],\%symbols);
234for (; $i < @ARGV; $i++) {
235 print_sorted(\@pfds,split("_",$ARGV[$i]));
236}