diff options
Diffstat (limited to 'tools/perf/util')
| -rw-r--r-- | tools/perf/util/cpumap.c | 59 | ||||
| -rw-r--r-- | tools/perf/util/cpumap.h | 7 | ||||
| -rw-r--r-- | tools/perf/util/event.h | 9 | ||||
| -rw-r--r-- | tools/perf/util/hist.c | 50 | ||||
| -rw-r--r-- | tools/perf/util/hist.h | 12 | ||||
| -rw-r--r-- | tools/perf/util/probe-event.c | 2 | ||||
| -rw-r--r-- | tools/perf/util/probe-finder.c | 20 | ||||
| -rw-r--r-- | tools/perf/util/probe-finder.h | 1 | ||||
| -rw-r--r-- | tools/perf/util/scripting-engines/trace-event-python.c | 17 | ||||
| -rw-r--r-- | tools/perf/util/session.c | 1 | ||||
| -rw-r--r-- | tools/perf/util/session.h | 1 | ||||
| -rw-r--r-- | tools/perf/util/symbol.c | 18 | ||||
| -rw-r--r-- | tools/perf/util/symbol.h | 3 | ||||
| -rw-r--r-- | tools/perf/util/thread.c | 41 | ||||
| -rw-r--r-- | tools/perf/util/thread.h | 3 | 
15 files changed, 186 insertions, 58 deletions
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c new file mode 100644 index 00000000000..4e01490e51e --- /dev/null +++ b/tools/perf/util/cpumap.c @@ -0,0 +1,59 @@ +#include "util.h" +#include "../perf.h" +#include "cpumap.h" +#include <assert.h> +#include <stdio.h> + +int cpumap[MAX_NR_CPUS]; + +static int default_cpu_map(void) +{ +	int nr_cpus, i; + +	nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); +	assert(nr_cpus <= MAX_NR_CPUS); +	assert((int)nr_cpus >= 0); + +	for (i = 0; i < nr_cpus; ++i) +		cpumap[i] = i; + +	return nr_cpus; +} + +int read_cpu_map(void) +{ +	FILE *onlnf; +	int nr_cpus = 0; +	int n, cpu, prev; +	char sep; + +	onlnf = fopen("/sys/devices/system/cpu/online", "r"); +	if (!onlnf) +		return default_cpu_map(); + +	sep = 0; +	prev = -1; +	for (;;) { +		n = fscanf(onlnf, "%u%c", &cpu, &sep); +		if (n <= 0) +			break; +		if (prev >= 0) { +			assert(nr_cpus + cpu - prev - 1 < MAX_NR_CPUS); +			while (++prev < cpu) +				cpumap[nr_cpus++] = prev; +		} +		assert (nr_cpus < MAX_NR_CPUS); +		cpumap[nr_cpus++] = cpu; +		if (n == 2 && sep == '-') +			prev = cpu; +		else +			prev = -1; +		if (n == 1 || sep == '\n') +			break; +	} +	fclose(onlnf); +	if (nr_cpus > 0) +		return nr_cpus; + +	return default_cpu_map(); +} diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h new file mode 100644 index 00000000000..86c78bb3309 --- /dev/null +++ b/tools/perf/util/cpumap.h @@ -0,0 +1,7 @@ +#ifndef __PERF_CPUMAP_H +#define __PERF_CPUMAP_H + +extern int read_cpu_map(void); +extern int cpumap[]; + +#endif /* __PERF_CPUMAP_H */ diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 50a7132887f..a33b94952e3 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h @@ -99,6 +99,15 @@ struct events_stats {  	u64 lost;  }; +struct event_stat_id { +	struct rb_node		rb_node; +	struct rb_root		hists; +	struct events_stats	stats; +	u64			config; +	u64			event_stream; +	u32			type; +}; +  void event__print_totals(void);  struct perf_session; diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 44408c2621c..2be33c7dbf0 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -12,12 +12,12 @@ struct callchain_param	callchain_param = {   * histogram, sorted on item, collects counts   */ -struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self, +struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists,  						  struct addr_location *al,  						  struct symbol *sym_parent,  						  u64 count, bool *hit)  { -	struct rb_node **p = &self->hists.rb_node; +	struct rb_node **p = &hists->rb_node;  	struct rb_node *parent = NULL;  	struct hist_entry *he;  	struct hist_entry entry = { @@ -53,7 +53,7 @@ struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self,  		return NULL;  	*he = entry;  	rb_link_node(&he->rb_node, parent, p); -	rb_insert_color(&he->rb_node, &self->hists); +	rb_insert_color(&he->rb_node, hists);  	*hit = false;  	return he;  } @@ -130,7 +130,7 @@ static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)  	rb_insert_color(&he->rb_node, root);  } -void perf_session__collapse_resort(struct perf_session *self) +void perf_session__collapse_resort(struct rb_root *hists)  {  	struct rb_root tmp;  	struct rb_node *next; @@ -140,17 +140,17 @@ void perf_session__collapse_resort(struct perf_session *self)  		return;  	tmp = RB_ROOT; -	next = rb_first(&self->hists); +	next = rb_first(hists);  	while (next) {  		n = rb_entry(next, struct hist_entry, rb_node);  		next = rb_next(&n->rb_node); -		rb_erase(&n->rb_node, &self->hists); +		rb_erase(&n->rb_node, hists);  		collapse__insert_entry(&tmp, n);  	} -	self->hists = tmp; +	*hists = tmp;  }  /* @@ -183,7 +183,7 @@ static void perf_session__insert_output_hist_entry(struct rb_root *root,  	rb_insert_color(&he->rb_node, root);  } -void perf_session__output_resort(struct perf_session *self, u64 total_samples) +void perf_session__output_resort(struct rb_root *hists, u64 total_samples)  {  	struct rb_root tmp;  	struct rb_node *next; @@ -194,18 +194,18 @@ void perf_session__output_resort(struct perf_session *self, u64 total_samples)  		total_samples * (callchain_param.min_percent / 100);  	tmp = RB_ROOT; -	next = rb_first(&self->hists); +	next = rb_first(hists);  	while (next) {  		n = rb_entry(next, struct hist_entry, rb_node);  		next = rb_next(&n->rb_node); -		rb_erase(&n->rb_node, &self->hists); +		rb_erase(&n->rb_node, hists);  		perf_session__insert_output_hist_entry(&tmp, n,  						       min_callchain_hits);  	} -	self->hists = tmp; +	*hists = tmp;  }  static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) @@ -456,10 +456,10 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,  }  static size_t hist_entry__fprintf(struct hist_entry *self, -				  struct perf_session *session,  				  struct perf_session *pair_session,  				  bool show_displacement, -				  long displacement, FILE *fp) +				  long displacement, FILE *fp, +				  u64 session_total)  {  	struct sort_entry *se;  	u64 count, total; @@ -474,7 +474,7 @@ static size_t hist_entry__fprintf(struct hist_entry *self,  		total = pair_session->events_stats.total;  	} else {  		count = self->count; -		total = session->events_stats.total; +		total = session_total;  	}  	if (total) @@ -496,8 +496,8 @@ static size_t hist_entry__fprintf(struct hist_entry *self,  		if (total > 0)  			old_percent = (count * 100.0) / total; -		if (session->events_stats.total > 0) -			new_percent = (self->count * 100.0) / session->events_stats.total; +		if (session_total > 0) +			new_percent = (self->count * 100.0) / session_total;  		diff = new_percent - old_percent; @@ -544,16 +544,17 @@ static size_t hist_entry__fprintf(struct hist_entry *self,  			left_margin -= thread__comm_len(self->thread);  		} -		hist_entry_callchain__fprintf(fp, self, session->events_stats.total, +		hist_entry_callchain__fprintf(fp, self, session_total,  					      left_margin);  	}  	return ret;  } -size_t perf_session__fprintf_hists(struct perf_session *self, +size_t perf_session__fprintf_hists(struct rb_root *hists,  				   struct perf_session *pair, -				   bool show_displacement, FILE *fp) +				   bool show_displacement, FILE *fp, +				   u64 session_total)  {  	struct sort_entry *se;  	struct rb_node *nd; @@ -641,7 +642,7 @@ size_t perf_session__fprintf_hists(struct perf_session *self,  	fprintf(fp, "\n#\n");  print_entries: -	for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) { +	for (nd = rb_first(hists); nd; nd = rb_next(nd)) {  		struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);  		if (show_displacement) { @@ -652,8 +653,13 @@ print_entries:  				displacement = 0;  			++position;  		} -		ret += hist_entry__fprintf(h, self, pair, show_displacement, -					   displacement, fp); +		ret += hist_entry__fprintf(h, pair, show_displacement, +					   displacement, fp, session_total); +		if (h->map == NULL && verbose > 1) { +			__map_groups__fprintf_maps(&h->thread->mg, +						   MAP__FUNCTION, fp); +			fprintf(fp, "%.10s end\n", graph_dotted_line); +		}  	}  	free(rem_sq_bracket); diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index e5f99b24048..16f360cce5b 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -10,8 +10,9 @@ struct perf_session;  struct hist_entry;  struct addr_location;  struct symbol; +struct rb_root; -struct hist_entry *__perf_session__add_hist_entry(struct perf_session *self, +struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists,  						  struct addr_location *al,  						  struct symbol *parent,  						  u64 count, bool *hit); @@ -19,9 +20,10 @@ extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);  extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);  void hist_entry__free(struct hist_entry *); -void perf_session__output_resort(struct perf_session *self, u64 total_samples); -void perf_session__collapse_resort(struct perf_session *self); -size_t perf_session__fprintf_hists(struct perf_session *self, +void perf_session__output_resort(struct rb_root *hists, u64 total_samples); +void perf_session__collapse_resort(struct rb_root *hists); +size_t perf_session__fprintf_hists(struct rb_root *hists,  				   struct perf_session *pair, -				   bool show_displacement, FILE *fp); +				   bool show_displacement, FILE *fp, +				   u64 session_total);  #endif	/* __PERF_HIST_H */ diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 53181dbfe4a..7c004b6ef24 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -242,7 +242,7 @@ void parse_perf_probe_event(const char *str, struct probe_point *pp,  	/* Parse probe point */  	parse_perf_probe_probepoint(argv[0], pp); -	if (pp->file || pp->line) +	if (pp->file || pp->line || pp->lazy_line)  		*need_dwarf = true;  	/* Copy arguments and ensure return probe has no C argument */ diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index e77dc886760..c171a243d05 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -169,7 +169,7 @@ static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)  {  	Dwarf_Files *files;  	size_t nfiles, i; -	const char *src; +	const char *src = NULL;  	int ret;  	if (!fname) @@ -333,8 +333,8 @@ static void show_location(Dwarf_Op *op, struct probe_finder *pf)  		die("%u exceeds max register number.", regn);  	if (deref) -		ret = snprintf(pf->buf, pf->len, " %s=+%ju(%s)", -			       pf->var, (uintmax_t)offs, regs); +		ret = snprintf(pf->buf, pf->len, " %s=%+jd(%s)", +			       pf->var, (intmax_t)offs, regs);  	else  		ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);  	DIE_IF(ret < 0); @@ -352,8 +352,7 @@ static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf)  	if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)  		goto error;  	/* TODO: handle more than 1 exprs */ -	ret = dwarf_getlocation_addr(&attr, (pf->addr - pf->cu_base), -				     &expr, &nexpr, 1); +	ret = dwarf_getlocation_addr(&attr, pf->addr, &expr, &nexpr, 1);  	if (ret <= 0 || nexpr == 0)  		goto error; @@ -437,8 +436,7 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)  	/* Get the frame base attribute/ops */  	dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); -	ret = dwarf_getlocation_addr(&fb_attr, (pf->addr - pf->cu_base), -				     &pf->fb_ops, &nops, 1); +	ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);  	if (ret <= 0 || nops == 0)  		pf->fb_ops = NULL; @@ -455,6 +453,9 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)  	/* *pf->fb_ops will be cached in libdw. Don't free it. */  	pf->fb_ops = NULL; +	if (pp->found == MAX_PROBES) +		die("Too many( > %d) probe point found.\n", MAX_PROBES); +  	pp->probes[pp->found] = strdup(tmp);  	pp->found++;  } @@ -641,7 +642,6 @@ static void find_probe_point_by_func(struct probe_finder *pf)  int find_probe_point(int fd, struct probe_point *pp)  {  	struct probe_finder pf = {.pp = pp}; -	int ret;  	Dwarf_Off off, noff;  	size_t cuhl;  	Dwarf_Die *diep; @@ -668,10 +668,6 @@ int find_probe_point(int fd, struct probe_point *pp)  			pf.fname = NULL;  		if (!pp->file || pf.fname) { -			/* Save CU base address (for frame_base) */ -			ret = dwarf_lowpc(&pf.cu_die, &pf.cu_base); -			if (ret != 0) -				pf.cu_base = 0;  			if (pp->function)  				find_probe_point_by_func(&pf);  			else if (pp->lazy_line) diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index d1a651793ba..21f7354397b 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h @@ -71,7 +71,6 @@ struct probe_finder {  	/* For variable searching */  	Dwarf_Op		*fb_ops;	/* Frame base attribute */ -	Dwarf_Addr		cu_base;	/* Current CU base address */  	const char		*var;		/* Current variable name */  	char			*buf;		/* Current output buffer */  	int			len;		/* Length of output buffer */ diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 33a414bbba3..6a72f14c598 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -208,7 +208,7 @@ static void python_process_event(int cpu, void *data,  				 int size __unused,  				 unsigned long long nsecs, char *comm)  { -	PyObject *handler, *retval, *context, *t; +	PyObject *handler, *retval, *context, *t, *obj;  	static char handler_name[256];  	struct format_field *field;  	unsigned long long val; @@ -256,16 +256,23 @@ static void python_process_event(int cpu, void *data,  				offset &= 0xffff;  			} else  				offset = field->offset; -			PyTuple_SetItem(t, n++, -				PyString_FromString((char *)data + offset)); +			obj = PyString_FromString((char *)data + offset);  		} else { /* FIELD_IS_NUMERIC */  			val = read_size(data + field->offset, field->size);  			if (field->flags & FIELD_IS_SIGNED) { -				PyTuple_SetItem(t, n++, PyInt_FromLong(val)); +				if ((long long)val >= LONG_MIN && +				    (long long)val <= LONG_MAX) +					obj = PyInt_FromLong(val); +				else +					obj = PyLong_FromLongLong(val);  			} else { -				PyTuple_SetItem(t, n++, PyInt_FromLong(val)); +				if (val <= LONG_MAX) +					obj = PyInt_FromLong(val); +				else +					obj = PyLong_FromUnsignedLongLong(val);  			}  		} +		PyTuple_SetItem(t, n++, obj);  	}  	if (_PyTuple_Resize(&t, n) == -1) diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 0de7258e70a..eed1cb88900 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -70,6 +70,7 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc  	memcpy(self->filename, filename, len);  	self->threads = RB_ROOT; +	self->stats_by_id = RB_ROOT;  	self->last_match = NULL;  	self->mmap_window = 32;  	self->cwd = NULL; diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 31950fcd8a4..5c33417eebb 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h @@ -20,6 +20,7 @@ struct perf_session {  	struct thread		*last_match;  	struct map		*vmlinux_maps[MAP__NR_TYPES];  	struct events_stats	events_stats; +	struct rb_root		stats_by_id;  	unsigned long		event_total[PERF_RECORD_MAX];  	unsigned long		unknown_events;  	struct rb_root		hists; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 323c0aea0a9..c458c4a371d 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -163,9 +163,17 @@ void dso__set_long_name(struct dso *self, char *name)  	self->long_name_len = strlen(name);  } +static void dso__set_short_name(struct dso *self, const char *name) +{ +	if (name == NULL) +		return; +	self->short_name = name; +	self->short_name_len = strlen(name); +} +  static void dso__set_basename(struct dso *self)  { -	self->short_name = basename(self->long_name); +	dso__set_short_name(self, basename(self->long_name));  }  struct dso *dso__new(const char *name) @@ -176,7 +184,7 @@ struct dso *dso__new(const char *name)  		int i;  		strcpy(self->name, name);  		dso__set_long_name(self, self->name); -		self->short_name = self->name; +		dso__set_short_name(self, self->name);  		for (i = 0; i < MAP__NR_TYPES; ++i)  			self->symbols[i] = self->symbol_names[i] = RB_ROOT;  		self->slen_calculated = 0; @@ -897,7 +905,6 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,  	struct kmap *kmap = self->kernel ? map__kmap(map) : NULL;  	struct map *curr_map = map;  	struct dso *curr_dso = self; -	size_t dso_name_len = strlen(self->short_name);  	Elf_Data *symstrs, *secstrs;  	uint32_t nr_syms;  	int err = -1; @@ -987,7 +994,8 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,  			char dso_name[PATH_MAX];  			if (strcmp(section_name, -				   curr_dso->short_name + dso_name_len) == 0) +				   (curr_dso->short_name + +				    self->short_name_len)) == 0)  				goto new_symbol;  			if (strcmp(section_name, ".text") == 0) { @@ -1782,7 +1790,7 @@ struct dso *dso__new_kernel(const char *name)  	struct dso *self = dso__new(name ?: "[kernel.kallsyms]");  	if (self != NULL) { -		self->short_name = "[kernel]"; +		dso__set_short_name(self, "[kernel]");  		self->kernel	 = 1;  	} diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 280dadd32a0..f30a3742891 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -110,9 +110,10 @@ struct dso {  	u8		 sorted_by_name;  	u8		 loaded;  	u8		 build_id[BUILD_ID_SIZE]; -	u16		 long_name_len;  	const char	 *short_name;  	char	 	 *long_name; +	u16		 long_name_len; +	u16		 short_name_len;  	char		 name[0];  }; diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 21b92162282..fa968312ee7 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -79,8 +79,8 @@ int thread__comm_len(struct thread *self)  	return self->comm_len;  } -static size_t __map_groups__fprintf_maps(struct map_groups *self, -					 enum map_type type, FILE *fp) +size_t __map_groups__fprintf_maps(struct map_groups *self, +				  enum map_type type, FILE *fp)  {  	size_t printed = fprintf(fp, "%s:\n", map_type__name[type]);  	struct rb_node *nd; @@ -89,7 +89,7 @@ static size_t __map_groups__fprintf_maps(struct map_groups *self,  		struct map *pos = rb_entry(nd, struct map, rb_node);  		printed += fprintf(fp, "Map:");  		printed += map__fprintf(pos, fp); -		if (verbose > 1) { +		if (verbose > 2) {  			printed += dso__fprintf(pos->dso, type, fp);  			printed += fprintf(fp, "--\n");  		} @@ -183,8 +183,8 @@ struct thread *perf_session__findnew(struct perf_session *self, pid_t pid)  	return th;  } -static void map_groups__remove_overlappings(struct map_groups *self, -					    struct map *map) +static int map_groups__fixup_overlappings(struct map_groups *self, +					  struct map *map)  {  	struct rb_root *root = &self->maps[map->type];  	struct rb_node *next = rb_first(root); @@ -209,7 +209,36 @@ static void map_groups__remove_overlappings(struct map_groups *self,  		 * list.  		 */  		list_add_tail(&pos->node, &self->removed_maps[map->type]); +		/* +		 * Now check if we need to create new maps for areas not +		 * overlapped by the new map: +		 */ +		if (map->start > pos->start) { +			struct map *before = map__clone(pos); + +			if (before == NULL) +				return -ENOMEM; + +			before->end = map->start - 1; +			map_groups__insert(self, before); +			if (verbose >= 2) +				map__fprintf(before, stderr); +		} + +		if (map->end < pos->end) { +			struct map *after = map__clone(pos); + +			if (after == NULL) +				return -ENOMEM; + +			after->start = map->end + 1; +			map_groups__insert(self, after); +			if (verbose >= 2) +				map__fprintf(after, stderr); +		}  	} + +	return 0;  }  void maps__insert(struct rb_root *maps, struct map *map) @@ -254,7 +283,7 @@ struct map *maps__find(struct rb_root *maps, u64 ip)  void thread__insert_map(struct thread *self, struct map *map)  { -	map_groups__remove_overlappings(&self->mg, map); +	map_groups__fixup_overlappings(&self->mg, map);  	map_groups__insert(&self->mg, map);  } diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 0a28f39de54..dcf70303e58 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -10,6 +10,9 @@ struct map_groups {  	struct list_head	removed_maps[MAP__NR_TYPES];  }; +size_t __map_groups__fprintf_maps(struct map_groups *self, +				  enum map_type type, FILE *fp); +  struct thread {  	struct rb_node		rb_node;  	struct map_groups	mg;  |