diff options
author | Pekka Enberg <penberg@cs.helsinki.fi> | 2009-06-08 14:12:48 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-06-08 17:10:44 -0400 |
commit | 80d496be89ed7dede5abee5c057634e80a31c82d (patch) | |
tree | f3a7d3b9f7d08fc300ae0c3ae1554598311fccb1 /tools | |
parent | dab5855b12411334355ba21349a06700e4ae7a3b (diff) |
perf report: Add support for profiling JIT generated code
This patch adds support for profiling JIT generated code to 'perf
report'. A JIT compiler is required to generate a "/tmp/perf-$PID.map"
symbols map that is parsed when looking and displaying symbols.
Thanks to Peter Zijlstra for his help with this patch!
Example "perf report" output with the Jato JIT:
#
# (40311 samples)
#
# Overhead Command Shared Object Symbol
# ........ ................ ......................... ......
#
97.80% jato /tmp/perf-11915.map [.] Fibonacci.fib(I)I
0.56% jato 00000000b7fa023b 0x000000b7fa023b
0.45% jato /tmp/perf-11915.map [.] Fibonacci.main([Ljava/lang/String;)V
0.38% jato [kernel] [k] get_page_from_freelist
0.06% jato [kernel] [k] kunmap_atomic
0.05% jato ./jato [.] utf8Hash
0.04% jato ./jato [.] executeJava
0.04% jato ./jato [.] defineClass
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Pekka Enberg <penberg@cs.helsinki.fi>
Cc: a.p.zijlstra@chello.nl
Cc: acme@redhat.com
LKML-Reference: <Pine.LNX.4.64.0906082111590.12407@melkki.cs.Helsinki.FI>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-report.c | 15 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 65 |
2 files changed, 79 insertions, 1 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index f053a7463dc..61d871849b4 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -209,6 +209,11 @@ static uint64_t vdso__map_ip(struct map *map, uint64_t ip) | |||
209 | return ip; | 209 | return ip; |
210 | } | 210 | } |
211 | 211 | ||
212 | static inline int is_anon_memory(const char *filename) | ||
213 | { | ||
214 | return strcmp(filename, "//anon") == 0; | ||
215 | } | ||
216 | |||
212 | static struct map *map__new(struct mmap_event *event) | 217 | static struct map *map__new(struct mmap_event *event) |
213 | { | 218 | { |
214 | struct map *self = malloc(sizeof(*self)); | 219 | struct map *self = malloc(sizeof(*self)); |
@@ -216,6 +221,7 @@ static struct map *map__new(struct mmap_event *event) | |||
216 | if (self != NULL) { | 221 | if (self != NULL) { |
217 | const char *filename = event->filename; | 222 | const char *filename = event->filename; |
218 | char newfilename[PATH_MAX]; | 223 | char newfilename[PATH_MAX]; |
224 | int anon; | ||
219 | 225 | ||
220 | if (cwd) { | 226 | if (cwd) { |
221 | int n = strcommon(filename); | 227 | int n = strcommon(filename); |
@@ -227,6 +233,13 @@ static struct map *map__new(struct mmap_event *event) | |||
227 | } | 233 | } |
228 | } | 234 | } |
229 | 235 | ||
236 | anon = is_anon_memory(filename); | ||
237 | |||
238 | if (anon) { | ||
239 | snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid); | ||
240 | filename = newfilename; | ||
241 | } | ||
242 | |||
230 | self->start = event->start; | 243 | self->start = event->start; |
231 | self->end = event->start + event->len; | 244 | self->end = event->start + event->len; |
232 | self->pgoff = event->pgoff; | 245 | self->pgoff = event->pgoff; |
@@ -235,7 +248,7 @@ static struct map *map__new(struct mmap_event *event) | |||
235 | if (self->dso == NULL) | 248 | if (self->dso == NULL) |
236 | goto out_delete; | 249 | goto out_delete; |
237 | 250 | ||
238 | if (self->dso == vdso) | 251 | if (self->dso == vdso || anon) |
239 | self->map_ip = vdso__map_ip; | 252 | self->map_ip = vdso__map_ip; |
240 | else | 253 | else |
241 | self->map_ip = map__map_ip; | 254 | self->map_ip = map__map_ip; |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 158588c7f6b..32dd47d60d9 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -220,6 +220,68 @@ out_failure: | |||
220 | return -1; | 220 | return -1; |
221 | } | 221 | } |
222 | 222 | ||
223 | static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verbose) | ||
224 | { | ||
225 | char *line = NULL; | ||
226 | size_t n; | ||
227 | FILE *file; | ||
228 | int nr_syms = 0; | ||
229 | |||
230 | file = fopen(self->name, "r"); | ||
231 | if (file == NULL) | ||
232 | goto out_failure; | ||
233 | |||
234 | while (!feof(file)) { | ||
235 | __u64 start, size; | ||
236 | struct symbol *sym; | ||
237 | int line_len, len; | ||
238 | |||
239 | line_len = getline(&line, &n, file); | ||
240 | if (line_len < 0) | ||
241 | break; | ||
242 | |||
243 | if (!line) | ||
244 | goto out_failure; | ||
245 | |||
246 | line[--line_len] = '\0'; /* \n */ | ||
247 | |||
248 | len = hex2u64(line, &start); | ||
249 | |||
250 | len++; | ||
251 | if (len + 2 >= line_len) | ||
252 | continue; | ||
253 | |||
254 | len += hex2u64(line + len, &size); | ||
255 | |||
256 | len++; | ||
257 | if (len + 2 >= line_len) | ||
258 | continue; | ||
259 | |||
260 | sym = symbol__new(start, size, line + len, | ||
261 | self->sym_priv_size, start, verbose); | ||
262 | |||
263 | if (sym == NULL) | ||
264 | goto out_delete_line; | ||
265 | |||
266 | if (filter && filter(self, sym)) | ||
267 | symbol__delete(sym, self->sym_priv_size); | ||
268 | else { | ||
269 | dso__insert_symbol(self, sym); | ||
270 | nr_syms++; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | free(line); | ||
275 | fclose(file); | ||
276 | |||
277 | return nr_syms; | ||
278 | |||
279 | out_delete_line: | ||
280 | free(line); | ||
281 | out_failure: | ||
282 | return -1; | ||
283 | } | ||
284 | |||
223 | /** | 285 | /** |
224 | * elf_symtab__for_each_symbol - iterate thru all the symbols | 286 | * elf_symtab__for_each_symbol - iterate thru all the symbols |
225 | * | 287 | * |
@@ -507,6 +569,9 @@ int dso__load(struct dso *self, symbol_filter_t filter, int verbose) | |||
507 | if (!name) | 569 | if (!name) |
508 | return -1; | 570 | return -1; |
509 | 571 | ||
572 | if (strncmp(self->name, "/tmp/perf-", 10) == 0) | ||
573 | return dso__load_perf_map(self, filter, verbose); | ||
574 | |||
510 | more: | 575 | more: |
511 | do { | 576 | do { |
512 | switch (variant) { | 577 | switch (variant) { |