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