diff options
Diffstat (limited to 'tools/perf/util')
| -rw-r--r-- | tools/perf/util/callchain.c | 32 | ||||
| -rw-r--r-- | tools/perf/util/callchain.h | 8 | ||||
| -rw-r--r-- | tools/perf/util/header.c | 5 | ||||
| -rw-r--r-- | tools/perf/util/parse-events.c | 36 | ||||
| -rw-r--r-- | tools/perf/util/parse-events.h | 1 | ||||
| -rw-r--r-- | tools/perf/util/symbol.c | 72 | ||||
| -rw-r--r-- | tools/perf/util/symbol.h | 26 | 
7 files changed, 139 insertions, 41 deletions
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 9d3c8141b8c..01147341164 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c @@ -13,6 +13,7 @@  #include <stdio.h>  #include <stdbool.h>  #include <errno.h> +#include <math.h>  #include "callchain.h" @@ -26,10 +27,14 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,  	struct rb_node **p = &root->rb_node;  	struct rb_node *parent = NULL;  	struct callchain_node *rnode; +	u64 chain_cumul = cumul_hits(chain);  	while (*p) { +		u64 rnode_cumul; +  		parent = *p;  		rnode = rb_entry(parent, struct callchain_node, rb_node); +		rnode_cumul = cumul_hits(rnode);  		switch (mode) {  		case CHAIN_FLAT: @@ -40,7 +45,7 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,  			break;  		case CHAIN_GRAPH_ABS: /* Falldown */  		case CHAIN_GRAPH_REL: -			if (rnode->cumul_hit < chain->cumul_hit) +			if (rnode_cumul < chain_cumul)  				p = &(*p)->rb_left;  			else  				p = &(*p)->rb_right; @@ -87,7 +92,7 @@ static void __sort_chain_graph_abs(struct callchain_node *node,  	chain_for_each_child(child, node) {  		__sort_chain_graph_abs(child, min_hit); -		if (child->cumul_hit >= min_hit) +		if (cumul_hits(child) >= min_hit)  			rb_insert_callchain(&node->rb_root, child,  					    CHAIN_GRAPH_ABS);  	} @@ -108,11 +113,11 @@ static void __sort_chain_graph_rel(struct callchain_node *node,  	u64 min_hit;  	node->rb_root = RB_ROOT; -	min_hit = node->cumul_hit * min_percent / 100.0; +	min_hit = ceil(node->children_hit * min_percent);  	chain_for_each_child(child, node) {  		__sort_chain_graph_rel(child, min_percent); -		if (child->cumul_hit >= min_hit) +		if (cumul_hits(child) >= min_hit)  			rb_insert_callchain(&node->rb_root, child,  					    CHAIN_GRAPH_REL);  	} @@ -122,7 +127,7 @@ static void  sort_chain_graph_rel(struct rb_root *rb_root, struct callchain_node *chain_root,  		     u64 min_hit __used, struct callchain_param *param)  { -	__sort_chain_graph_rel(chain_root, param->min_percent); +	__sort_chain_graph_rel(chain_root, param->min_percent / 100.0);  	rb_root->rb_node = chain_root->rb_root.rb_node;  } @@ -211,7 +216,8 @@ add_child(struct callchain_node *parent, struct ip_callchain *chain,  	new = create_child(parent, false);  	fill_node(new, chain, start, syms); -	new->cumul_hit = new->hit = 1; +	new->children_hit = 0; +	new->hit = 1;  }  /* @@ -241,7 +247,8 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain,  	/* split the hits */  	new->hit = parent->hit; -	new->cumul_hit = parent->cumul_hit; +	new->children_hit = parent->children_hit; +	parent->children_hit = cumul_hits(new);  	new->val_nr = parent->val_nr - idx_local;  	parent->val_nr = idx_local; @@ -249,6 +256,7 @@ split_add_child(struct callchain_node *parent, struct ip_callchain *chain,  	if (idx_total < chain->nr) {  		parent->hit = 0;  		add_child(parent, chain, idx_total, syms); +		parent->children_hit++;  	} else {  		parent->hit = 1;  	} @@ -269,13 +277,13 @@ __append_chain_children(struct callchain_node *root, struct ip_callchain *chain,  		unsigned int ret = __append_chain(rnode, chain, start, syms);  		if (!ret) -			goto cumul; +			goto inc_children_hit;  	}  	/* nothing in children, add to the current node */  	add_child(root, chain, start, syms); -cumul: -	root->cumul_hit++; +inc_children_hit: +	root->children_hit++;  }  static int @@ -317,8 +325,6 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,  	/* we match 100% of the path, increment the hit */  	if (i - start == root->val_nr && i == chain->nr) {  		root->hit++; -		root->cumul_hit++; -  		return 0;  	} @@ -331,5 +337,7 @@ __append_chain(struct callchain_node *root, struct ip_callchain *chain,  void append_chain(struct callchain_node *root, struct ip_callchain *chain,  		  struct symbol **syms)  { +	if (!chain->nr) +		return;  	__append_chain_children(root, chain, syms, 0);  } diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index 7812122bea1..a926ae4f5a1 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h @@ -7,6 +7,7 @@  #include "symbol.h"  enum chain_mode { +	CHAIN_NONE,  	CHAIN_FLAT,  	CHAIN_GRAPH_ABS,  	CHAIN_GRAPH_REL @@ -21,7 +22,7 @@ struct callchain_node {  	struct rb_root		rb_root; /* sorted tree of children */  	unsigned int		val_nr;  	u64			hit; -	u64			cumul_hit; /* hit + hits of children */ +	u64			children_hit;  };  struct callchain_param; @@ -48,6 +49,11 @@ static inline void callchain_init(struct callchain_node *node)  	INIT_LIST_HEAD(&node->val);  } +static inline u64 cumul_hits(struct callchain_node *node) +{ +	return node->hit + node->children_hit; +} +  int register_callchain_param(struct callchain_param *param);  void append_chain(struct callchain_node *root, struct ip_callchain *chain,  		  struct symbol **syms); diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 450384b3bbe..b92a457ca32 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -185,6 +185,8 @@ static void do_read(int fd, void *buf, size_t size)  		if (ret < 0)  			die("failed to read"); +		if (ret == 0) +			die("failed to read: missing data");  		size -= ret;  		buf += ret; @@ -213,9 +215,10 @@ struct perf_header *perf_header__read(int fd)  	for (i = 0; i < nr_attrs; i++) {  		struct perf_header_attr *attr; -		off_t tmp = lseek(fd, 0, SEEK_CUR); +		off_t tmp;  		do_read(fd, &f_attr, sizeof(f_attr)); +		tmp = lseek(fd, 0, SEEK_CUR);  		attr = perf_header_attr__new(&f_attr.attr); diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 7bdad8df22a..04417840878 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -121,13 +121,29 @@ static unsigned long hw_cache_stat[C(MAX)] = {  	   (strcmp(sys_dirent.d_name, ".")) &&				       \  	   (strcmp(sys_dirent.d_name, ".."))) +static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) +{ +	char evt_path[MAXPATHLEN]; +	int fd; + +	snprintf(evt_path, MAXPATHLEN, "%s/%s/%s/id", debugfs_path, +			sys_dir->d_name, evt_dir->d_name); +	fd = open(evt_path, O_RDONLY); +	if (fd < 0) +		return -EINVAL; +	close(fd); + +	return 0; +} +  #define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next, file, st)    \  	while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next)        \  	if (snprintf(file, MAXPATHLEN, "%s/%s/%s", debugfs_path,	       \  		     sys_dirent.d_name, evt_dirent.d_name) &&		       \  	   (!stat(file, &st)) && (S_ISDIR(st.st_mode)) &&		       \  	   (strcmp(evt_dirent.d_name, ".")) &&				       \ -	   (strcmp(evt_dirent.d_name, ".."))) +	   (strcmp(evt_dirent.d_name, "..")) &&				       \ +	   (!tp_event_has_id(&sys_dirent, &evt_dirent)))  #define MAX_EVENT_LENGTH 30 @@ -223,9 +239,15 @@ char *event_name(int counter)  {  	u64 config = attrs[counter].config;  	int type = attrs[counter].type; + +	return __event_name(type, config); +} + +char *__event_name(int type, u64 config) +{  	static char buf[32]; -	if (attrs[counter].type == PERF_TYPE_RAW) { +	if (type == PERF_TYPE_RAW) {  		sprintf(buf, "raw 0x%llx", config);  		return buf;  	} @@ -357,6 +379,7 @@ static int parse_tracepoint_event(const char **strp,  				    struct perf_counter_attr *attr)  {  	const char *evt_name; +	char *flags;  	char sys_name[MAX_EVENT_LENGTH];  	char id_buf[4];  	int fd; @@ -378,6 +401,15 @@ static int parse_tracepoint_event(const char **strp,  	strncpy(sys_name, *strp, sys_length);  	sys_name[sys_length] = '\0';  	evt_name = evt_name + 1; + +	flags = strchr(evt_name, ':'); +	if (flags) { +		*flags = '\0'; +		flags++; +		if (!strncmp(flags, "record", strlen(flags))) +			attr->sample_type |= PERF_SAMPLE_RAW; +	} +  	evt_length = strlen(evt_name);  	if (evt_length >= MAX_EVENT_LENGTH)  		return 0; diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h index 1ea5d09b6eb..192a962e3a0 100644 --- a/tools/perf/util/parse-events.h +++ b/tools/perf/util/parse-events.h @@ -10,6 +10,7 @@ extern int			nr_counters;  extern struct perf_counter_attr attrs[MAX_COUNTERS];  extern char *event_name(int ctr); +extern char *__event_name(int type, u64 config);  extern int parse_events(const struct option *opt, const char *str, int unset); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 16ddca20294..5c0f42e6b33 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -7,22 +7,17 @@  #include <gelf.h>  #include <elf.h> -#ifndef NO_DEMANGLE -#include <bfd.h> -#else -static inline -char *bfd_demangle(void __used *v, const char __used *c, int __used i) -{ -	return NULL; -} -#endif -  const char *sym_hist_filter; -#ifndef DMGL_PARAMS -#define DMGL_PARAMS      (1 << 0)       /* Include function args */ -#define DMGL_ANSI        (1 << 1)       /* Include const, volatile, etc */ -#endif +enum dso_origin { +	DSO__ORIG_KERNEL = 0, +	DSO__ORIG_JAVA_JIT, +	DSO__ORIG_FEDORA, +	DSO__ORIG_UBUNTU, +	DSO__ORIG_BUILDID, +	DSO__ORIG_DSO, +	DSO__ORIG_NOT_FOUND, +};  static struct symbol *symbol__new(u64 start, u64 len,  				  const char *name, unsigned int priv_size, @@ -81,6 +76,7 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size)  		self->sym_priv_size = sym_priv_size;  		self->find_symbol = dso__find_symbol;  		self->slen_calculated = 0; +		self->origin = DSO__ORIG_NOT_FOUND;  	}  	return self; @@ -710,7 +706,7 @@ static char *dso__read_build_id(struct dso *self, int verbose)  		++raw;  		bid += 2;  	} -	if (verbose) +	if (verbose >= 2)  		printf("%s(%s): %s\n", __func__, self->name, build_id);  out_elf_end:  	elf_end(elf); @@ -720,11 +716,26 @@ out:  	return build_id;  } +char dso__symtab_origin(const struct dso *self) +{ +	static const char origin[] = { +		[DSO__ORIG_KERNEL] =   'k', +		[DSO__ORIG_JAVA_JIT] = 'j', +		[DSO__ORIG_FEDORA] =   'f', +		[DSO__ORIG_UBUNTU] =   'u', +		[DSO__ORIG_BUILDID] =  'b', +		[DSO__ORIG_DSO] =      'd', +	}; + +	if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) +		return '!'; +	return origin[self->origin]; +} +  int dso__load(struct dso *self, symbol_filter_t filter, int verbose)  {  	int size = PATH_MAX;  	char *name = malloc(size), *build_id = NULL; -	int variant = 0;  	int ret = -1;  	int fd; @@ -733,19 +744,26 @@ int dso__load(struct dso *self, symbol_filter_t filter, int verbose)  	self->adjust_symbols = 0; -	if (strncmp(self->name, "/tmp/perf-", 10) == 0) -		return dso__load_perf_map(self, filter, verbose); +	if (strncmp(self->name, "/tmp/perf-", 10) == 0) { +		ret = dso__load_perf_map(self, filter, verbose); +		self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : +					 DSO__ORIG_NOT_FOUND; +		return ret; +	} + +	self->origin = DSO__ORIG_FEDORA - 1;  more:  	do { -		switch (variant) { -		case 0: /* Fedora */ +		self->origin++; +		switch (self->origin) { +		case DSO__ORIG_FEDORA:  			snprintf(name, size, "/usr/lib/debug%s.debug", self->name);  			break; -		case 1: /* Ubuntu */ +		case DSO__ORIG_UBUNTU:  			snprintf(name, size, "/usr/lib/debug%s", self->name);  			break; -		case 2: +		case DSO__ORIG_BUILDID:  			build_id = dso__read_build_id(self, verbose);  			if (build_id != NULL) {  				snprintf(name, size, @@ -754,16 +772,15 @@ more:  				free(build_id);  				break;  			} -			variant++; +			self->origin++;  			/* Fall thru */ -		case 3: /* Sane people */ +		case DSO__ORIG_DSO:  			snprintf(name, size, "%s", self->name);  			break;  		default:  			goto out;  		} -		variant++;  		fd = open(name, O_RDONLY);  	} while (fd < 0); @@ -784,6 +801,8 @@ more:  	}  out:  	free(name); +	if (ret < 0 && strstr(self->name, " (deleted)") != NULL) +		return 0;  	return ret;  } @@ -899,6 +918,9 @@ int dso__load_kernel(struct dso *self, const char *vmlinux,  	if (err <= 0)  		err = dso__load_kallsyms(self, filter, verbose); +	if (err > 0) +		self->origin = DSO__ORIG_KERNEL; +  	return err;  } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 2f92b21c712..b53bf0125c1 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -7,6 +7,30 @@  #include <linux/rbtree.h>  #include "module.h" +#ifdef HAVE_CPLUS_DEMANGLE +extern char *cplus_demangle(const char *, int); + +static inline char *bfd_demangle(void __used *v, const char *c, int i) +{ +	return cplus_demangle(c, i); +} +#else +#ifdef NO_DEMANGLE +static inline char *bfd_demangle(void __used *v, const char __used *c, +				 int __used i) +{ +	return NULL; +} +#else +#include <bfd.h> +#endif +#endif + +#ifndef DMGL_PARAMS +#define DMGL_PARAMS      (1 << 0)       /* Include function args */ +#define DMGL_ANSI        (1 << 1)       /* Include const, volatile, etc */ +#endif +  struct symbol {  	struct rb_node	rb_node;  	u64		start; @@ -26,6 +50,7 @@ struct dso {  	unsigned int	 sym_priv_size;  	unsigned char	 adjust_symbols;  	unsigned char	 slen_calculated; +	unsigned char	 origin;  	char		 name[0];  }; @@ -49,6 +74,7 @@ int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose);  int dso__load(struct dso *self, symbol_filter_t filter, int verbose);  size_t dso__fprintf(struct dso *self, FILE *fp); +char dso__symtab_origin(const struct dso *self);  void symbol__init(void);  #endif /* _PERF_SYMBOL_ */  |