diff options
author | Michael Giacomelli <giac2000@hotmail.com> | 2008-07-28 22:43:41 +0000 |
---|---|---|
committer | Michael Giacomelli <giac2000@hotmail.com> | 2008-07-28 22:43:41 +0000 |
commit | 52bdcbae856b07d3a793615b98dff338d26302ec (patch) | |
tree | 9ee975d98287ca851664cbc626e7d006c0a4264b | |
parent | c323d533c29fcf420df6b63ccf5c37340c7ba6c5 (diff) | |
download | rockbox-52bdcbae856b07d3a793615b98dff338d26302ec.tar.gz rockbox-52bdcbae856b07d3a793615b98dff338d26302ec.zip |
Commit FS#9170 by Dave Hooper. Adds support for profiling on ARM, and fixes various issues with compiling profile builds. Also, note that profile_reader.pl syntax has changed.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18142 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | apps/codecs.c | 4 | ||||
-rw-r--r-- | apps/codecs/SOURCES | 2 | ||||
-rw-r--r-- | apps/plugin.c | 4 | ||||
-rw-r--r-- | apps/plugins/SUBDIRS | 4 | ||||
-rw-r--r-- | firmware/export/profile.h | 4 | ||||
-rw-r--r-- | firmware/profile.c | 23 | ||||
-rwxr-xr-x | tools/profile_reader/profile_reader.pl | 39 |
7 files changed, 52 insertions, 28 deletions
diff --git a/apps/codecs.c b/apps/codecs.c index c31fd843b3..24490dd04b 100644 --- a/apps/codecs.c +++ b/apps/codecs.c | |||
@@ -138,8 +138,8 @@ struct codec_api ci = { | |||
138 | #ifdef RB_PROFILE | 138 | #ifdef RB_PROFILE |
139 | profile_thread, | 139 | profile_thread, |
140 | profstop, | 140 | profstop, |
141 | profile_func_enter, | 141 | __cyg_profile_func_enter, |
142 | profile_func_exit, | 142 | __cyg_profile_func_exit, |
143 | #endif | 143 | #endif |
144 | 144 | ||
145 | #if defined(HAVE_RECORDING) && !defined(SIMULATOR) | 145 | #if defined(HAVE_RECORDING) && !defined(SIMULATOR) |
diff --git a/apps/codecs/SOURCES b/apps/codecs/SOURCES index 25ca5490d4..3038903f9e 100644 --- a/apps/codecs/SOURCES +++ b/apps/codecs/SOURCES | |||
@@ -7,7 +7,9 @@ wav.c | |||
7 | a52.c | 7 | a52.c |
8 | mpc.c | 8 | mpc.c |
9 | wavpack.c | 9 | wavpack.c |
10 | #ifndef RB_PROFILE | ||
10 | alac.c | 11 | alac.c |
12 | #endif | ||
11 | wma.c | 13 | wma.c |
12 | #if MEMORYSIZE > 1 | 14 | #if MEMORYSIZE > 1 |
13 | aac.c | 15 | aac.c |
diff --git a/apps/plugin.c b/apps/plugin.c index a220e8c429..24082de637 100644 --- a/apps/plugin.c +++ b/apps/plugin.c | |||
@@ -335,8 +335,8 @@ static const struct plugin_api rockbox_api = { | |||
335 | #ifdef RB_PROFILE | 335 | #ifdef RB_PROFILE |
336 | profile_thread, | 336 | profile_thread, |
337 | profstop, | 337 | profstop, |
338 | profile_func_enter, | 338 | __cyg_profile_func_enter, |
339 | profile_func_exit, | 339 | __cyg_profile_func_exit, |
340 | #endif | 340 | #endif |
341 | 341 | ||
342 | #ifdef SIMULATOR | 342 | #ifdef SIMULATOR |
diff --git a/apps/plugins/SUBDIRS b/apps/plugins/SUBDIRS index 94614e2f12..1b3e2af252 100644 --- a/apps/plugins/SUBDIRS +++ b/apps/plugins/SUBDIRS | |||
@@ -33,14 +33,18 @@ pacbox | |||
33 | /* For all the color targets */ | 33 | /* For all the color targets */ |
34 | #if defined(HAVE_LCD_COLOR) || defined(MROBE_100) || \ | 34 | #if defined(HAVE_LCD_COLOR) || defined(MROBE_100) || \ |
35 | (LCD_DEPTH == 2) && !defined(ARCHOS_AV300) | 35 | (LCD_DEPTH == 2) && !defined(ARCHOS_AV300) |
36 | #ifndef RB_PROFILE | ||
36 | doom | 37 | doom |
37 | #endif | 38 | #endif |
39 | #endif | ||
38 | 40 | ||
39 | /* For all the swcodec targets */ | 41 | /* For all the swcodec targets */ |
40 | #if CONFIG_CODEC == SWCODEC | 42 | #if CONFIG_CODEC == SWCODEC |
41 | midi | 43 | midi |
42 | /* beatbox */ | 44 | /* beatbox */ |
45 | #ifndef RB_PROFILE | ||
43 | mpegplayer | 46 | mpegplayer |
44 | #endif | 47 | #endif |
48 | #endif | ||
45 | 49 | ||
46 | #endif /* IRIVER_IFP7XX_SERIES */ | 50 | #endif /* IRIVER_IFP7XX_SERIES */ |
diff --git a/firmware/export/profile.h b/firmware/export/profile.h index d173f4b6e0..18a6f8679f 100644 --- a/firmware/export/profile.h +++ b/firmware/export/profile.h | |||
@@ -39,9 +39,9 @@ void profile_thread_stopped(int current_thread) | |||
39 | void profile_thread_started(int current_thread) | 39 | void profile_thread_started(int current_thread) |
40 | NO_PROF_ATTR; | 40 | NO_PROF_ATTR; |
41 | 41 | ||
42 | void profile_func_exit(void *this_fn, void *call_site) | 42 | void __cyg_profile_func_exit(void *this_fn, void *call_site) |
43 | NO_PROF_ATTR ICODE_ATTR; | 43 | NO_PROF_ATTR ICODE_ATTR; |
44 | void profile_func_enter(void *this_fn, void *call_site) | 44 | void __cyg_profile_func_enter(void *this_fn, void *call_site) |
45 | NO_PROF_ATTR ICODE_ATTR; | 45 | NO_PROF_ATTR ICODE_ATTR; |
46 | 46 | ||
47 | #endif /*_SYS_PROFILE_H*/ | 47 | #endif /*_SYS_PROFILE_H*/ |
diff --git a/firmware/profile.c b/firmware/profile.c index f84eebe3f1..cb68f18d8e 100644 --- a/firmware/profile.c +++ b/firmware/profile.c | |||
@@ -62,7 +62,6 @@ | |||
62 | #include <sys/types.h> | 62 | #include <sys/types.h> |
63 | #include "profile.h" | 63 | #include "profile.h" |
64 | 64 | ||
65 | |||
66 | /* PFD is Profiled Function Data */ | 65 | /* PFD is Profiled Function Data */ |
67 | 66 | ||
68 | /* Indices are shorts which means that we use 4k of RAM */ | 67 | /* Indices are shorts which means that we use 4k of RAM */ |
@@ -75,7 +74,7 @@ | |||
75 | * for profiling, and allows for profiling sections of code with up-to | 74 | * for profiling, and allows for profiling sections of code with up-to |
76 | * 1024 function caller->callee pairs | 75 | * 1024 function caller->callee pairs |
77 | */ | 76 | */ |
78 | #define NUMPFDS 1024 | 77 | #define NUMPFDS 512 |
79 | 78 | ||
80 | struct pfd_struct { | 79 | struct pfd_struct { |
81 | void *self_pc; | 80 | void *self_pc; |
@@ -141,7 +140,7 @@ void profile_thread_started(int current_thread) { | |||
141 | if (profiling < PROF_ERROR) { | 140 | if (profiling < PROF_ERROR) { |
142 | /* After we de-mask, if profiling is active, reactivate the timer */ | 141 | /* After we de-mask, if profiling is active, reactivate the timer */ |
143 | timer_register(0, profile_timer_unregister, | 142 | timer_register(0, profile_timer_unregister, |
144 | TIMER_FREQ/10000, 0, profile_timer_tick); | 143 | TIMER_FREQ/10000, 0, profile_timer_tick IF_COP(, 0 ) ); |
145 | } | 144 | } |
146 | } | 145 | } |
147 | } | 146 | } |
@@ -168,9 +167,9 @@ void profstart(int current_thread) { | |||
168 | last_pfd = (struct pfd_struct*)0; | 167 | last_pfd = (struct pfd_struct*)0; |
169 | pfds[0].link = 0; | 168 | pfds[0].link = 0; |
170 | pfds[0].self_pc = 0; | 169 | pfds[0].self_pc = 0; |
171 | memset(&indices,0,INDEX_SIZE * sizeof(unsigned short)); | 170 | memset(indices,0,INDEX_SIZE * sizeof(unsigned short)); |
172 | timer_register( | 171 | timer_register( |
173 | 0, profile_timer_unregister, TIMER_FREQ/10000, 0, profile_timer_tick); | 172 | 0, profile_timer_unregister, TIMER_FREQ/10000, 0, profile_timer_tick IF_COP(, 0 ) ); |
174 | profiling = PROF_ON; | 173 | profiling = PROF_ON; |
175 | } | 174 | } |
176 | 175 | ||
@@ -179,7 +178,7 @@ static void write_function_recursive(int fd, struct pfd_struct *pfd, int depth){ | |||
179 | fdprintf(fd,"0x%08lX\t%08ld\t%08ld\t%04d\n", (size_t)pfd->self_pc, | 178 | fdprintf(fd,"0x%08lX\t%08ld\t%08ld\t%04d\n", (size_t)pfd->self_pc, |
180 | pfd->count, pfd->time, depth); | 179 | pfd->count, pfd->time, depth); |
181 | if (link > 0 && link < NUMPFDS) { | 180 | if (link > 0 && link < NUMPFDS) { |
182 | write_function_recursive(fd, &pfds[link], depth++); | 181 | write_function_recursive(fd, &pfds[link], ++depth); |
183 | } | 182 | } |
184 | } | 183 | } |
185 | 184 | ||
@@ -206,7 +205,7 @@ void profstop() { | |||
206 | } | 205 | } |
207 | } | 206 | } |
208 | fdprintf(fd,"DEBUG PROFILE DATA FOLLOWS\n"); | 207 | fdprintf(fd,"DEBUG PROFILE DATA FOLLOWS\n"); |
209 | fdprintf(fd,"INDEX\tLOCATION\tSELF_PC\t\tCOUNT\t\tTIME\t\tLINK\tCALLER\n"); | 208 | fdprintf(fd,"INDEX\tLOCATION\tSELF_PC\t\tCOUNT\t\tTIME\t\tLINK\tCALLER_IDX\n"); |
210 | for (i = 0; i < NUMPFDS; i++) { | 209 | for (i = 0; i < NUMPFDS; i++) { |
211 | struct pfd_struct *my_last_pfd = &pfds[i]; | 210 | struct pfd_struct *my_last_pfd = &pfds[i]; |
212 | if (my_last_pfd->self_pc != 0) { | 211 | if (my_last_pfd->self_pc != 0) { |
@@ -214,7 +213,7 @@ void profstop() { | |||
214 | "%04d\t0x%08lX\t0x%08lX\t0x%08lX\t0x%08lX\t%04d\t0x%08lX\n", | 213 | "%04d\t0x%08lX\t0x%08lX\t0x%08lX\t0x%08lX\t%04d\t0x%08lX\n", |
215 | i, (size_t)my_last_pfd, (size_t)my_last_pfd->self_pc, | 214 | i, (size_t)my_last_pfd, (size_t)my_last_pfd->self_pc, |
216 | my_last_pfd->count, my_last_pfd->time, my_last_pfd->link, | 215 | my_last_pfd->count, my_last_pfd->time, my_last_pfd->link, |
217 | (size_t)my_last_pfd->caller); | 216 | (size_t)my_last_pfd->caller ); |
218 | } | 217 | } |
219 | } | 218 | } |
220 | fdprintf(fd,"INDEX_ADDRESS=INDEX\n"); | 219 | fdprintf(fd,"INDEX_ADDRESS=INDEX\n"); |
@@ -224,7 +223,7 @@ void profstop() { | |||
224 | close(fd); | 223 | close(fd); |
225 | } | 224 | } |
226 | 225 | ||
227 | void profile_func_exit(void *self_pc, void *call_site) { | 226 | void __cyg_profile_func_exit(void *self_pc, void *call_site) { |
228 | (void)call_site; | 227 | (void)call_site; |
229 | (void)self_pc; | 228 | (void)self_pc; |
230 | /* When we started timing, we set the time to the tick at that time | 229 | /* When we started timing, we set the time to the tick at that time |
@@ -255,7 +254,7 @@ void profile_func_exit(void *self_pc, void *call_site) { | |||
255 | pfd = &pfds[temp];\ | 254 | pfd = &pfds[temp];\ |
256 | pfd->self_pc = self_pc; pfd->count = 1; pfd->time = 0 | 255 | pfd->self_pc = self_pc; pfd->count = 1; pfd->time = 0 |
257 | 256 | ||
258 | void profile_func_enter(void *self_pc, void *from_pc) { | 257 | void __cyg_profile_func_enter(void *self_pc, void *from_pc) { |
259 | struct pfd_struct *pfd; | 258 | struct pfd_struct *pfd; |
260 | struct pfd_struct *prev_pfd; | 259 | struct pfd_struct *prev_pfd; |
261 | unsigned short *pfd_index_pointer; | 260 | unsigned short *pfd_index_pointer; |
@@ -339,3 +338,7 @@ overflow: | |||
339 | profiling = PROF_ERROR; | 338 | profiling = PROF_ERROR; |
340 | return; | 339 | return; |
341 | } | 340 | } |
341 | |||
342 | |||
343 | |||
344 | |||
diff --git a/tools/profile_reader/profile_reader.pl b/tools/profile_reader/profile_reader.pl index 6a45ddef02..ca40a901d8 100755 --- a/tools/profile_reader/profile_reader.pl +++ b/tools/profile_reader/profile_reader.pl | |||
@@ -36,11 +36,11 @@ sub read_map { | |||
36 | return %retval; | 36 | return %retval; |
37 | } | 37 | } |
38 | 38 | ||
39 | # string (filename.[ao]), hash(string:number) | 39 | # string (filename.(a|o|elf)), hash(number:string), string(objdump_tool) |
40 | # return hash(number:string) | 40 | # return hash(number:string) |
41 | sub read_library { | 41 | sub read_library { |
42 | open(OBJECT_FILE,"objdump -t $_[0] |") || | 42 | open(OBJECT_FILE,"$_[2] -t $_[0] |") || |
43 | error("Couldn't pipe objdump for $_[0]"); | 43 | error("Couldn't pipe objdump for $_[0]\nCommand was: $_[2] -t $_[0]"); |
44 | my $library = $_[1]; | 44 | my $library = $_[1]; |
45 | my %library = %$library; | 45 | my %library = %$library; |
46 | my %retval; | 46 | my %retval; |
@@ -62,7 +62,7 @@ sub read_library { | |||
62 | if ($parts[3] eq $parts[5]) { | 62 | if ($parts[3] eq $parts[5]) { |
63 | next; | 63 | next; |
64 | } | 64 | } |
65 | if ($parts[3] =~ m/\.(text|data|rodata|bss|icode|idata|irodata|ibss)/) { | 65 | if ($parts[3] =~ m/\.(text|data|rodata|bss|icode|idata|irodata|ibss|iram)/) { |
66 | my $region = $parts[3]; | 66 | my $region = $parts[3]; |
67 | my $symbolOffset = hex("0x" . $parts[0]); | 67 | my $symbolOffset = hex("0x" . $parts[0]); |
68 | my $sectionOffset = hex($library{$object . $region}); | 68 | my $sectionOffset = hex($library{$object . $region}); |
@@ -139,8 +139,16 @@ sub print_sorted { | |||
139 | my $totalCalls = 0; | 139 | my $totalCalls = 0; |
140 | my $totalTicks = 0; | 140 | my $totalTicks = 0; |
141 | $pfds = 0; | 141 | $pfds = 0; |
142 | |||
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 | ||
142 | foreach $element(@pfds) { | 147 | foreach $element(@pfds) { |
143 | $elements{@$element[$sort_index] . @$element[2]} = $element; | 148 | $ne = $element; |
149 | @$ne[0] = sprintf( "%08d", @$element[0]); | ||
150 | @$ne[1] = sprintf( "%08d", @$element[1]); | ||
151 | $elements{@$ne[$sort_index] . @$element[2]} = $element; | ||
144 | $pfds++; | 152 | $pfds++; |
145 | $totalCalls += @$element[0]; | 153 | $totalCalls += @$element[0]; |
146 | $totalTicks += @$element[1]; | 154 | $totalTicks += @$element[1]; |
@@ -174,13 +182,17 @@ sub usage { | |||
174 | print STDERR ("Error: @_\n"); | 182 | print STDERR ("Error: @_\n"); |
175 | } | 183 | } |
176 | print STDERR ("USAGE:\n"); | 184 | print STDERR ("USAGE:\n"); |
177 | print STDERR ("$0 profile.out map obj[...] [map obj[...]...] sort[...]\n"); | 185 | print STDERR ("$0 profile.out objdump_tool map obj[...] [map obj[...]...] sort[...]\n"); |
178 | print STDERR | 186 | print STDERR |
179 | ("\tprofile.out output from the profiler, extension is .out\n"); | 187 | ("\tprofile.out output from the profiler, extension is .out\n"); |
188 | print STDERR | ||
189 | ("\tobjdump_tool name of objdump executable for this platform\n"); | ||
190 | print STDERR | ||
191 | ("\t e.g. arm-elf-objdump\n"); | ||
180 | print STDERR | 192 | print STDERR |
181 | ("\tmap map file, extension is .map\n"); | 193 | ("\tmap map file, extension is .map\n"); |
182 | print STDERR | 194 | print STDERR |
183 | ("\tobj library or object file, extension is .a or .o\n"); | 195 | ("\tobj library or object file, extension is .a or .o or .elf\n"); |
184 | print STDERR | 196 | print STDERR |
185 | ("\tformat 0-2[_p] 0: by calls, 1: by ticks, 2: by name\n"); | 197 | ("\tformat 0-2[_p] 0: by calls, 1: by ticks, 2: by name\n"); |
186 | print STDERR | 198 | print STDERR |
@@ -195,13 +207,13 @@ sub usage { | |||
195 | if ($ARGV[0] =~ m/-(h|help|-help)/) { | 207 | if ($ARGV[0] =~ m/-(h|help|-help)/) { |
196 | usage(); | 208 | usage(); |
197 | } | 209 | } |
198 | if (@ARGV < 2) { | 210 | if (@ARGV < 3) { |
199 | usage("Requires at least 2 arguments"); | 211 | usage("Requires at least 3 arguments"); |
200 | } | 212 | } |
201 | if ($ARGV[0] !~ m/\.out$/) { | 213 | if ($ARGV[0] !~ m/\.out$/) { |
202 | usage("Profile file must end in .out"); | 214 | usage("Profile file must end in .out"); |
203 | } | 215 | } |
204 | my $i = 1; | 216 | my $i = 2; |
205 | my %symbols; | 217 | my %symbols; |
206 | { | 218 | { |
207 | my %map; | 219 | my %map; |
@@ -209,12 +221,12 @@ my %symbols; | |||
209 | my $file = $ARGV[$i]; | 221 | my $file = $ARGV[$i]; |
210 | if ($file =~ m/\.map$/) { | 222 | if ($file =~ m/\.map$/) { |
211 | %map = read_map($file); | 223 | %map = read_map($file); |
212 | } elsif ($file =~ m/\.[ao]$/) { | 224 | } elsif ($file =~ m/\.(a|o|elf)$/) { |
213 | if (!%map) { | 225 | if (!%map) { |
214 | usage("No map file found before first object file"); | 226 | usage("No map file found before first object file"); |
215 | } | 227 | } |
216 | my @parts = split(/\//,$file); | 228 | my @parts = split(/\//,$file); |
217 | my %new_symbols = read_library($file,$map{$parts[$#parts]}); | 229 | my %new_symbols = read_library($file,$map{$parts[$#parts]},$ARGV[1]); |
218 | %symbols = merge_hashes(\%symbols,\%new_symbols); | 230 | %symbols = merge_hashes(\%symbols,\%new_symbols); |
219 | } else { | 231 | } else { |
220 | last; | 232 | last; |
@@ -224,6 +236,9 @@ my %symbols; | |||
224 | if (!%symbols) { | 236 | if (!%symbols) { |
225 | warning("No symbols found"); | 237 | warning("No symbols found"); |
226 | } | 238 | } |
239 | if ($i >= @ARGV) { | ||
240 | error("You forgot to specify any sort ordering on output (e.g. 0, 1_p, 2)"); | ||
241 | } | ||
227 | my @pfds = create_list($ARGV[0],\%symbols); | 242 | my @pfds = create_list($ARGV[0],\%symbols); |
228 | for (; $i < @ARGV; $i++) { | 243 | for (; $i < @ARGV; $i++) { |
229 | print_sorted(\@pfds,split("_",$ARGV[$i])); | 244 | print_sorted(\@pfds,split("_",$ARGV[$i])); |