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>
This commit is contained in:
parent
dab5855b12
commit
80d496be89
@ -209,6 +209,11 @@ static uint64_t vdso__map_ip(struct map *map, uint64_t ip)
|
||||
return ip;
|
||||
}
|
||||
|
||||
static inline int is_anon_memory(const char *filename)
|
||||
{
|
||||
return strcmp(filename, "//anon") == 0;
|
||||
}
|
||||
|
||||
static struct map *map__new(struct mmap_event *event)
|
||||
{
|
||||
struct map *self = malloc(sizeof(*self));
|
||||
@ -216,6 +221,7 @@ static struct map *map__new(struct mmap_event *event)
|
||||
if (self != NULL) {
|
||||
const char *filename = event->filename;
|
||||
char newfilename[PATH_MAX];
|
||||
int anon;
|
||||
|
||||
if (cwd) {
|
||||
int n = strcommon(filename);
|
||||
@ -227,6 +233,13 @@ static struct map *map__new(struct mmap_event *event)
|
||||
}
|
||||
}
|
||||
|
||||
anon = is_anon_memory(filename);
|
||||
|
||||
if (anon) {
|
||||
snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", event->pid);
|
||||
filename = newfilename;
|
||||
}
|
||||
|
||||
self->start = event->start;
|
||||
self->end = event->start + event->len;
|
||||
self->pgoff = event->pgoff;
|
||||
@ -235,7 +248,7 @@ static struct map *map__new(struct mmap_event *event)
|
||||
if (self->dso == NULL)
|
||||
goto out_delete;
|
||||
|
||||
if (self->dso == vdso)
|
||||
if (self->dso == vdso || anon)
|
||||
self->map_ip = vdso__map_ip;
|
||||
else
|
||||
self->map_ip = map__map_ip;
|
||||
|
@ -220,6 +220,68 @@ out_failure:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int dso__load_perf_map(struct dso *self, symbol_filter_t filter, int verbose)
|
||||
{
|
||||
char *line = NULL;
|
||||
size_t n;
|
||||
FILE *file;
|
||||
int nr_syms = 0;
|
||||
|
||||
file = fopen(self->name, "r");
|
||||
if (file == NULL)
|
||||
goto out_failure;
|
||||
|
||||
while (!feof(file)) {
|
||||
__u64 start, size;
|
||||
struct symbol *sym;
|
||||
int line_len, len;
|
||||
|
||||
line_len = getline(&line, &n, file);
|
||||
if (line_len < 0)
|
||||
break;
|
||||
|
||||
if (!line)
|
||||
goto out_failure;
|
||||
|
||||
line[--line_len] = '\0'; /* \n */
|
||||
|
||||
len = hex2u64(line, &start);
|
||||
|
||||
len++;
|
||||
if (len + 2 >= line_len)
|
||||
continue;
|
||||
|
||||
len += hex2u64(line + len, &size);
|
||||
|
||||
len++;
|
||||
if (len + 2 >= line_len)
|
||||
continue;
|
||||
|
||||
sym = symbol__new(start, size, line + len,
|
||||
self->sym_priv_size, start, verbose);
|
||||
|
||||
if (sym == NULL)
|
||||
goto out_delete_line;
|
||||
|
||||
if (filter && filter(self, sym))
|
||||
symbol__delete(sym, self->sym_priv_size);
|
||||
else {
|
||||
dso__insert_symbol(self, sym);
|
||||
nr_syms++;
|
||||
}
|
||||
}
|
||||
|
||||
free(line);
|
||||
fclose(file);
|
||||
|
||||
return nr_syms;
|
||||
|
||||
out_delete_line:
|
||||
free(line);
|
||||
out_failure:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* elf_symtab__for_each_symbol - iterate thru all the symbols
|
||||
*
|
||||
@ -507,6 +569,9 @@ int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
|
||||
if (!name)
|
||||
return -1;
|
||||
|
||||
if (strncmp(self->name, "/tmp/perf-", 10) == 0)
|
||||
return dso__load_perf_map(self, filter, verbose);
|
||||
|
||||
more:
|
||||
do {
|
||||
switch (variant) {
|
||||
|
Loading…
Reference in New Issue
Block a user