Merge branch 'perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/frederic/random-tracing into perf/urgent
Conflicts: tools/perf/builtin-top.c Semantic conflict: util/include/linux/list.h # fix prefetch.h removal fallout Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
		
				commit
				
					
						3ac1bbcf13
					
				
			
		
					 13 changed files with 138 additions and 47 deletions
				
			
		|  | @ -474,6 +474,7 @@ static int test__basic_mmap(void) | ||||||
| 	unsigned int nr_events[nsyscalls], | 	unsigned int nr_events[nsyscalls], | ||||||
| 		     expected_nr_events[nsyscalls], i, j; | 		     expected_nr_events[nsyscalls], i, j; | ||||||
| 	struct perf_evsel *evsels[nsyscalls], *evsel; | 	struct perf_evsel *evsels[nsyscalls], *evsel; | ||||||
|  | 	int sample_size = perf_sample_size(attr.sample_type); | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < nsyscalls; ++i) { | 	for (i = 0; i < nsyscalls; ++i) { | ||||||
| 		char name[64]; | 		char name[64]; | ||||||
|  | @ -558,7 +559,13 @@ static int test__basic_mmap(void) | ||||||
| 			goto out_munmap; | 			goto out_munmap; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		perf_event__parse_sample(event, attr.sample_type, false, &sample); | 		err = perf_event__parse_sample(event, attr.sample_type, sample_size, | ||||||
|  | 					       false, &sample); | ||||||
|  | 		if (err) { | ||||||
|  | 			pr_err("Can't parse sample, err = %d\n", err); | ||||||
|  | 			goto out_munmap; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		evsel = perf_evlist__id2evsel(evlist, sample.id); | 		evsel = perf_evlist__id2evsel(evlist, sample.id); | ||||||
| 		if (evsel == NULL) { | 		if (evsel == NULL) { | ||||||
| 			pr_debug("event with id %" PRIu64 | 			pr_debug("event with id %" PRIu64 | ||||||
|  |  | ||||||
|  | @ -805,9 +805,14 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx) | ||||||
| { | { | ||||||
| 	struct perf_sample sample; | 	struct perf_sample sample; | ||||||
| 	union perf_event *event; | 	union perf_event *event; | ||||||
|  | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	while ((event = perf_evlist__mmap_read(top.evlist, idx)) != NULL) { | 	while ((event = perf_evlist__mmap_read(top.evlist, idx)) != NULL) { | ||||||
| 		perf_session__parse_sample(self, event, &sample); | 		ret = perf_session__parse_sample(self, event, &sample); | ||||||
|  | 		if (ret) { | ||||||
|  | 			pr_err("Can't parse sample, err = %d\n", ret); | ||||||
|  | 			continue; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		if (event->header.type == PERF_RECORD_SAMPLE) | 		if (event->header.type == PERF_RECORD_SAMPLE) | ||||||
| 			perf_event__process_sample(event, &sample, self); | 			perf_event__process_sample(event, &sample, self); | ||||||
|  |  | ||||||
|  | @ -35,6 +35,22 @@ const char *perf_event__name(unsigned int id) | ||||||
| 	return perf_event__names[id]; | 	return perf_event__names[id]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | int perf_sample_size(u64 sample_type) | ||||||
|  | { | ||||||
|  | 	u64 mask = sample_type & PERF_SAMPLE_MASK; | ||||||
|  | 	int size = 0; | ||||||
|  | 	int i; | ||||||
|  | 
 | ||||||
|  | 	for (i = 0; i < 64; i++) { | ||||||
|  | 		if ((mask << i) & 1) | ||||||
|  | 			size++; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	size *= sizeof(u64); | ||||||
|  | 
 | ||||||
|  | 	return size; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static struct perf_sample synth_sample = { | static struct perf_sample synth_sample = { | ||||||
| 	.pid	   = -1, | 	.pid	   = -1, | ||||||
| 	.tid	   = -1, | 	.tid	   = -1, | ||||||
|  |  | ||||||
|  | @ -56,6 +56,13 @@ struct read_event { | ||||||
| 	u64 id; | 	u64 id; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | #define PERF_SAMPLE_MASK				\ | ||||||
|  | 	(PERF_SAMPLE_IP | PERF_SAMPLE_TID |		\ | ||||||
|  | 	 PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR |		\ | ||||||
|  | 	PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID |	\ | ||||||
|  | 	 PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) | ||||||
|  | 
 | ||||||
| struct sample_event { | struct sample_event { | ||||||
| 	struct perf_event_header        header; | 	struct perf_event_header        header; | ||||||
| 	u64 array[]; | 	u64 array[]; | ||||||
|  | @ -75,6 +82,8 @@ struct perf_sample { | ||||||
| 	struct ip_callchain *callchain; | 	struct ip_callchain *callchain; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | int perf_sample_size(u64 sample_type); | ||||||
|  | 
 | ||||||
| #define BUILD_ID_SIZE 20 | #define BUILD_ID_SIZE 20 | ||||||
| 
 | 
 | ||||||
| struct build_id_event { | struct build_id_event { | ||||||
|  | @ -178,6 +187,7 @@ int perf_event__preprocess_sample(const union perf_event *self, | ||||||
| const char *perf_event__name(unsigned int id); | const char *perf_event__name(unsigned int id); | ||||||
| 
 | 
 | ||||||
| int perf_event__parse_sample(const union perf_event *event, u64 type, | int perf_event__parse_sample(const union perf_event *event, u64 type, | ||||||
| 			     bool sample_id_all, struct perf_sample *sample); | 			     int sample_size, bool sample_id_all, | ||||||
|  | 			     struct perf_sample *sample); | ||||||
| 
 | 
 | ||||||
| #endif /* __PERF_RECORD_H */ | #endif /* __PERF_RECORD_H */ | ||||||
|  |  | ||||||
|  | @ -459,3 +459,34 @@ int perf_evlist__set_filters(struct perf_evlist *evlist) | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | u64 perf_evlist__sample_type(struct perf_evlist *evlist) | ||||||
|  | { | ||||||
|  | 	struct perf_evsel *pos; | ||||||
|  | 	u64 type = 0; | ||||||
|  | 
 | ||||||
|  | 	list_for_each_entry(pos, &evlist->entries, node) { | ||||||
|  | 		if (!type) | ||||||
|  | 			type = pos->attr.sample_type; | ||||||
|  | 		else if (type != pos->attr.sample_type) | ||||||
|  | 			die("non matching sample_type"); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return type; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool perf_evlist__sample_id_all(const struct perf_evlist *evlist) | ||||||
|  | { | ||||||
|  | 	bool value = false, first = true; | ||||||
|  | 	struct perf_evsel *pos; | ||||||
|  | 
 | ||||||
|  | 	list_for_each_entry(pos, &evlist->entries, node) { | ||||||
|  | 		if (first) { | ||||||
|  | 			value = pos->attr.sample_id_all; | ||||||
|  | 			first = false; | ||||||
|  | 		} else if (value != pos->attr.sample_id_all) | ||||||
|  | 			die("non matching sample_id_all"); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return value; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -66,4 +66,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid, | ||||||
| void perf_evlist__delete_maps(struct perf_evlist *evlist); | void perf_evlist__delete_maps(struct perf_evlist *evlist); | ||||||
| int perf_evlist__set_filters(struct perf_evlist *evlist); | int perf_evlist__set_filters(struct perf_evlist *evlist); | ||||||
| 
 | 
 | ||||||
|  | u64 perf_evlist__sample_type(struct perf_evlist *evlist); | ||||||
|  | bool perf_evlist__sample_id_all(const struct perf_evlist *evlist); | ||||||
|  | 
 | ||||||
| #endif /* __PERF_EVLIST_H */ | #endif /* __PERF_EVLIST_H */ | ||||||
|  |  | ||||||
|  | @ -303,8 +303,20 @@ static int perf_event__parse_id_sample(const union perf_event *event, u64 type, | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static bool sample_overlap(const union perf_event *event, | ||||||
|  | 			   const void *offset, u64 size) | ||||||
|  | { | ||||||
|  | 	const void *base = event; | ||||||
|  | 
 | ||||||
|  | 	if (offset + size > base + event->header.size) | ||||||
|  | 		return true; | ||||||
|  | 
 | ||||||
|  | 	return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int perf_event__parse_sample(const union perf_event *event, u64 type, | int perf_event__parse_sample(const union perf_event *event, u64 type, | ||||||
| 			     bool sample_id_all, struct perf_sample *data) | 			     int sample_size, bool sample_id_all, | ||||||
|  | 			     struct perf_sample *data) | ||||||
| { | { | ||||||
| 	const u64 *array; | 	const u64 *array; | ||||||
| 
 | 
 | ||||||
|  | @ -319,6 +331,9 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, | ||||||
| 
 | 
 | ||||||
| 	array = event->sample.array; | 	array = event->sample.array; | ||||||
| 
 | 
 | ||||||
|  | 	if (sample_size + sizeof(event->header) > event->header.size) | ||||||
|  | 		return -EFAULT; | ||||||
|  | 
 | ||||||
| 	if (type & PERF_SAMPLE_IP) { | 	if (type & PERF_SAMPLE_IP) { | ||||||
| 		data->ip = event->ip.ip; | 		data->ip = event->ip.ip; | ||||||
| 		array++; | 		array++; | ||||||
|  | @ -369,14 +384,29 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (type & PERF_SAMPLE_CALLCHAIN) { | 	if (type & PERF_SAMPLE_CALLCHAIN) { | ||||||
|  | 		if (sample_overlap(event, array, sizeof(data->callchain->nr))) | ||||||
|  | 			return -EFAULT; | ||||||
|  | 
 | ||||||
| 		data->callchain = (struct ip_callchain *)array; | 		data->callchain = (struct ip_callchain *)array; | ||||||
|  | 
 | ||||||
|  | 		if (sample_overlap(event, array, data->callchain->nr)) | ||||||
|  | 			return -EFAULT; | ||||||
|  | 
 | ||||||
| 		array += 1 + data->callchain->nr; | 		array += 1 + data->callchain->nr; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (type & PERF_SAMPLE_RAW) { | 	if (type & PERF_SAMPLE_RAW) { | ||||||
| 		u32 *p = (u32 *)array; | 		u32 *p = (u32 *)array; | ||||||
|  | 
 | ||||||
|  | 		if (sample_overlap(event, array, sizeof(u32))) | ||||||
|  | 			return -EFAULT; | ||||||
|  | 
 | ||||||
| 		data->raw_size = *p; | 		data->raw_size = *p; | ||||||
| 		p++; | 		p++; | ||||||
|  | 
 | ||||||
|  | 		if (sample_overlap(event, p, data->raw_size)) | ||||||
|  | 			return -EFAULT; | ||||||
|  | 
 | ||||||
| 		data->raw_data = p; | 		data->raw_data = p; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -934,37 +934,6 @@ out_delete_evlist: | ||||||
| 	return -ENOMEM; | 	return -ENOMEM; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| u64 perf_evlist__sample_type(struct perf_evlist *evlist) |  | ||||||
| { |  | ||||||
| 	struct perf_evsel *pos; |  | ||||||
| 	u64 type = 0; |  | ||||||
| 
 |  | ||||||
| 	list_for_each_entry(pos, &evlist->entries, node) { |  | ||||||
| 		if (!type) |  | ||||||
| 			type = pos->attr.sample_type; |  | ||||||
| 		else if (type != pos->attr.sample_type) |  | ||||||
| 			die("non matching sample_type"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return type; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool perf_evlist__sample_id_all(const struct perf_evlist *evlist) |  | ||||||
| { |  | ||||||
| 	bool value = false, first = true; |  | ||||||
| 	struct perf_evsel *pos; |  | ||||||
| 
 |  | ||||||
| 	list_for_each_entry(pos, &evlist->entries, node) { |  | ||||||
| 		if (first) { |  | ||||||
| 			value = pos->attr.sample_id_all; |  | ||||||
| 			first = false; |  | ||||||
| 		} else if (value != pos->attr.sample_id_all) |  | ||||||
| 			die("non matching sample_id_all"); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return value; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, | int perf_event__synthesize_attr(struct perf_event_attr *attr, u16 ids, u64 *id, | ||||||
| 				perf_event__handler_t process, | 				perf_event__handler_t process, | ||||||
| 				struct perf_session *session) | 				struct perf_session *session) | ||||||
|  |  | ||||||
|  | @ -64,8 +64,6 @@ int perf_header__write_pipe(int fd); | ||||||
| int perf_header__push_event(u64 id, const char *name); | int perf_header__push_event(u64 id, const char *name); | ||||||
| char *perf_header__find_event(u64 id); | char *perf_header__find_event(u64 id); | ||||||
| 
 | 
 | ||||||
| u64 perf_evlist__sample_type(struct perf_evlist *evlist); |  | ||||||
| bool perf_evlist__sample_id_all(const struct perf_evlist *evlist); |  | ||||||
| void perf_header__set_feat(struct perf_header *header, int feat); | void perf_header__set_feat(struct perf_header *header, int feat); | ||||||
| void perf_header__clear_feat(struct perf_header *header, int feat); | void perf_header__clear_feat(struct perf_header *header, int feat); | ||||||
| bool perf_header__has_feat(const struct perf_header *header, int feat); | bool perf_header__has_feat(const struct perf_header *header, int feat); | ||||||
|  |  | ||||||
|  | @ -1,4 +1,6 @@ | ||||||
| #include <linux/kernel.h> | #include <linux/kernel.h> | ||||||
|  | #include <linux/prefetch.h> | ||||||
|  | 
 | ||||||
| #include "../../../../include/linux/list.h" | #include "../../../../include/linux/list.h" | ||||||
| 
 | 
 | ||||||
| #ifndef PERF_LIST_H | #ifndef PERF_LIST_H | ||||||
|  |  | ||||||
|  | @ -675,6 +675,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, | ||||||
| 	union perf_event *event; | 	union perf_event *event; | ||||||
| 	int sample_id_all = 1, cpu; | 	int sample_id_all = 1, cpu; | ||||||
| 	static char *kwlist[] = {"sample_id_all", NULL, NULL}; | 	static char *kwlist[] = {"sample_id_all", NULL, NULL}; | ||||||
|  | 	int err; | ||||||
| 
 | 
 | ||||||
| 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i", kwlist, | 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|i", kwlist, | ||||||
| 					 &cpu, &sample_id_all)) | 					 &cpu, &sample_id_all)) | ||||||
|  | @ -690,11 +691,17 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, | ||||||
| 			return PyErr_NoMemory(); | 			return PyErr_NoMemory(); | ||||||
| 
 | 
 | ||||||
| 		first = list_entry(evlist->entries.next, struct perf_evsel, node); | 		first = list_entry(evlist->entries.next, struct perf_evsel, node); | ||||||
| 		perf_event__parse_sample(event, first->attr.sample_type, sample_id_all, | 		err = perf_event__parse_sample(event, first->attr.sample_type, | ||||||
| 					 &pevent->sample); | 					       perf_sample_size(first->attr.sample_type), | ||||||
|  | 					       sample_id_all, &pevent->sample); | ||||||
|  | 		if (err) { | ||||||
|  | 			pr_err("Can't parse sample, err = %d\n", err); | ||||||
|  | 			goto end; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		return pyevent; | 		return pyevent; | ||||||
| 	} | 	} | ||||||
| 
 | end: | ||||||
| 	Py_INCREF(Py_None); | 	Py_INCREF(Py_None); | ||||||
| 	return Py_None; | 	return Py_None; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -97,6 +97,7 @@ out: | ||||||
| void perf_session__update_sample_type(struct perf_session *self) | void perf_session__update_sample_type(struct perf_session *self) | ||||||
| { | { | ||||||
| 	self->sample_type = perf_evlist__sample_type(self->evlist); | 	self->sample_type = perf_evlist__sample_type(self->evlist); | ||||||
|  | 	self->sample_size = perf_sample_size(self->sample_type); | ||||||
| 	self->sample_id_all = perf_evlist__sample_id_all(self->evlist); | 	self->sample_id_all = perf_evlist__sample_id_all(self->evlist); | ||||||
| 	perf_session__id_header_size(self); | 	perf_session__id_header_size(self); | ||||||
| } | } | ||||||
|  | @ -479,6 +480,7 @@ static void flush_sample_queue(struct perf_session *s, | ||||||
| 	struct perf_sample sample; | 	struct perf_sample sample; | ||||||
| 	u64 limit = os->next_flush; | 	u64 limit = os->next_flush; | ||||||
| 	u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; | 	u64 last_ts = os->last_sample ? os->last_sample->timestamp : 0ULL; | ||||||
|  | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	if (!ops->ordered_samples || !limit) | 	if (!ops->ordered_samples || !limit) | ||||||
| 		return; | 		return; | ||||||
|  | @ -487,9 +489,12 @@ static void flush_sample_queue(struct perf_session *s, | ||||||
| 		if (iter->timestamp > limit) | 		if (iter->timestamp > limit) | ||||||
| 			break; | 			break; | ||||||
| 
 | 
 | ||||||
| 		perf_session__parse_sample(s, iter->event, &sample); | 		ret = perf_session__parse_sample(s, iter->event, &sample); | ||||||
| 		perf_session_deliver_event(s, iter->event, &sample, ops, | 		if (ret) | ||||||
| 					   iter->file_offset); | 			pr_err("Can't parse sample, err = %d\n", ret); | ||||||
|  | 		else | ||||||
|  | 			perf_session_deliver_event(s, iter->event, &sample, ops, | ||||||
|  | 						   iter->file_offset); | ||||||
| 
 | 
 | ||||||
| 		os->last_flush = iter->timestamp; | 		os->last_flush = iter->timestamp; | ||||||
| 		list_del(&iter->list); | 		list_del(&iter->list); | ||||||
|  | @ -805,7 +810,9 @@ static int perf_session__process_event(struct perf_session *session, | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * For all kernel events we get the sample data | 	 * For all kernel events we get the sample data | ||||||
| 	 */ | 	 */ | ||||||
| 	perf_session__parse_sample(session, event, &sample); | 	ret = perf_session__parse_sample(session, event, &sample); | ||||||
|  | 	if (ret) | ||||||
|  | 		return ret; | ||||||
| 
 | 
 | ||||||
| 	/* Preprocess sample records - precheck callchains */ | 	/* Preprocess sample records - precheck callchains */ | ||||||
| 	if (perf_session__preprocess_sample(session, event, &sample)) | 	if (perf_session__preprocess_sample(session, event, &sample)) | ||||||
|  | @ -1007,13 +1014,17 @@ remap: | ||||||
| 	file_pos = file_offset + head; | 	file_pos = file_offset + head; | ||||||
| 
 | 
 | ||||||
| more: | more: | ||||||
|  | 	/*
 | ||||||
|  | 	 * Ensure we have enough space remaining to read | ||||||
|  | 	 * the size of the event in the headers. | ||||||
|  | 	 */ | ||||||
|  | 	if (head + sizeof(event->header) > mmap_size) | ||||||
|  | 		goto remap; | ||||||
|  | 
 | ||||||
| 	event = (union perf_event *)(buf + head); | 	event = (union perf_event *)(buf + head); | ||||||
| 
 | 
 | ||||||
| 	if (session->header.needs_swap) | 	if (session->header.needs_swap) | ||||||
| 		perf_event_header__bswap(&event->header); | 		perf_event_header__bswap(&event->header); | ||||||
| 	size = event->header.size; |  | ||||||
| 	if (size == 0) |  | ||||||
| 		size = 8; |  | ||||||
| 
 | 
 | ||||||
| 	if (head + event->header.size > mmap_size) { | 	if (head + event->header.size > mmap_size) { | ||||||
| 		if (mmaps[map_idx]) { | 		if (mmaps[map_idx]) { | ||||||
|  |  | ||||||
|  | @ -43,6 +43,7 @@ struct perf_session { | ||||||
| 	 */ | 	 */ | ||||||
| 	struct hists		hists; | 	struct hists		hists; | ||||||
| 	u64			sample_type; | 	u64			sample_type; | ||||||
|  | 	int			sample_size; | ||||||
| 	int			fd; | 	int			fd; | ||||||
| 	bool			fd_pipe; | 	bool			fd_pipe; | ||||||
| 	bool			repipe; | 	bool			repipe; | ||||||
|  | @ -159,6 +160,7 @@ static inline int perf_session__parse_sample(struct perf_session *session, | ||||||
| 					     struct perf_sample *sample) | 					     struct perf_sample *sample) | ||||||
| { | { | ||||||
| 	return perf_event__parse_sample(event, session->sample_type, | 	return perf_event__parse_sample(event, session->sample_type, | ||||||
|  | 					session->sample_size, | ||||||
| 					session->sample_id_all, sample); | 					session->sample_id_all, sample); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Ingo Molnar
				Ingo Molnar