perf callchain: Add mask into struct regs_dump
Adding mask info into struct regs_dump to make the registers information compact. The mask was always passed along, so logically the mask info fits more into the struct regs_dump. Signed-off-by: Jiri Olsa <jolsa@redhat.com> Acked-by: Jean Pihet <jean.pihet@linaro.org> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com> Cc: David Ahern <dsahern@gmail.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Jean Pihet <jean.pihet@linaro.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Link: http://lkml.kernel.org/r/1389098853-14466-9-git-send-email-jolsa@redhat.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
		
							parent
							
								
									1cf0382af9
								
							
						
					
					
						commit
						352ea45a72
					
				| @ -53,6 +53,7 @@ int test__arch_unwind_sample(struct perf_sample *sample, | ||||
| 	perf_regs_load(buf); | ||||
| 	regs->abi  = PERF_SAMPLE_REGS_ABI; | ||||
| 	regs->regs = buf; | ||||
| 	regs->mask = PERF_REGS_MASK; | ||||
| 
 | ||||
| 	return sample_ustack(sample, thread, buf); | ||||
| } | ||||
|  | ||||
| @ -312,7 +312,6 @@ found: | ||||
| 	sample_sw.period = sample->period; | ||||
| 	sample_sw.time	 = sample->time; | ||||
| 	perf_event__synthesize_sample(event_sw, evsel->attr.sample_type, | ||||
| 				      evsel->attr.sample_regs_user, | ||||
| 				      evsel->attr.read_format, &sample_sw, | ||||
| 				      false); | ||||
| 	build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine); | ||||
|  | ||||
| @ -72,7 +72,7 @@ static int unwind_thread(struct thread *thread, struct machine *machine) | ||||
| 	} | ||||
| 
 | ||||
| 	err = unwind__get_entries(unwind_entry, &cnt, machine, thread, | ||||
| 				  PERF_REGS_MASK, &sample, MAX_STACK); | ||||
| 				  &sample, MAX_STACK); | ||||
| 	if (err) | ||||
| 		pr_debug("unwind failed\n"); | ||||
| 	else if (cnt != MAX_STACK) { | ||||
|  | ||||
| @ -22,8 +22,8 @@ | ||||
| } while (0) | ||||
| 
 | ||||
| static bool samples_same(const struct perf_sample *s1, | ||||
| 			 const struct perf_sample *s2, u64 type, u64 regs_user, | ||||
| 			 u64 read_format) | ||||
| 			 const struct perf_sample *s2, | ||||
| 			 u64 type, u64 read_format) | ||||
| { | ||||
| 	size_t i; | ||||
| 
 | ||||
| @ -95,8 +95,9 @@ static bool samples_same(const struct perf_sample *s1, | ||||
| 	} | ||||
| 
 | ||||
| 	if (type & PERF_SAMPLE_REGS_USER) { | ||||
| 		size_t sz = hweight_long(regs_user) * sizeof(u64); | ||||
| 		size_t sz = hweight_long(s1->user_regs.mask) * sizeof(u64); | ||||
| 
 | ||||
| 		COMP(user_regs.mask); | ||||
| 		COMP(user_regs.abi); | ||||
| 		if (s1->user_regs.abi && | ||||
| 		    (!s1->user_regs.regs || !s2->user_regs.regs || | ||||
| @ -174,6 +175,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format) | ||||
| 		.branch_stack	= &branch_stack.branch_stack, | ||||
| 		.user_regs	= { | ||||
| 			.abi	= PERF_SAMPLE_REGS_ABI_64, | ||||
| 			.mask	= sample_regs_user, | ||||
| 			.regs	= user_regs, | ||||
| 		}, | ||||
| 		.user_stack	= { | ||||
| @ -201,8 +203,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format) | ||||
| 		sample.read.one.id    = 99; | ||||
| 	} | ||||
| 
 | ||||
| 	sz = perf_event__sample_event_size(&sample, sample_type, | ||||
| 					   sample_regs_user, read_format); | ||||
| 	sz = perf_event__sample_event_size(&sample, sample_type, read_format); | ||||
| 	bufsz = sz + 4096; /* Add a bit for overrun checking */ | ||||
| 	event = malloc(bufsz); | ||||
| 	if (!event) { | ||||
| @ -215,8 +216,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format) | ||||
| 	event->header.misc = 0; | ||||
| 	event->header.size = sz; | ||||
| 
 | ||||
| 	err = perf_event__synthesize_sample(event, sample_type, | ||||
| 					    sample_regs_user, read_format, | ||||
| 	err = perf_event__synthesize_sample(event, sample_type, read_format, | ||||
| 					    &sample, false); | ||||
| 	if (err) { | ||||
| 		pr_debug("%s failed for sample_type %#"PRIx64", error %d\n", | ||||
| @ -244,8 +244,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format) | ||||
| 		goto out_free; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!samples_same(&sample, &sample_out, sample_type, | ||||
| 			  sample_regs_user, read_format)) { | ||||
| 	if (!samples_same(&sample, &sample_out, sample_type, read_format)) { | ||||
| 		pr_debug("parsing failed for sample_type %#"PRIx64"\n", | ||||
| 			 sample_type); | ||||
| 		goto out_free; | ||||
|  | ||||
| @ -85,6 +85,7 @@ struct sample_event { | ||||
| 
 | ||||
| struct regs_dump { | ||||
| 	u64 abi; | ||||
| 	u64 mask; | ||||
| 	u64 *regs; | ||||
| }; | ||||
| 
 | ||||
| @ -259,9 +260,9 @@ int perf_event__preprocess_sample(const union perf_event *event, | ||||
| const char *perf_event__name(unsigned int id); | ||||
| 
 | ||||
| size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, | ||||
| 				     u64 sample_regs_user, u64 read_format); | ||||
| 				     u64 read_format); | ||||
| int perf_event__synthesize_sample(union perf_event *event, u64 type, | ||||
| 				  u64 sample_regs_user, u64 read_format, | ||||
| 				  u64 read_format, | ||||
| 				  const struct perf_sample *sample, | ||||
| 				  bool swapped); | ||||
| 
 | ||||
|  | ||||
| @ -1396,10 +1396,11 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, | ||||
| 		array++; | ||||
| 
 | ||||
| 		if (data->user_regs.abi) { | ||||
| 			u64 regs_user = evsel->attr.sample_regs_user; | ||||
| 			u64 mask = evsel->attr.sample_regs_user; | ||||
| 
 | ||||
| 			sz = hweight_long(regs_user) * sizeof(u64); | ||||
| 			sz = hweight_long(mask) * sizeof(u64); | ||||
| 			OVERFLOW_CHECK(array, sz, max_size); | ||||
| 			data->user_regs.mask = mask; | ||||
| 			data->user_regs.regs = (u64 *)array; | ||||
| 			array = (void *)array + sz; | ||||
| 		} | ||||
| @ -1451,7 +1452,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, | ||||
| } | ||||
| 
 | ||||
| size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, | ||||
| 				     u64 sample_regs_user, u64 read_format) | ||||
| 				     u64 read_format) | ||||
| { | ||||
| 	size_t sz, result = sizeof(struct sample_event); | ||||
| 
 | ||||
| @ -1517,7 +1518,7 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, | ||||
| 	if (type & PERF_SAMPLE_REGS_USER) { | ||||
| 		if (sample->user_regs.abi) { | ||||
| 			result += sizeof(u64); | ||||
| 			sz = hweight_long(sample_regs_user) * sizeof(u64); | ||||
| 			sz = hweight_long(sample->user_regs.mask) * sizeof(u64); | ||||
| 			result += sz; | ||||
| 		} else { | ||||
| 			result += sizeof(u64); | ||||
| @ -1546,7 +1547,7 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, | ||||
| } | ||||
| 
 | ||||
| int perf_event__synthesize_sample(union perf_event *event, u64 type, | ||||
| 				  u64 sample_regs_user, u64 read_format, | ||||
| 				  u64 read_format, | ||||
| 				  const struct perf_sample *sample, | ||||
| 				  bool swapped) | ||||
| { | ||||
| @ -1687,7 +1688,7 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, | ||||
| 	if (type & PERF_SAMPLE_REGS_USER) { | ||||
| 		if (sample->user_regs.abi) { | ||||
| 			*array++ = sample->user_regs.abi; | ||||
| 			sz = hweight_long(sample_regs_user) * sizeof(u64); | ||||
| 			sz = hweight_long(sample->user_regs.mask) * sizeof(u64); | ||||
| 			memcpy(array, sample->user_regs.regs, sz); | ||||
| 			array = (void *)array + sz; | ||||
| 		} else { | ||||
|  | ||||
| @ -1383,8 +1383,7 @@ int machine__resolve_callchain(struct machine *machine, | ||||
| 		return 0; | ||||
| 
 | ||||
| 	return unwind__get_entries(unwind_entry, &callchain_cursor, machine, | ||||
| 				   thread, evsel->attr.sample_regs_user, | ||||
| 				   sample, max_stack); | ||||
| 				   thread, sample, max_stack); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -702,11 +702,12 @@ static void regs_dump__printf(u64 mask, u64 *regs) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void regs_user__printf(struct perf_sample *sample, u64 mask) | ||||
| static void regs_user__printf(struct perf_sample *sample) | ||||
| { | ||||
| 	struct regs_dump *user_regs = &sample->user_regs; | ||||
| 
 | ||||
| 	if (user_regs->regs) { | ||||
| 		u64 mask = user_regs->mask; | ||||
| 		printf("... user regs: mask 0x%" PRIx64 "\n", mask); | ||||
| 		regs_dump__printf(mask, user_regs->regs); | ||||
| 	} | ||||
| @ -806,7 +807,7 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event, | ||||
| 		branch_stack__printf(sample); | ||||
| 
 | ||||
| 	if (sample_type & PERF_SAMPLE_REGS_USER) | ||||
| 		regs_user__printf(sample, evsel->attr.sample_regs_user); | ||||
| 		regs_user__printf(sample); | ||||
| 
 | ||||
| 	if (sample_type & PERF_SAMPLE_STACK_USER) | ||||
| 		stack_user__printf(&sample->user_stack); | ||||
|  | ||||
| @ -86,7 +86,6 @@ struct unwind_info { | ||||
| 	struct perf_sample	*sample; | ||||
| 	struct machine		*machine; | ||||
| 	struct thread		*thread; | ||||
| 	u64			sample_uregs; | ||||
| }; | ||||
| 
 | ||||
| #define dw_read(ptr, type, end) ({	\ | ||||
| @ -391,16 +390,16 @@ static int access_dso_mem(struct unwind_info *ui, unw_word_t addr, | ||||
| 	return !(size == sizeof(*data)); | ||||
| } | ||||
| 
 | ||||
| static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id, | ||||
| 		     u64 sample_regs) | ||||
| static int reg_value(unw_word_t *valp, struct regs_dump *regs, int id) | ||||
| { | ||||
| 	int i, idx = 0; | ||||
| 	u64 mask = regs->mask; | ||||
| 
 | ||||
| 	if (!(sample_regs & (1 << id))) | ||||
| 	if (!(mask & (1 << id))) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	for (i = 0; i < id; i++) { | ||||
| 		if (sample_regs & (1 << i)) | ||||
| 		if (mask & (1 << i)) | ||||
| 			idx++; | ||||
| 	} | ||||
| 
 | ||||
| @ -424,8 +423,7 @@ static int access_mem(unw_addr_space_t __maybe_unused as, | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP, | ||||
| 			ui->sample_uregs); | ||||
| 	ret = reg_value(&start, &ui->sample->user_regs, PERF_REG_SP); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
| @ -475,7 +473,7 @@ static int access_reg(unw_addr_space_t __maybe_unused as, | ||||
| 	if (id < 0) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	ret = reg_value(valp, &ui->sample->user_regs, id, ui->sample_uregs); | ||||
| 	ret = reg_value(valp, &ui->sample->user_regs, id); | ||||
| 	if (ret) { | ||||
| 		pr_err("unwind: can't read reg %d\n", regnum); | ||||
| 		return ret; | ||||
| @ -572,13 +570,11 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, | ||||
| 
 | ||||
| int unwind__get_entries(unwind_entry_cb_t cb, void *arg, | ||||
| 			struct machine *machine, struct thread *thread, | ||||
| 			u64 sample_uregs, struct perf_sample *data, | ||||
| 			int max_stack) | ||||
| 			struct perf_sample *data, int max_stack) | ||||
| { | ||||
| 	unw_word_t ip; | ||||
| 	struct unwind_info ui = { | ||||
| 		.sample       = data, | ||||
| 		.sample_uregs = sample_uregs, | ||||
| 		.thread       = thread, | ||||
| 		.machine      = machine, | ||||
| 	}; | ||||
| @ -587,7 +583,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg, | ||||
| 	if (!data->user_regs.regs) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	ret = reg_value(&ip, &data->user_regs, PERF_REG_IP, sample_uregs); | ||||
| 	ret = reg_value(&ip, &data->user_regs, PERF_REG_IP); | ||||
| 	if (ret) | ||||
| 		return ret; | ||||
| 
 | ||||
|  | ||||
| @ -17,7 +17,6 @@ typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg); | ||||
| int unwind__get_entries(unwind_entry_cb_t cb, void *arg, | ||||
| 			struct machine *machine, | ||||
| 			struct thread *thread, | ||||
| 			u64 sample_uregs, | ||||
| 			struct perf_sample *data, int max_stack); | ||||
| int unwind__arch_reg_id(int regnum); | ||||
| #else | ||||
| @ -26,7 +25,6 @@ unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, | ||||
| 		    void *arg __maybe_unused, | ||||
| 		    struct machine *machine __maybe_unused, | ||||
| 		    struct thread *thread __maybe_unused, | ||||
| 		    u64 sample_uregs __maybe_unused, | ||||
| 		    struct perf_sample *data __maybe_unused, | ||||
| 		    int max_stack __maybe_unused) | ||||
| { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user