diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/perf/.gitignore | 2 | ||||
| -rw-r--r-- | tools/perf/Makefile | 25 | ||||
| -rw-r--r-- | tools/perf/builtin-report.c | 17 | ||||
| -rw-r--r-- | tools/perf/builtin-sched.c | 1 | ||||
| -rw-r--r-- | tools/perf/builtin-test.c | 30 | ||||
| -rw-r--r-- | tools/perf/builtin-top.c | 36 | ||||
| -rw-r--r-- | tools/perf/perf-archive.sh | 3 | ||||
| -rw-r--r-- | tools/perf/util/annotate.c | 16 | ||||
| -rw-r--r-- | tools/perf/util/hist.c | 12 | ||||
| -rw-r--r-- | tools/perf/util/map.c | 1 | ||||
| -rw-r--r-- | tools/perf/util/map.h | 1 | ||||
| -rw-r--r-- | tools/perf/util/parse-events.l | 2 | ||||
| -rw-r--r-- | tools/perf/util/session.c | 16 | ||||
| -rw-r--r-- | tools/perf/util/symbol.c | 13 | ||||
| -rw-r--r-- | tools/perf/util/ui/browsers/hists.c | 3 | 
15 files changed, 135 insertions, 43 deletions
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore index 416684be0ad..26b823b61aa 100644 --- a/tools/perf/.gitignore +++ b/tools/perf/.gitignore @@ -19,3 +19,5 @@ TAGS  cscope*  config.mak  config.mak.autogen +*-bison.* +*-flex.* diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 820371f10d1..9bf3fc75934 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -234,24 +234,23 @@ endif  export PERL_PATH -FLEX = $(CROSS_COMPILE)flex -BISON= $(CROSS_COMPILE)bison +FLEX = flex +BISON= bison -event-parser: -	$(QUIET_BISON)$(BISON) -v util/parse-events.y -d -o $(OUTPUT)util/parse-events-bison.c +$(OUTPUT)util/parse-events-flex.c: util/parse-events.l  	$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/parse-events-flex.h -t util/parse-events.l > $(OUTPUT)util/parse-events-flex.c -$(OUTPUT)util/parse-events-flex.c: event-parser -$(OUTPUT)util/parse-events-bison.c: event-parser +$(OUTPUT)util/parse-events-bison.c: util/parse-events.y +	$(QUIET_BISON)$(BISON) -v util/parse-events.y -d -o $(OUTPUT)util/parse-events-bison.c -pmu-parser: -	$(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c +$(OUTPUT)util/pmu-flex.c: util/pmu.l  	$(QUIET_FLEX)$(FLEX) --header-file=$(OUTPUT)util/pmu-flex.h -t util/pmu.l > $(OUTPUT)util/pmu-flex.c -$(OUTPUT)util/pmu-flex.c: pmu-parser -$(OUTPUT)util/pmu-bison.c: pmu-parser +$(OUTPUT)util/pmu-bison.c: util/pmu.y +	$(QUIET_BISON)$(BISON) -v util/pmu.y -d -o $(OUTPUT)util/pmu-bison.c -$(OUTPUT)util/parse-events.o: event-parser pmu-parser +$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c +$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c  LIB_FILE=$(OUTPUT)libperf.a @@ -527,7 +526,7 @@ else  endif  ifdef NO_GTK2 -	BASIC_CFLAGS += -DNO_GTK2 +	BASIC_CFLAGS += -DNO_GTK2_SUPPORT  else  	FLAGS_GTK2=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) $(shell pkg-config --libs --cflags gtk+-2.0)  	ifneq ($(call try-cc,$(SOURCE_GTK2),$(FLAGS_GTK2)),y) @@ -852,8 +851,6 @@ help:  	@echo '  html		- make html documentation'  	@echo '  info		- make GNU info documentation (access with info <foo>)'  	@echo '  pdf		- make pdf documentation' -	@echo '  event-parser	- make event parser code' -	@echo '  pmu-parser	- make pmu format parser code'  	@echo '  TAGS		- use etags to make tag information for source browsing'  	@echo '  tags		- use ctags to make tag information for source browsing'  	@echo '  cscope	- use cscope to make interactive browsing database' diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 2e317438980..cdae9b2db1c 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -374,16 +374,23 @@ static int __cmd_report(struct perf_report *rep)  	    (kernel_map->dso->hit &&  	     (kernel_kmap->ref_reloc_sym == NULL ||  	      kernel_kmap->ref_reloc_sym->addr == 0))) { -		const struct dso *kdso = kernel_map->dso; +		const char *desc = +		    "As no suitable kallsyms nor vmlinux was found, kernel samples\n" +		    "can't be resolved."; + +		if (kernel_map) { +			const struct dso *kdso = kernel_map->dso; +			if (!RB_EMPTY_ROOT(&kdso->symbols[MAP__FUNCTION])) { +				desc = "If some relocation was applied (e.g. " +				       "kexec) symbols may be misresolved."; +			} +		}  		ui__warning(  "Kernel address maps (/proc/{kallsyms,modules}) were restricted.\n\n"  "Check /proc/sys/kernel/kptr_restrict before running 'perf record'.\n\n%s\n\n"  "Samples in kernel modules can't be resolved as well.\n\n", -			    RB_EMPTY_ROOT(&kdso->symbols[MAP__FUNCTION]) ? -"As no suitable kallsyms nor vmlinux was found, kernel samples\n" -"can't be resolved." : -"If some relocation was applied (e.g. kexec) symbols may be misresolved."); +		desc);  	}  	if (dump_trace) { diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index fb8b5f83b4a..1cad3af4bf4 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -17,6 +17,7 @@  #include "util/debug.h"  #include <sys/prctl.h> +#include <sys/resource.h>  #include <semaphore.h>  #include <pthread.h> diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 1c5b9801ac6..223ffdcc0fd 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c @@ -851,6 +851,28 @@ static int test__checkevent_symbolic_name_modifier(struct perf_evlist *evlist)  	return test__checkevent_symbolic_name(evlist);  } +static int test__checkevent_exclude_host_modifier(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong exclude guest", !evsel->attr.exclude_guest); +	TEST_ASSERT_VAL("wrong exclude host", evsel->attr.exclude_host); + +	return test__checkevent_symbolic_name(evlist); +} + +static int test__checkevent_exclude_guest_modifier(struct perf_evlist *evlist) +{ +	struct perf_evsel *evsel = list_entry(evlist->entries.next, +					      struct perf_evsel, node); + +	TEST_ASSERT_VAL("wrong exclude guest", evsel->attr.exclude_guest); +	TEST_ASSERT_VAL("wrong exclude host", !evsel->attr.exclude_host); + +	return test__checkevent_symbolic_name(evlist); +} +  static int test__checkevent_symbolic_alias_modifier(struct perf_evlist *evlist)  {  	struct perf_evsel *evsel = list_entry(evlist->entries.next, @@ -1091,6 +1113,14 @@ static struct test__event_st {  		.name  = "r1,syscalls:sys_enter_open:k,1:1:hp",  		.check = test__checkevent_list,  	}, +	{ +		.name  = "instructions:G", +		.check = test__checkevent_exclude_host_modifier, +	}, +	{ +		.name  = "instructions:H", +		.check = test__checkevent_exclude_guest_modifier, +	},  };  #define TEST__EVENTS_CNT (sizeof(test__events) / sizeof(struct test__event_st)) diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index e3c63aef8ef..8ef59f8262b 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -42,6 +42,7 @@  #include "util/debug.h"  #include <assert.h> +#include <elf.h>  #include <fcntl.h>  #include <stdio.h> @@ -59,6 +60,7 @@  #include <sys/prctl.h>  #include <sys/wait.h>  #include <sys/uio.h> +#include <sys/utsname.h>  #include <sys/mman.h>  #include <linux/unistd.h> @@ -162,12 +164,40 @@ static void __zero_source_counters(struct hist_entry *he)  	symbol__annotate_zero_histograms(sym);  } +static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip) +{ +	struct utsname uts; +	int err = uname(&uts); + +	ui__warning("Out of bounds address found:\n\n" +		    "Addr:   %" PRIx64 "\n" +		    "DSO:    %s %c\n" +		    "Map:    %" PRIx64 "-%" PRIx64 "\n" +		    "Symbol: %" PRIx64 "-%" PRIx64 " %c %s\n" +		    "Arch:   %s\n" +		    "Kernel: %s\n" +		    "Tools:  %s\n\n" +		    "Not all samples will be on the annotation output.\n\n" +		    "Please report to linux-kernel@vger.kernel.org\n", +		    ip, map->dso->long_name, dso__symtab_origin(map->dso), +		    map->start, map->end, sym->start, sym->end, +		    sym->binding == STB_GLOBAL ? 'g' : +		    sym->binding == STB_LOCAL  ? 'l' : 'w', sym->name, +		    err ? "[unknown]" : uts.machine, +		    err ? "[unknown]" : uts.release, perf_version_string); +	if (use_browser <= 0) +		sleep(5); +	 +	map->erange_warned = true; +} +  static void perf_top__record_precise_ip(struct perf_top *top,  					struct hist_entry *he,  					int counter, u64 ip)  {  	struct annotation *notes;  	struct symbol *sym; +	int err;  	if (he == NULL || he->ms.sym == NULL ||  	    ((top->sym_filter_entry == NULL || @@ -189,9 +219,12 @@ static void perf_top__record_precise_ip(struct perf_top *top,  	}  	ip = he->ms.map->map_ip(he->ms.map, ip); -	symbol__inc_addr_samples(sym, he->ms.map, counter, ip); +	err = symbol__inc_addr_samples(sym, he->ms.map, counter, ip);  	pthread_mutex_unlock(¬es->lock); + +	if (err == -ERANGE && !he->ms.map->erange_warned) +		ui__warn_map_erange(he->ms.map, sym, ip);  }  static void perf_top__show_details(struct perf_top *top) @@ -615,6 +648,7 @@ process_hotkey:  /* Tag samples to be skipped. */  static const char *skip_symbols[] = { +	"intel_idle",  	"default_idle",  	"native_safe_halt",  	"cpu_idle", diff --git a/tools/perf/perf-archive.sh b/tools/perf/perf-archive.sh index 677e59d62a8..95b6f8b6177 100644 --- a/tools/perf/perf-archive.sh +++ b/tools/perf/perf-archive.sh @@ -29,13 +29,14 @@ if [ ! -s $BUILDIDS ] ; then  fi  MANIFEST=$(mktemp /tmp/perf-archive-manifest.XXXXXX) +PERF_BUILDID_LINKDIR=$(readlink -f $PERF_BUILDID_DIR)/  cut -d ' ' -f 1 $BUILDIDS | \  while read build_id ; do  	linkname=$PERF_BUILDID_DIR.build-id/${build_id:0:2}/${build_id:2}  	filename=$(readlink -f $linkname)  	echo ${linkname#$PERF_BUILDID_DIR} >> $MANIFEST -	echo ${filename#$PERF_BUILDID_DIR} >> $MANIFEST +	echo ${filename#$PERF_BUILDID_LINKDIR} >> $MANIFEST  done  tar cfj $PERF_DATA.tar.bz2 -C $PERF_BUILDID_DIR -T $MANIFEST diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 199f69ec656..08c6d138a65 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -64,8 +64,8 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map,  	pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); -	if (addr > sym->end) -		return 0; +	if (addr < sym->start || addr > sym->end) +		return -ERANGE;  	offset = addr - sym->start;  	h = annotation__histogram(notes, evidx); @@ -561,16 +561,12 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)  {  	struct annotation *notes = symbol__annotation(sym);  	struct sym_hist *h = annotation__histogram(notes, evidx); -	struct objdump_line *pos; -	int len = sym->end - sym->start; +	int len = sym->end - sym->start, offset;  	h->sum = 0; - -	list_for_each_entry(pos, ¬es->src->source, node) { -		if (pos->offset != -1 && pos->offset < len) { -			h->addr[pos->offset] = h->addr[pos->offset] * 7 / 8; -			h->sum += h->addr[pos->offset]; -		} +	for (offset = 0; offset < len; ++offset) { +		h->addr[offset] = h->addr[offset] * 7 / 8; +		h->sum += h->addr[offset];  	}  } diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 2ec4b60aff6..9f6d630d531 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -256,6 +256,18 @@ static struct hist_entry *add_hist_entry(struct hists *hists,  		if (!cmp) {  			he->period += period;  			++he->nr_events; + +			/* If the map of an existing hist_entry has +			 * become out-of-date due to an exec() or +			 * similar, update it.  Otherwise we will +			 * mis-adjust symbol addresses when computing +			 * the history counter to increment. +			 */ +			if (he->ms.map != entry->ms.map) { +				he->ms.map = entry->ms.map; +				if (he->ms.map) +					he->ms.map->referenced = true; +			}  			goto out;  		} diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index dea6d1c1a95..35ae56864e4 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -38,6 +38,7 @@ void map__init(struct map *self, enum map_type type,  	RB_CLEAR_NODE(&self->rb_node);  	self->groups   = NULL;  	self->referenced = false; +	self->erange_warned = false;  }  struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index b100c20b7f9..81371bad4ef 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -33,6 +33,7 @@ struct map {  	u64			end;  	u8 /* enum map_type */	type;  	bool			referenced; +	bool			erange_warned;  	u32			priv;  	u64			pgoff; diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index 05d766e3ecb..1fcf1bbc545 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -54,7 +54,7 @@ num_dec		[0-9]+  num_hex		0x[a-fA-F0-9]+  num_raw_hex	[a-fA-F0-9]+  name		[a-zA-Z_*?][a-zA-Z0-9_*?]* -modifier_event	[ukhp]{1,5} +modifier_event	[ukhpGH]{1,8}  modifier_bp	[rwx]  %% diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 9412e3b05f6..1efd3bee633 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -826,8 +826,16 @@ static struct machine *  {  	const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; -	if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) -		return perf_session__find_machine(session, event->ip.pid); +	if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) { +		u32 pid; + +		if (event->header.type == PERF_RECORD_MMAP) +			pid = event->mmap.pid; +		else +			pid = event->ip.pid; + +		return perf_session__find_machine(session, pid); +	}  	return perf_session__find_host_machine(session);  } @@ -868,11 +876,11 @@ static int perf_session_deliver_event(struct perf_session *session,  		dump_sample(session, event, sample);  		if (evsel == NULL) {  			++session->hists.stats.nr_unknown_id; -			return -1; +			return 0;  		}  		if (machine == NULL) {  			++session->hists.stats.nr_unprocessable_samples; -			return -1; +			return 0;  		}  		return tool->sample(tool, event, sample, evsel, machine);  	case PERF_RECORD_MMAP: diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index c0a028c3eba..ab9867b2b43 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -977,8 +977,9 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,   * And always look at the original dso, not at debuginfo packages, that   * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS).   */ -static int dso__synthesize_plt_symbols(struct  dso *dso, struct map *map, -				       symbol_filter_t filter) +static int +dso__synthesize_plt_symbols(struct dso *dso, char *name, struct map *map, +			    symbol_filter_t filter)  {  	uint32_t nr_rel_entries, idx;  	GElf_Sym sym; @@ -993,10 +994,7 @@ static int dso__synthesize_plt_symbols(struct  dso *dso, struct map *map,  	char sympltname[1024];  	Elf *elf;  	int nr = 0, symidx, fd, err = 0; -	char name[PATH_MAX]; -	snprintf(name, sizeof(name), "%s%s", -		 symbol_conf.symfs, dso->long_name);  	fd = open(name, O_RDONLY);  	if (fd < 0)  		goto out; @@ -1703,8 +1701,9 @@ restart:  			continue;  		if (ret > 0) { -			int nr_plt = dso__synthesize_plt_symbols(dso, map, -								 filter); +			int nr_plt; + +			nr_plt = dso__synthesize_plt_symbols(dso, name, map, filter);  			if (nr_plt > 0)  				ret += nr_plt;  			break; diff --git a/tools/perf/util/ui/browsers/hists.c b/tools/perf/util/ui/browsers/hists.c index d7a1c4afe28..2f83e5dc996 100644 --- a/tools/perf/util/ui/browsers/hists.c +++ b/tools/perf/util/ui/browsers/hists.c @@ -125,6 +125,9 @@ static int callchain__count_rows(struct rb_root *chain)  static bool map_symbol__toggle_fold(struct map_symbol *self)  { +	if (!self) +		return false; +  	if (!self->has_children)  		return false;  |