summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorBrandon Low <lostlogic@rockbox.org>2006-01-18 20:54:13 +0000
committerBrandon Low <lostlogic@rockbox.org>2006-01-18 20:54:13 +0000
commit05dccc355144dc717b3cb9ef0074a9ab38a520f4 (patch)
tree0a36425cf1321817480a82ed05564a2790e2fca9 /tools
parent1060e447f83128a78dfaa8d59ba0baa642d15a4d (diff)
downloadrockbox-05dccc355144dc717b3cb9ef0074a9ab38a520f4.tar.gz
rockbox-05dccc355144dc717b3cb9ef0074a9ab38a520f4.zip
Profiling support, tools and documentation.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8375 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'tools')
-rw-r--r--tools/FILES1
-rwxr-xr-xtools/buildzip.pl1
-rwxr-xr-xtools/configure38
-rwxr-xr-xtools/profile_reader/profile_comparator.pl104
-rwxr-xr-xtools/profile_reader/profile_reader.pl236
5 files changed, 373 insertions, 7 deletions
diff --git a/tools/FILES b/tools/FILES
index 19d3a5576f..f4b1c6dca7 100644
--- a/tools/FILES
+++ b/tools/FILES
@@ -23,3 +23,4 @@ ucl/*.[ch]
23ucl/src/*.[ch] 23ucl/src/*.[ch]
24ucl/src/Makefile 24ucl/src/Makefile
25ucl/include/ucl/*.h 25ucl/include/ucl/*.h
26profile_reader/*.pl
diff --git a/tools/buildzip.pl b/tools/buildzip.pl
index eabf739d0d..934b0035e4 100755
--- a/tools/buildzip.pl
+++ b/tools/buildzip.pl
@@ -199,6 +199,7 @@ sub buildzip {
199 "CUSTOM_CFG_FORMAT", 199 "CUSTOM_CFG_FORMAT",
200 "CUSTOM_WPS_FORMAT", 200 "CUSTOM_WPS_FORMAT",
201 "FAQ", 201 "FAQ",
202 "LICENSES",
202 "NODO", 203 "NODO",
203 "TECH")) { 204 "TECH")) {
204 `cp $ROOT/docs/$_ .rockbox/docs/$_.txt`; 205 `cp $ROOT/docs/$_ .rockbox/docs/$_.txt`;
diff --git a/tools/configure b/tools/configure
index 2cd855e0c5..2bea201324 100755
--- a/tools/configure
+++ b/tools/configure
@@ -240,7 +240,7 @@ whichdevel () {
240 # 240 #
241 echo "" 241 echo ""
242 echo "Enter your developer options (press enter when done)" 242 echo "Enter your developer options (press enter when done)"
243 echo "(D)EBUG, (L)ogf, (S)imulator" 243 echo "(D)EBUG, (L)ogf, (S)imulator, (P)rofiling"
244 cont=1 244 cont=1
245 245
246 while [ $cont = "1" ]; do 246 while [ $cont = "1" ]; do
@@ -249,19 +249,29 @@ whichdevel () {
249 249
250 case $option in 250 case $option in
251 [Dd]) 251 [Dd])
252 echo "define DEBUG" 252 if [ "yes" = "$profile" ]; then
253 debug="-DDEBUG" 253 echo "Debug is incompatible with profiling"
254 GCCOPTS="$GCCOPTS -g -DDEBUG" 254 else
255 echo "define DEBUG"
256 use_debug="yes"
257 fi
255 ;; 258 ;;
256 [Ll]) 259 [Ll])
257 logf="yes"
258 echo "logf() support enabled" 260 echo "logf() support enabled"
259 use_logf="#define ROCKBOX_HAS_LOGF 1" 261 logf="yes"
260 ;; 262 ;;
261 [Ss]) 263 [Ss])
262 echo "Simulator build enabled" 264 echo "Simulator build enabled"
263 simulator="yes" 265 simulator="yes"
264 ;; 266 ;;
267 [Pp])
268 if [ "yes" = "$use_debug" ]; then
269 echo "Profiling is incompatible with debug"
270 else
271 echo "Profiling support is enabled"
272 profile="yes"
273 fi
274 ;;
265 *) 275 *)
266 echo "done" 276 echo "done"
267 cont=0 277 cont=0
@@ -269,11 +279,23 @@ whichdevel () {
269 esac 279 esac
270 done 280 done
271 281
282 if [ "yes" = "$use_debug" ]; then
283 debug="-DDEBUG"
284 GCCOPTS="$GCCOPTS -g -DDEBUG"
285 fi
286 if [ "yes" = "$logf" ]; then
287 use_logf="#define ROCKBOX_HAS_LOGF 1"
288 fi
272 if [ "yes" = "$simulator" ]; then 289 if [ "yes" = "$simulator" ]; then
273 debug="-DDEBUG" 290 debug="-DDEBUG"
274 extradefines="-DSIMULATOR" 291 extradefines="$extradefines -DSIMULATOR"
275 whichsim 292 whichsim
276 fi 293 fi
294 if [ "yes" = "$profile" ]; then
295 extradefines="$extradefines -DRB_PROFILE"
296 PROFILE_OPTS="-finstrument-functions"
297 GCCOPTS="$GCCOPTS $GCCOPTIMIZE"
298 fi
277} 299}
278 300
279whichsim () { 301whichsim () {
@@ -902,6 +924,7 @@ sed > Makefile \
902 -e "s,@FLASHFILE@,${flash},g" \ 924 -e "s,@FLASHFILE@,${flash},g" \
903 -e "s,@PLUGINS@,${plugins},g" \ 925 -e "s,@PLUGINS@,${plugins},g" \
904 -e "s,@CODECS@,${codecs},g" \ 926 -e "s,@CODECS@,${codecs},g" \
927 -e "s,@PROFILE_OPTS@,${PROFILE_OPTS},g" \
905 -e "s,@GCCOPTS@,${GCCOPTS},g" \ 928 -e "s,@GCCOPTS@,${GCCOPTS},g" \
906 -e "s!@LDOPTS@!${LDOPTS}!g" \ 929 -e "s!@LDOPTS@!${LDOPTS}!g" \
907 -e "s,@LOADADDRESS@,${loadaddress},g" \ 930 -e "s,@LOADADDRESS@,${loadaddress},g" \
@@ -952,6 +975,7 @@ export WINDRES=@WINDRES@
952export DLLTOOL=@DLLTOOL@ 975export DLLTOOL=@DLLTOOL@
953export DLLWRAP=@DLLWRAP@ 976export DLLWRAP=@DLLWRAP@
954export RANLIB=@RANLIB@ 977export RANLIB=@RANLIB@
978export PROFILE_OPTS=@PROFILE_OPTS@
955export GCCOPTS=@GCCOPTS@ 979export GCCOPTS=@GCCOPTS@
956export LOADADDRESS=@LOADADDRESS@ 980export LOADADDRESS=@LOADADDRESS@
957export SIMVER=@SIMVER@ 981export SIMVER=@SIMVER@
diff --git a/tools/profile_reader/profile_comparator.pl b/tools/profile_reader/profile_comparator.pl
new file mode 100755
index 0000000000..da5e3004c9
--- /dev/null
+++ b/tools/profile_reader/profile_comparator.pl
@@ -0,0 +1,104 @@
1#!/usr/bin/perl
2sub error {
3 print("Error: @_\n");
4 exit(1);
5}
6sub usage {
7 if (@_) {
8 print STDERR ("Error: @_\n");
9 }
10 print STDERR ("USAGE:\n");
11 print STDERR ("$0 file1 file2 [showcalldiff]\n");
12 print STDERR
13 ("\tfile[12] output from profile_reader.pl to compare\n");
14 print STDERR
15 ("\tshowcalldiff show the percent change in calls instead of ticks\n");
16 exit(1);
17}
18if ($ARGV[0] =~ m/-(h|help|-help)/) {
19 usage();
20}
21if (@ARGV < 2) {
22 usage("Requires at least 2 arguments");
23}
24open(FILE1,shift) || error("Couldn't open file1");
25my @file1 = <FILE1>;
26close(FILE1);
27open(FILE2,shift) || error("Couldn't open file2");
28my @file2 = <FILE2>;
29close(FILE2);
30my $showcalldiff = shift;
31my %calls1;
32my %calls2;
33my @calls = (\%calls1,\%calls2);
34my $start = 0;
35my @files = (\@file1,\@file2);
36my @allcalls = (0,0);
37my @allticks = (0,0);
38for ( $i=0; $i <= $#files; $i++ ) {
39 my $file = $files[$i];
40 foreach $line(@$file) {
41 chomp($line);
42 if ( $line =~ m/By calls/ ) {
43 $start = 1;
44 next;
45 }
46 if ( $line =~ m/By ticks/ ) {
47 $start = 0;
48 last;
49 }
50 if ( $start == 1) {
51 my @line = split(/[[:space:]]+/,$line);
52 $allcalls[$i] += $line[1];
53 $allticks[$i] += $line[3];
54 $calls[$i]{$line[5]} = [($line[1],$line[3])];
55 }
56 }
57}
58printf("File one calls: %08ld, ticks: %08ld\n",$allcalls[0],$allticks[0]);
59printf("File two calls: %08ld, ticks: %08ld\n",$allcalls[1],$allticks[1]);
60printf("Percent change: %+7.2f%%, ticks: %+7.2f%%\n",
61 ($allcalls[1]-$allcalls[0])/$allcalls[0]*100,
62 ($allticks[1]-$allticks[0])/$allticks[0]*100);
63my @allkeys = keys(%calls1);
64push(@allkeys,keys(%calls2));
65my %u = ();
66my @keys = grep {defined} map {
67 if (exists $u{$_}) { undef; } else { $u{$_}=undef;$_; }
68} @allkeys;
69undef %u;
70my %byticks;
71my %bycalls;
72foreach $key(@keys) {
73 my $values1 = $calls1{$key};
74 my $values2 = $calls2{$key};
75 my $calldiff = @$values2[0]-@$values1[0];
76 my $totalcalls = @$values2[0]+@$values1[0];
77 my $tickdiff = @$values2[1]-@$values1[1];
78 my $totalticks = @$values2[1]+@$values1[1];
79 my $pdiff;
80 my $result;
81 if ($showcalldiff) {
82 $pdiff = $calldiff/(@$values1[0]>0?@$values1[0]:1)*100;
83 $result = sprintf("%+7.2f%% Calls: %+09d Symbol: %s$key\n",
84 $pdiff, $calldiff,
85 (exists $calls1{$key} && exists $calls2{$key})?"":"LONE ");
86 } else {
87 $pdiff = $tickdiff/(@$values1[1]>0?@$values1[1]:1)*100;
88 $result = sprintf("%+7.2f%% Ticks: %+09d Symbol: %s$key\n",
89 $pdiff, $tickdiff,
90 (exists $calls1{$key} && exists $calls2{$key})?"":"LONE ");
91 }
92 $bycalls{sprintf("%08X$key",$totalcalls)} = $result;
93 $byticks{sprintf("%08X$key",$totalticks)} = $result;
94}
95my @calls = sort(keys(%bycalls));
96print("By calls\n");
97foreach $call(@calls) {
98 print($bycalls{$call});
99}
100my @ticks = sort(keys(%byticks));
101print("By ticks\n");
102foreach $tick(@ticks) {
103 print($byticks{$tick});
104}
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}