diff options
| author | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2016-03-29 16:33:47 +0300 | 
|---|---|---|
| committer | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2016-03-29 16:33:47 +0300 | 
| commit | 8041dcc881c928134c546ae85e6e59e65804357c (patch) | |
| tree | be5d1c21af8cf38ac32ed8708396881aabd44d4e /tools/perf/builtin-script.c | |
| parent | ed6069be7204541c1da532ad8bbf892e34513552 (diff) | |
| parent | f55532a0c0b8bb6148f4e07853b876ef73bc69ca (diff) | |
| download | linux-8041dcc881c928134c546ae85e6e59e65804357c.tar.xz | |
Merge tag 'v4.6-rc1' into for-linus-4.6
Linux 4.6-rc1
* tag 'v4.6-rc1': (12823 commits)
  Linux 4.6-rc1
  f2fs/crypto: fix xts_tweak initialization
  NTB: Remove _addr functions from ntb_hw_amd
  orangefs: fix orangefs_superblock locking
  orangefs: fix do_readv_writev() handling of error halfway through
  orangefs: have ->kill_sb() evict the VFS side of things first
  orangefs: sanitize ->llseek()
  orangefs-bufmap.h: trim unused junk
  orangefs: saner calling conventions for getting a slot
  orangefs_copy_{to,from}_bufmap(): don't pass bufmap pointer
  orangefs: get rid of readdir_handle_s
  thp: fix typo in khugepaged_scan_pmd()
  MAINTAINERS: fill entries for KASAN
  mm/filemap: generic_file_read_iter(): check for zero reads unconditionally
  kasan: test fix: warn if the UAF could not be detected in kmalloc_uaf2
  mm, kasan: stackdepot implementation. Enable stackdepot for SLAB
  arch, ftrace: for KASAN put hard/soft IRQ entries into separate sections
  mm, kasan: add GFP flags to KASAN API
  mm, kasan: SLAB support
  kasan: modify kmalloc_large_oob_right(), add kmalloc_pagealloc_oob_right()
  ...
Diffstat (limited to 'tools/perf/builtin-script.c')
| -rw-r--r-- | tools/perf/builtin-script.c | 201 | 
1 files changed, 149 insertions, 52 deletions
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index c691214d820f..3770c3dffe5e 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -23,6 +23,7 @@  #include "util/stat.h"  #include <linux/bitmap.h>  #include "asm/bug.h" +#include "util/mem-events.h"  static char const		*script_name;  static char const		*generate_script_lang; @@ -58,6 +59,9 @@ enum perf_output_field {  	PERF_OUTPUT_IREGS	    = 1U << 14,  	PERF_OUTPUT_BRSTACK	    = 1U << 15,  	PERF_OUTPUT_BRSTACKSYM	    = 1U << 16, +	PERF_OUTPUT_DATA_SRC	    = 1U << 17, +	PERF_OUTPUT_WEIGHT	    = 1U << 18, +	PERF_OUTPUT_BPF_OUTPUT	    = 1U << 19,  };  struct output_option { @@ -81,6 +85,9 @@ struct output_option {  	{.str = "iregs", .field = PERF_OUTPUT_IREGS},  	{.str = "brstack", .field = PERF_OUTPUT_BRSTACK},  	{.str = "brstacksym", .field = PERF_OUTPUT_BRSTACKSYM}, +	{.str = "data_src", .field = PERF_OUTPUT_DATA_SRC}, +	{.str = "weight",   .field = PERF_OUTPUT_WEIGHT}, +	{.str = "bpf-output",   .field = PERF_OUTPUT_BPF_OUTPUT},  };  /* default set to maintain compatibility with current format */ @@ -101,7 +108,7 @@ static struct {  			      PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |  			      PERF_OUTPUT_PERIOD, -		.invalid_fields = PERF_OUTPUT_TRACE, +		.invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,  	},  	[PERF_TYPE_SOFTWARE] = { @@ -111,7 +118,7 @@ static struct {  			      PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |  			      PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |  			      PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | -			      PERF_OUTPUT_PERIOD, +			      PERF_OUTPUT_PERIOD | PERF_OUTPUT_BPF_OUTPUT,  		.invalid_fields = PERF_OUTPUT_TRACE,  	}, @@ -121,7 +128,7 @@ static struct {  		.fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |  				  PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | -				  PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE, +				  PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE  	},  	[PERF_TYPE_RAW] = { @@ -131,9 +138,10 @@ static struct {  			      PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |  			      PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |  			      PERF_OUTPUT_SYM | PERF_OUTPUT_DSO | -			      PERF_OUTPUT_PERIOD, +			      PERF_OUTPUT_PERIOD |  PERF_OUTPUT_ADDR | +			      PERF_OUTPUT_DATA_SRC | PERF_OUTPUT_WEIGHT, -		.invalid_fields = PERF_OUTPUT_TRACE, +		.invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,  	},  	[PERF_TYPE_BREAKPOINT] = { @@ -145,7 +153,7 @@ static struct {  			      PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |  			      PERF_OUTPUT_PERIOD, -		.invalid_fields = PERF_OUTPUT_TRACE, +		.invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT,  	},  }; @@ -242,6 +250,16 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,  					   PERF_OUTPUT_ADDR, allow_user_set))  		return -EINVAL; +	if (PRINT_FIELD(DATA_SRC) && +		perf_evsel__check_stype(evsel, PERF_SAMPLE_DATA_SRC, "DATA_SRC", +					PERF_OUTPUT_DATA_SRC)) +		return -EINVAL; + +	if (PRINT_FIELD(WEIGHT) && +		perf_evsel__check_stype(evsel, PERF_SAMPLE_WEIGHT, "WEIGHT", +					PERF_OUTPUT_WEIGHT)) +		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 " @@ -387,9 +405,7 @@ out:  	return 0;  } -static void print_sample_iregs(union perf_event *event __maybe_unused, -			  struct perf_sample *sample, -			  struct thread *thread __maybe_unused, +static void print_sample_iregs(struct perf_sample *sample,  			  struct perf_event_attr *attr)  {  	struct regs_dump *regs = &sample->intr_regs; @@ -458,10 +474,7 @@ mispred_str(struct branch_entry *br)  	return br->flags.predicted ? 'P' : 'M';  } -static void print_sample_brstack(union perf_event *event __maybe_unused, -			  struct perf_sample *sample, -			  struct thread *thread __maybe_unused, -			  struct perf_event_attr *attr __maybe_unused) +static void print_sample_brstack(struct perf_sample *sample)  {  	struct branch_stack *br = sample->branch_stack;  	u64 i; @@ -480,14 +493,11 @@ static void print_sample_brstack(union perf_event *event __maybe_unused,  	}  } -static void print_sample_brstacksym(union perf_event *event __maybe_unused, -			  struct perf_sample *sample, -			  struct thread *thread __maybe_unused, -			  struct perf_event_attr *attr __maybe_unused) +static void print_sample_brstacksym(struct perf_sample *sample, +				    struct thread *thread)  {  	struct branch_stack *br = sample->branch_stack;  	struct addr_location alf, alt; -	u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;  	u64 i, from, to;  	if (!(br && br->nr)) @@ -500,11 +510,11 @@ static void print_sample_brstacksym(union perf_event *event __maybe_unused,  		from = br->entries[i].from;  		to   = br->entries[i].to; -		thread__find_addr_map(thread, cpumode, MAP__FUNCTION, from, &alf); +		thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, from, &alf);  		if (alf.map)  			alf.sym = map__find_symbol(alf.map, alf.addr, NULL); -		thread__find_addr_map(thread, cpumode, MAP__FUNCTION, to, &alt); +		thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, to, &alt);  		if (alt.map)  			alt.sym = map__find_symbol(alt.map, alt.addr, NULL); @@ -520,8 +530,7 @@ static void print_sample_brstacksym(union perf_event *event __maybe_unused,  } -static void print_sample_addr(union perf_event *event, -			  struct perf_sample *sample, +static void print_sample_addr(struct perf_sample *sample,  			  struct thread *thread,  			  struct perf_event_attr *attr)  { @@ -532,7 +541,7 @@ static void print_sample_addr(union perf_event *event,  	if (!sample_addr_correlates_sym(attr))  		return; -	perf_event__preprocess_sample_addr(event, sample, thread, &al); +	thread__resolve(thread, &al, sample);  	if (PRINT_FIELD(SYM)) {  		printf(" "); @@ -549,8 +558,7 @@ static void print_sample_addr(union perf_event *event,  	}  } -static void print_sample_bts(union perf_event *event, -			     struct perf_sample *sample, +static void print_sample_bts(struct perf_sample *sample,  			     struct perf_evsel *evsel,  			     struct thread *thread,  			     struct addr_location *al) @@ -580,7 +588,7 @@ static void print_sample_bts(union perf_event *event,  	    ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&  	     !output[attr->type].user_set)) {  		printf(" => "); -		print_sample_addr(event, sample, thread, attr); +		print_sample_addr(sample, thread, attr);  	}  	if (print_srcline_last) @@ -608,6 +616,84 @@ static void print_sample_flags(u32 flags)  	printf("  %-4s ", str);  } +struct printer_data { +	int line_no; +	bool hit_nul; +	bool is_printable; +}; + +static void +print_sample_bpf_output_printer(enum binary_printer_ops op, +				unsigned int val, +				void *extra) +{ +	unsigned char ch = (unsigned char)val; +	struct printer_data *printer_data = extra; + +	switch (op) { +	case BINARY_PRINT_DATA_BEGIN: +		printf("\n"); +		break; +	case BINARY_PRINT_LINE_BEGIN: +		printf("%17s", !printer_data->line_no ? "BPF output:" : +						        "           "); +		break; +	case BINARY_PRINT_ADDR: +		printf(" %04x:", val); +		break; +	case BINARY_PRINT_NUM_DATA: +		printf(" %02x", val); +		break; +	case BINARY_PRINT_NUM_PAD: +		printf("   "); +		break; +	case BINARY_PRINT_SEP: +		printf("  "); +		break; +	case BINARY_PRINT_CHAR_DATA: +		if (printer_data->hit_nul && ch) +			printer_data->is_printable = false; + +		if (!isprint(ch)) { +			printf("%c", '.'); + +			if (!printer_data->is_printable) +				break; + +			if (ch == '\0') +				printer_data->hit_nul = true; +			else +				printer_data->is_printable = false; +		} else { +			printf("%c", ch); +		} +		break; +	case BINARY_PRINT_CHAR_PAD: +		printf(" "); +		break; +	case BINARY_PRINT_LINE_END: +		printf("\n"); +		printer_data->line_no++; +		break; +	case BINARY_PRINT_DATA_END: +	default: +		break; +	} +} + +static void print_sample_bpf_output(struct perf_sample *sample) +{ +	unsigned int nr_bytes = sample->raw_size; +	struct printer_data printer_data = {0, false, true}; + +	print_binary(sample->raw_data, nr_bytes, 8, +		     print_sample_bpf_output_printer, &printer_data); + +	if (printer_data.is_printable && printer_data.hit_nul) +		printf("%17s \"%s\"\n", "BPF string:", +		       (char *)(sample->raw_data)); +} +  struct perf_script {  	struct perf_tool	tool;  	struct perf_session	*session; @@ -634,7 +720,24 @@ static int perf_evlist__max_name_len(struct perf_evlist *evlist)  	return max;  } -static void process_event(struct perf_script *script, union perf_event *event, +static size_t data_src__printf(u64 data_src) +{ +	struct mem_info mi = { .data_src.val = data_src }; +	char decode[100]; +	char out[100]; +	static int maxlen; +	int len; + +	perf_script__meminfo_scnprintf(decode, 100, &mi); + +	len = scnprintf(out, 100, "%16" PRIx64 " %s", data_src, decode); +	if (maxlen < len) +		maxlen = len; + +	return printf("%-*s", maxlen, out); +} + +static void process_event(struct perf_script *script,  			  struct perf_sample *sample, struct perf_evsel *evsel,  			  struct addr_location *al)  { @@ -663,7 +766,7 @@ static void process_event(struct perf_script *script, union perf_event *event,  		print_sample_flags(sample->flags);  	if (is_bts_event(attr)) { -		print_sample_bts(event, sample, evsel, thread, al); +		print_sample_bts(sample, evsel, thread, al);  		return;  	} @@ -671,7 +774,13 @@ static void process_event(struct perf_script *script, union perf_event *event,  		event_format__print(evsel->tp_format, sample->cpu,  				    sample->raw_data, sample->raw_size);  	if (PRINT_FIELD(ADDR)) -		print_sample_addr(event, sample, thread, attr); +		print_sample_addr(sample, thread, attr); + +	if (PRINT_FIELD(DATA_SRC)) +		data_src__printf(sample->data_src); + +	if (PRINT_FIELD(WEIGHT)) +		printf("%16" PRIu64, sample->weight);  	if (PRINT_FIELD(IP)) {  		if (!symbol_conf.use_callchain) @@ -685,12 +794,15 @@ static void process_event(struct perf_script *script, union perf_event *event,  	}  	if (PRINT_FIELD(IREGS)) -		print_sample_iregs(event, sample, thread, attr); +		print_sample_iregs(sample, attr);  	if (PRINT_FIELD(BRSTACK)) -		print_sample_brstack(event, sample, thread, attr); +		print_sample_brstack(sample);  	else if (PRINT_FIELD(BRSTACKSYM)) -		print_sample_brstacksym(event, sample, thread, attr); +		print_sample_brstacksym(sample, thread); + +	if (perf_evsel__is_bpf_output(evsel) && PRINT_FIELD(BPF_OUTPUT)) +		print_sample_bpf_output(sample);  	printf("\n");  } @@ -783,7 +895,7 @@ static int process_sample_event(struct perf_tool *tool,  		return 0;  	} -	if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) { +	if (machine__resolve(machine, &al, sample) < 0) {  		pr_err("problem processing %d event, skipping it.\n",  		       event->header.type);  		return -1; @@ -798,7 +910,7 @@ static int process_sample_event(struct perf_tool *tool,  	if (scripting_ops)  		scripting_ops->process_event(event, sample, evsel, &al);  	else -		process_event(scr, event, sample, evsel, &al); +		process_event(scr, sample, evsel, &al);  out_put:  	addr_location__put(&al); @@ -1090,23 +1202,6 @@ static struct script_spec *script_spec__find(const char *spec)  	return NULL;  } -static struct script_spec *script_spec__findnew(const char *spec, -						struct scripting_ops *ops) -{ -	struct script_spec *s = script_spec__find(spec); - -	if (s) -		return s; - -	s = script_spec__new(spec, ops); -	if (!s) -		return NULL; - -	script_spec__add(s); - -	return s; -} -  int script_spec_register(const char *spec, struct scripting_ops *ops)  {  	struct script_spec *s; @@ -1115,9 +1210,11 @@ int script_spec_register(const char *spec, struct scripting_ops *ops)  	if (s)  		return -1; -	s = script_spec__findnew(spec, ops); +	s = script_spec__new(spec, ops);  	if (!s)  		return -1; +	else +		script_spec__add(s);  	return 0;  }  | 
