diff options
| author | Tejun Heo <tj@kernel.org> | 2011-11-28 09:46:22 -0800 | 
|---|---|---|
| committer | Tejun Heo <tj@kernel.org> | 2011-11-28 09:46:22 -0800 | 
| commit | d4bbf7e7759afc172e2bfbc5c416324590049cdd (patch) | |
| tree | 7eab5ee5481cd3dcf1162329fec827177640018a /tools/perf/builtin-script.c | |
| parent | a150439c4a97db379f0ed6faa46fbbb6e7bf3cb2 (diff) | |
| parent | 401d0069cb344f401bc9d264c31db55876ff78c0 (diff) | |
Merge branch 'master' into x86/memblock
Conflicts & resolutions:
* arch/x86/xen/setup.c
	dc91c728fd "xen: allow extra memory to be in multiple regions"
	24aa07882b "memblock, x86: Replace memblock_x86_reserve/free..."
	conflicted on xen_add_extra_mem() updates.  The resolution is
	trivial as the latter just want to replace
	memblock_x86_reserve_range() with memblock_reserve().
* drivers/pci/intel-iommu.c
	166e9278a3f "x86/ia64: intel-iommu: move to drivers/iommu/"
	5dfe8660a3d "bootmem: Replace work_with_active_regions() with..."
	conflicted as the former moved the file under drivers/iommu/.
	Resolved by applying the chnages from the latter on the moved
	file.
* mm/Kconfig
	6661672053a "memblock: add NO_BOOTMEM config symbol"
	c378ddd53f9 "memblock, x86: Make ARCH_DISCARD_MEMBLOCK a config option"
	conflicted trivially.  Both added config options.  Just
	letting both add their own options resolves the conflict.
* mm/memblock.c
	d1f0ece6cdc "mm/memblock.c: small function definition fixes"
	ed7b56a799c "memblock: Remove memblock_memory_can_coalesce()"
	confliected.  The former updates function removed by the
	latter.  Resolution is trivial.
Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'tools/perf/builtin-script.c')
| -rw-r--r-- | tools/perf/builtin-script.c | 127 | 
1 files changed, 116 insertions, 11 deletions
| diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 22747de7234..2f62a295226 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -13,6 +13,7 @@  #include "util/util.h"  #include "util/evlist.h"  #include "util/evsel.h" +#include <linux/bitmap.h>  static char const		*script_name;  static char const		*generate_script_lang; @@ -21,6 +22,9 @@ static u64			last_timestamp;  static u64			nr_unordered;  extern const struct option	record_options[];  static bool			no_callchain; +static bool			show_full_info; +static const char		*cpu_list; +static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);  enum perf_output_field {  	PERF_OUTPUT_COMM            = 1U << 0, @@ -30,7 +34,10 @@ enum perf_output_field {  	PERF_OUTPUT_CPU             = 1U << 4,  	PERF_OUTPUT_EVNAME          = 1U << 5,  	PERF_OUTPUT_TRACE           = 1U << 6, -	PERF_OUTPUT_SYM             = 1U << 7, +	PERF_OUTPUT_IP              = 1U << 7, +	PERF_OUTPUT_SYM             = 1U << 8, +	PERF_OUTPUT_DSO             = 1U << 9, +	PERF_OUTPUT_ADDR            = 1U << 10,  };  struct output_option { @@ -44,7 +51,10 @@ struct output_option {  	{.str = "cpu",   .field = PERF_OUTPUT_CPU},  	{.str = "event", .field = PERF_OUTPUT_EVNAME},  	{.str = "trace", .field = PERF_OUTPUT_TRACE}, +	{.str = "ip",    .field = PERF_OUTPUT_IP},  	{.str = "sym",   .field = PERF_OUTPUT_SYM}, +	{.str = "dso",   .field = PERF_OUTPUT_DSO}, +	{.str = "addr",  .field = PERF_OUTPUT_ADDR},  };  /* default set to maintain compatibility with current format */ @@ -60,7 +70,8 @@ static struct {  		.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |  			      PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | -			      PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM, +			      PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | +				  PERF_OUTPUT_SYM | PERF_OUTPUT_DSO,  		.invalid_fields = PERF_OUTPUT_TRACE,  	}, @@ -70,7 +81,8 @@ static struct {  		.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |  			      PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | -			      PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM, +			      PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | +				  PERF_OUTPUT_SYM | PERF_OUTPUT_DSO,  		.invalid_fields = PERF_OUTPUT_TRACE,  	}, @@ -88,7 +100,8 @@ static struct {  		.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |  			      PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | -			      PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM, +			      PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | +				  PERF_OUTPUT_SYM | PERF_OUTPUT_DSO,  		.invalid_fields = PERF_OUTPUT_TRACE,  	}, @@ -157,9 +170,9 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,  		!perf_session__has_traces(session, "record -R"))  		return -EINVAL; -	if (PRINT_FIELD(SYM)) { +	if (PRINT_FIELD(IP)) {  		if (perf_event_attr__check_stype(attr, PERF_SAMPLE_IP, "IP", -					   PERF_OUTPUT_SYM)) +					   PERF_OUTPUT_IP))  			return -EINVAL;  		if (!no_callchain && @@ -167,6 +180,24 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,  			symbol_conf.use_callchain = false;  	} +	if (PRINT_FIELD(ADDR) && +		perf_event_attr__check_stype(attr, PERF_SAMPLE_ADDR, "ADDR", +				       PERF_OUTPUT_ADDR)) +		return -EINVAL; + +	if (PRINT_FIELD(SYM) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { +		pr_err("Display of symbols requested but neither sample IP nor " +			   "sample address\nis selected. Hence, no addresses to convert " +		       "to symbols.\n"); +		return -EINVAL; +	} +	if (PRINT_FIELD(DSO) && !PRINT_FIELD(IP) && !PRINT_FIELD(ADDR)) { +		pr_err("Display of DSO requested but neither sample IP nor " +			   "sample address\nis selected. Hence, no addresses to convert " +		       "to DSO.\n"); +		return -EINVAL; +	} +  	if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&  		perf_event_attr__check_stype(attr, PERF_SAMPLE_TID, "TID",  				       PERF_OUTPUT_TID|PERF_OUTPUT_PID)) @@ -230,7 +261,7 @@ static void print_sample_start(struct perf_sample *sample,  	if (PRINT_FIELD(COMM)) {  		if (latency_format)  			printf("%8.8s ", thread->comm); -		else if (PRINT_FIELD(SYM) && symbol_conf.use_callchain) +		else if (PRINT_FIELD(IP) && symbol_conf.use_callchain)  			printf("%s ", thread->comm);  		else  			printf("%16s ", thread->comm); @@ -271,6 +302,63 @@ static void print_sample_start(struct perf_sample *sample,  	}  } +static bool sample_addr_correlates_sym(struct perf_event_attr *attr) +{ +	if ((attr->type == PERF_TYPE_SOFTWARE) && +	    ((attr->config == PERF_COUNT_SW_PAGE_FAULTS) || +	     (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN) || +	     (attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ))) +		return true; + +	return false; +} + +static void print_sample_addr(union perf_event *event, +			  struct perf_sample *sample, +			  struct perf_session *session, +			  struct thread *thread, +			  struct perf_event_attr *attr) +{ +	struct addr_location al; +	u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; +	const char *symname, *dsoname; + +	printf("%16" PRIx64, sample->addr); + +	if (!sample_addr_correlates_sym(attr)) +		return; + +	thread__find_addr_map(thread, session, cpumode, MAP__FUNCTION, +			      event->ip.pid, sample->addr, &al); +	if (!al.map) +		thread__find_addr_map(thread, session, cpumode, MAP__VARIABLE, +				      event->ip.pid, sample->addr, &al); + +	al.cpu = sample->cpu; +	al.sym = NULL; + +	if (al.map) +		al.sym = map__find_symbol(al.map, al.addr, NULL); + +	if (PRINT_FIELD(SYM)) { +		if (al.sym && al.sym->name) +			symname = al.sym->name; +		else +			symname = ""; + +		printf(" %16s", symname); +	} + +	if (PRINT_FIELD(DSO)) { +		if (al.map && al.map->dso && al.map->dso->name) +			dsoname = al.map->dso->name; +		else +			dsoname = ""; + +		printf(" (%s)", dsoname); +	} +} +  static void process_event(union perf_event *event __unused,  			  struct perf_sample *sample,  			  struct perf_evsel *evsel, @@ -288,12 +376,16 @@ static void process_event(union perf_event *event __unused,  		print_trace_event(sample->cpu, sample->raw_data,  				  sample->raw_size); -	if (PRINT_FIELD(SYM)) { +	if (PRINT_FIELD(ADDR)) +		print_sample_addr(event, sample, session, thread, attr); + +	if (PRINT_FIELD(IP)) {  		if (!symbol_conf.use_callchain)  			printf(" ");  		else  			printf("\n"); -		perf_session__print_symbols(event, sample, session); +		perf_session__print_ip(event, sample, session, +					      PRINT_FIELD(SYM), PRINT_FIELD(DSO));  	}  	printf("\n"); @@ -365,6 +457,10 @@ static int process_sample_event(union perf_event *event,  		last_timestamp = sample->time;  		return 0;  	} + +	if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) +		return 0; +  	scripting_ops->process_event(event, sample, evsel, session, thread);  	session->hists.stats.total_period += sample->period; @@ -985,9 +1081,11 @@ static const struct option options[] = {  	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",  		    "Look for files with symbols relative to this directory"),  	OPT_CALLBACK('f', "fields", NULL, "str", -		     "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,sym", +		     "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace,raw. Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso,addr",  		     parse_output_fields), - +	OPT_STRING('c', "cpu", &cpu_list, "cpu", "list of cpus to profile"), +	OPT_BOOLEAN('I', "show-info", &show_full_info, +		    "display extended information from perf.data file"),  	OPT_END()  }; @@ -1167,6 +1265,13 @@ int cmd_script(int argc, const char **argv, const char *prefix __used)  	if (session == NULL)  		return -ENOMEM; +	if (cpu_list) { +		if (perf_session__cpu_bitmap(session, cpu_list, cpu_bitmap)) +			return -1; +	} + +	perf_session__fprintf_info(session, stdout, show_full_info); +  	if (!no_callchain)  		symbol_conf.use_callchain = true;  	else | 
