diff options
| author | Thomas Gleixner <tglx@linutronix.de> | 2010-05-10 11:59:37 +0200 | 
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2010-05-10 14:20:42 +0200 | 
| commit | dbb6be6d5e974c42bbecd183effaa0df69e1dd8b (patch) | |
| tree | 5735cb47e70853d057a9881dd0ce44b83e88fa63 /tools | |
| parent | 6a867a395558a7f882d041783e4cdea6744ca2bf (diff) | |
| parent | b57f95a38233a2e73b679bea4a5453a1cc2a1cc9 (diff) | |
| download | olio-linux-3.10-dbb6be6d5e974c42bbecd183effaa0df69e1dd8b.tar.xz olio-linux-3.10-dbb6be6d5e974c42bbecd183effaa0df69e1dd8b.zip  | |
Merge branch 'linus' into timers/core
Reason: Further posix_cpu_timer patches depend on mainline changes
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/perf/Documentation/Makefile | 4 | ||||
| -rw-r--r-- | tools/perf/Makefile | 16 | ||||
| -rw-r--r-- | tools/perf/builtin-annotate.c | 6 | ||||
| -rw-r--r-- | tools/perf/builtin-diff.c | 13 | ||||
| -rw-r--r-- | tools/perf/builtin-probe.c | 1 | ||||
| -rw-r--r-- | tools/perf/builtin-record.c | 13 | ||||
| -rw-r--r-- | tools/perf/builtin-report.c | 112 | ||||
| -rw-r--r-- | tools/perf/builtin-stat.c | 10 | ||||
| -rw-r--r-- | tools/perf/builtin-top.c | 22 | ||||
| -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 | 
24 files changed, 338 insertions, 103 deletions
diff --git a/tools/perf/Documentation/Makefile b/tools/perf/Documentation/Makefile index bdd3b7ecad0..bd498d49695 100644 --- a/tools/perf/Documentation/Makefile +++ b/tools/perf/Documentation/Makefile @@ -24,7 +24,10 @@ DOC_MAN1=$(patsubst %.txt,%.1,$(MAN1_TXT))  DOC_MAN5=$(patsubst %.txt,%.5,$(MAN5_TXT))  DOC_MAN7=$(patsubst %.txt,%.7,$(MAN7_TXT)) +# Make the path relative to DESTDIR, not prefix +ifndef DESTDIR  prefix?=$(HOME) +endif  bindir?=$(prefix)/bin  htmldir?=$(prefix)/share/doc/perf-doc  pdfdir?=$(prefix)/share/doc/perf-doc @@ -32,7 +35,6 @@ mandir?=$(prefix)/share/man  man1dir=$(mandir)/man1  man5dir=$(mandir)/man5  man7dir=$(mandir)/man7 -# DESTDIR=  ASCIIDOC=asciidoc  ASCIIDOC_EXTRA = --unsafe diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 2d537382c68..bc0f670a833 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile @@ -200,7 +200,7 @@ endif  CFLAGS = -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)  EXTLIBS = -lpthread -lrt -lelf -lm -ALL_CFLAGS = $(CFLAGS) +ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  ALL_LDFLAGS = $(LDFLAGS)  STRIP ?= strip @@ -216,7 +216,10 @@ STRIP ?= strip  # runtime figures out where they are based on the path to the executable.  # This can help installing the suite in a relocatable way. +# Make the path relative to DESTDIR, not to prefix +ifndef DESTDIR  prefix = $(HOME) +endif  bindir_relative = bin  bindir = $(prefix)/$(bindir_relative)  mandir = share/man @@ -233,7 +236,6 @@ sysconfdir = $(prefix)/etc  ETC_PERFCONFIG = etc/perfconfig  endif  lib = lib -# DESTDIR=  export prefix bindir sharedir sysconfdir @@ -387,6 +389,7 @@ LIB_H += util/thread.h  LIB_H += util/trace-event.h  LIB_H += util/probe-finder.h  LIB_H += util/probe-event.h +LIB_H += util/cpumap.h  LIB_OBJS += util/abspath.o  LIB_OBJS += util/alias.o @@ -433,6 +436,7 @@ LIB_OBJS += util/sort.o  LIB_OBJS += util/hist.o  LIB_OBJS += util/probe-event.o  LIB_OBJS += util/util.o +LIB_OBJS += util/cpumap.o  BUILTIN_OBJS += builtin-annotate.o @@ -488,19 +492,19 @@ ifeq ($(uname_S),Darwin)  	PTHREAD_LIBS =  endif -ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) -ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) +ifeq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) +ifneq ($(shell sh -c "(echo '\#include <gnu/libc-version.h>'; echo 'int main(void) { const char * version = gnu_get_libc_version(); return (long)version; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)  	msg := $(error No gnu/libc-version.h found, please install glibc-dev[el]/glibc-static);  endif -	ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) +	ifneq ($(shell sh -c "(echo '\#include <libelf.h>'; echo 'int main(void) { Elf * elf = elf_begin(0, ELF_C_READ_MMAP, 0); return (long)elf; }') | $(CC) -x c - $(ALL_CFLAGS) -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)  		BASIC_CFLAGS += -DLIBELF_NO_MMAP  	endif  else  	msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);  endif -ifneq ($(shell sh -c "(echo '\#include <dwarf.h>'; echo '\#include <libdw.h>'; echo 'int main(void) { Dwarf *dbg; dbg = dwarf_begin(0, DWARF_C_READ); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/elfutils -ldw -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) +ifneq ($(shell sh -c "(echo '\#include <dwarf.h>'; echo '\#include <libdw.h>'; echo 'int main(void) { Dwarf *dbg; dbg = dwarf_begin(0, DWARF_C_READ); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -I/usr/include/elfutils -ldw -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)  	msg := $(warning No libdw.h found or old libdw.h found, disables dwarf support. Please install elfutils-devel/elfutils-dev);  	BASIC_CFLAGS += -DNO_DWARF_SUPPORT  else diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 5ec5de99587..6ad7148451c 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -116,7 +116,7 @@ static int perf_session__add_hist_entry(struct perf_session *self,  		return 0;  	} -	he = __perf_session__add_hist_entry(self, al, NULL, count, &hit); +	he = __perf_session__add_hist_entry(&self->hists, al, NULL, count, &hit);  	if (he == NULL)  		return -ENOMEM; @@ -564,8 +564,8 @@ static int __cmd_annotate(void)  	if (verbose > 2)  		dsos__fprintf(stdout); -	perf_session__collapse_resort(session); -	perf_session__output_resort(session, session->event_total[0]); +	perf_session__collapse_resort(&session->hists); +	perf_session__output_resort(&session->hists, session->event_total[0]);  	perf_session__find_annotations(session);  out_delete:  	perf_session__delete(session); diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 18b3f505f9d..1ea15d8aeed 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c @@ -26,7 +26,8 @@ static int perf_session__add_hist_entry(struct perf_session *self,  					struct addr_location *al, u64 count)  {  	bool hit; -	struct hist_entry *he = __perf_session__add_hist_entry(self, al, NULL, +	struct hist_entry *he = __perf_session__add_hist_entry(&self->hists, +							       al, NULL,  							       count, &hit);  	if (he == NULL)  		return -ENOMEM; @@ -114,7 +115,7 @@ static void perf_session__resort_hist_entries(struct perf_session *self)  static void perf_session__set_hist_entries_positions(struct perf_session *self)  { -	perf_session__output_resort(self, self->events_stats.total); +	perf_session__output_resort(&self->hists, self->events_stats.total);  	perf_session__resort_hist_entries(self);  } @@ -166,13 +167,15 @@ static int __cmd_diff(void)  			goto out_delete;  	} -	perf_session__output_resort(session[1], session[1]->events_stats.total); +	perf_session__output_resort(&session[1]->hists, +				    session[1]->events_stats.total);  	if (show_displacement)  		perf_session__set_hist_entries_positions(session[0]);  	perf_session__match_hists(session[0], session[1]); -	perf_session__fprintf_hists(session[1], session[0], -				    show_displacement, stdout); +	perf_session__fprintf_hists(&session[1]->hists, session[0], +				    show_displacement, stdout, +				    session[1]->events_stats.total);  out_delete:  	for (i = 0; i < 2; ++i)  		perf_session__delete(session[i]); diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index c30a3359234..152d6c9b1fa 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -47,7 +47,6 @@  #include "util/probe-event.h"  #define MAX_PATH_LEN 256 -#define MAX_PROBES 128  /* Session management structure */  static struct { diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 771533ced6a..3b8b6387c47 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -22,6 +22,7 @@  #include "util/debug.h"  #include "util/session.h"  #include "util/symbol.h" +#include "util/cpumap.h"  #include <unistd.h>  #include <sched.h> @@ -244,6 +245,9 @@ static void create_counter(int counter, int cpu, pid_t pid)  	attr->sample_type	|= PERF_SAMPLE_IP | PERF_SAMPLE_TID; +	if (nr_counters > 1) +		attr->sample_type |= PERF_SAMPLE_ID; +  	if (freq) {  		attr->sample_type	|= PERF_SAMPLE_PERIOD;  		attr->freq		= 1; @@ -391,6 +395,9 @@ static int process_buildids(void)  {  	u64 size = lseek(output, 0, SEEK_CUR); +	if (size == 0) +		return 0; +  	session->fd = output;  	return __perf_session__process_events(session, post_processing_offset,  					      size - post_processing_offset, @@ -418,9 +425,6 @@ static int __cmd_record(int argc, const char **argv)  	char buf;  	page_size = sysconf(_SC_PAGE_SIZE); -	nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); -	assert(nr_cpus <= MAX_NR_CPUS); -	assert(nr_cpus >= 0);  	atexit(sig_atexit);  	signal(SIGCHLD, sig_handler); @@ -544,8 +548,9 @@ static int __cmd_record(int argc, const char **argv)  	if ((!system_wide && !inherit) || profile_cpu != -1) {  		open_counters(profile_cpu, target_pid);  	} else { +		nr_cpus = read_cpu_map();  		for (i = 0; i < nr_cpus; i++) -			open_counters(i, target_pid); +			open_counters(cpumap[i], target_pid);  	}  	if (file_new) { diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index cfc655d40bb..f815de25d0f 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -45,28 +45,71 @@ static char		*pretty_printing_style = default_pretty_printing_style;  static char		callchain_default_opt[] = "fractal,0.5"; +static struct event_stat_id *get_stats(struct perf_session *self, +				       u64 event_stream, u32 type, u64 config) +{ +	struct rb_node **p = &self->stats_by_id.rb_node; +	struct rb_node *parent = NULL; +	struct event_stat_id *iter, *new; + +	while (*p != NULL) { +		parent = *p; +		iter = rb_entry(parent, struct event_stat_id, rb_node); +		if (iter->config == config) +			return iter; + + +		if (config > iter->config) +			p = &(*p)->rb_right; +		else +			p = &(*p)->rb_left; +	} + +	new = malloc(sizeof(struct event_stat_id)); +	if (new == NULL) +		return NULL; +	memset(new, 0, sizeof(struct event_stat_id)); +	new->event_stream = event_stream; +	new->config = config; +	new->type = type; +	rb_link_node(&new->rb_node, parent, p); +	rb_insert_color(&new->rb_node, &self->stats_by_id); +	return new; +} +  static int perf_session__add_hist_entry(struct perf_session *self,  					struct addr_location *al, -					struct ip_callchain *chain, u64 count) +					struct sample_data *data)  {  	struct symbol **syms = NULL, *parent = NULL;  	bool hit;  	struct hist_entry *he; +	struct event_stat_id *stats; +	struct perf_event_attr *attr; -	if ((sort__has_parent || symbol_conf.use_callchain) && chain) +	if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain)  		syms = perf_session__resolve_callchain(self, al->thread, -						       chain, &parent); -	he = __perf_session__add_hist_entry(self, al, parent, count, &hit); +						       data->callchain, &parent); + +	attr = perf_header__find_attr(data->id, &self->header); +	if (attr) +		stats = get_stats(self, data->id, attr->type, attr->config); +	else +		stats = get_stats(self, data->id, 0, 0); +	if (stats == NULL) +		return -ENOMEM; +	he = __perf_session__add_hist_entry(&stats->hists, al, parent, +					    data->period, &hit);  	if (he == NULL)  		return -ENOMEM;  	if (hit) -		he->count += count; +		he->count += data->period;  	if (symbol_conf.use_callchain) {  		if (!hit)  			callchain_init(&he->callchain); -		append_chain(&he->callchain, chain, syms); +		append_chain(&he->callchain, data->callchain, syms);  		free(syms);  	} @@ -86,10 +129,30 @@ static int validate_chain(struct ip_callchain *chain, event_t *event)  	return 0;  } +static int add_event_total(struct perf_session *session, +			   struct sample_data *data, +			   struct perf_event_attr *attr) +{ +	struct event_stat_id *stats; + +	if (attr) +		stats = get_stats(session, data->id, attr->type, attr->config); +	else +		stats = get_stats(session, data->id, 0, 0); + +	if (!stats) +		return -ENOMEM; + +	stats->stats.total += data->period; +	session->events_stats.total += data->period; +	return 0; +} +  static int process_sample_event(event_t *event, struct perf_session *session)  {  	struct sample_data data = { .period = 1, };  	struct addr_location al; +	struct perf_event_attr *attr;  	event__parse_sample(event, session->sample_type, &data); @@ -123,12 +186,18 @@ static int process_sample_event(event_t *event, struct perf_session *session)  	if (al.filtered || (hide_unresolved && al.sym == NULL))  		return 0; -	if (perf_session__add_hist_entry(session, &al, data.callchain, data.period)) { +	if (perf_session__add_hist_entry(session, &al, &data)) {  		pr_debug("problem incrementing symbol count, skipping event\n");  		return -1;  	} -	session->events_stats.total += data.period; +	attr = perf_header__find_attr(data.id, &session->header); + +	if (add_event_total(session, &data, attr)) { +		pr_debug("problem adding event count\n"); +		return -1; +	} +  	return 0;  } @@ -197,6 +266,7 @@ static int __cmd_report(void)  {  	int ret = -EINVAL;  	struct perf_session *session; +	struct rb_node *next;  	session = perf_session__new(input_name, O_RDONLY, force);  	if (session == NULL) @@ -224,10 +294,28 @@ static int __cmd_report(void)  	if (verbose > 2)  		dsos__fprintf(stdout); -	perf_session__collapse_resort(session); -	perf_session__output_resort(session, session->events_stats.total); -	fprintf(stdout, "# Samples: %Ld\n#\n", session->events_stats.total); -	perf_session__fprintf_hists(session, NULL, false, stdout); +	next = rb_first(&session->stats_by_id); +	while (next) { +		struct event_stat_id *stats; + +		stats = rb_entry(next, struct event_stat_id, rb_node); +		perf_session__collapse_resort(&stats->hists); +		perf_session__output_resort(&stats->hists, stats->stats.total); +		if (rb_first(&session->stats_by_id) == +		    rb_last(&session->stats_by_id)) +			fprintf(stdout, "# Samples: %Ld\n#\n", +				stats->stats.total); +		else +			fprintf(stdout, "# Samples: %Ld %s\n#\n", +				stats->stats.total, +				__event_name(stats->type, stats->config)); + +		perf_session__fprintf_hists(&stats->hists, NULL, false, stdout, +					    stats->stats.total); +		fprintf(stdout, "\n\n"); +		next = rb_next(&stats->rb_node); +	} +  	if (sort_order == default_sort_order &&  	    parent_pattern == default_parent_pattern)  		fprintf(stdout, "#\n# (For a higher level overview, try: perf report --sort comm,dso)\n#\n"); diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index e8c85d5aec4..95db31cff6f 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -45,6 +45,7 @@  #include "util/event.h"  #include "util/debug.h"  #include "util/header.h" +#include "util/cpumap.h"  #include <sys/prctl.h>  #include <math.h> @@ -151,7 +152,7 @@ static void create_perf_stat_counter(int counter, int pid)  		unsigned int cpu;  		for (cpu = 0; cpu < nr_cpus; cpu++) { -			fd[cpu][counter] = sys_perf_event_open(attr, -1, cpu, -1, 0); +			fd[cpu][counter] = sys_perf_event_open(attr, -1, cpumap[cpu], -1, 0);  			if (fd[cpu][counter] < 0 && verbose)  				fprintf(stderr, ERR_PERF_OPEN, counter,  					fd[cpu][counter], strerror(errno)); @@ -519,9 +520,10 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)  		nr_counters = ARRAY_SIZE(default_attrs);  	} -	nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); -	assert(nr_cpus <= MAX_NR_CPUS); -	assert((int)nr_cpus >= 0); +	if (system_wide) +		nr_cpus = read_cpu_map(); +	else +		nr_cpus = 1;  	/*  	 * We dont want to block the signals - that would cause diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 31f2e597800..1f529321607 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -28,6 +28,7 @@  #include <linux/rbtree.h>  #include "util/parse-options.h"  #include "util/parse-events.h" +#include "util/cpumap.h"  #include "util/debug.h" @@ -454,7 +455,7 @@ static void print_sym_table(void)  	struct sym_entry *syme, *n;  	struct rb_root tmp = RB_ROOT;  	struct rb_node *nd; -	int sym_width = 0, dso_width = 0, max_dso_width; +	int sym_width = 0, dso_width = 0, dso_short_width = 0;  	const int win_width = winsize.ws_col - 1;  	samples = userspace_samples = 0; @@ -544,15 +545,20 @@ static void print_sym_table(void)  		if (syme->map->dso->long_name_len > dso_width)  			dso_width = syme->map->dso->long_name_len; +		if (syme->map->dso->short_name_len > dso_short_width) +			dso_short_width = syme->map->dso->short_name_len; +  		if (syme->name_len > sym_width)  			sym_width = syme->name_len;  	}  	printed = 0; -	max_dso_width = winsize.ws_col - sym_width - 29; -	if (dso_width > max_dso_width) -		dso_width = max_dso_width; +	if (sym_width + dso_width > winsize.ws_col - 29) { +		dso_width = dso_short_width; +		if (sym_width + dso_width > winsize.ws_col - 29) +			sym_width = winsize.ws_col - dso_width - 29; +	}  	putchar('\n');  	if (nr_counters == 1)  		printf("             samples  pcnt"); @@ -1123,7 +1129,7 @@ static void start_counter(int i, int counter)  	cpu = profile_cpu;  	if (target_pid == -1 && profile_cpu == -1) -		cpu = i; +		cpu = cpumap[i];  	attr = attrs + counter; @@ -1347,12 +1353,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)  		attrs[counter].sample_period = default_interval;  	} -	nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); -	assert(nr_cpus <= MAX_NR_CPUS); -	assert(nr_cpus >= 0); -  	if (target_pid != -1 || profile_cpu != -1)  		nr_cpus = 1; +	else +		nr_cpus = read_cpu_map();  	get_term_dimensions(&winsize);  	if (print_entries == 0) { 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;  |