Commit 75b5293a authored by Ingo Molnar's avatar Ingo Molnar
Browse files

Merge branch 'perf/core' of...

Merge branch 'perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux-2.6 into perf/core
parents 10a18d7d ce47dc56
Loading
Loading
Loading
Loading
+12 −1
Original line number Diff line number Diff line
@@ -215,8 +215,9 @@ struct perf_event_attr {
				 */
				precise_ip     :  2, /* skid constraint       */
				mmap_data      :  1, /* non-exec mmap data    */
				sample_id_all  :  1, /* sample_type all events */

				__reserved_1   : 46;
				__reserved_1   : 45;

	union {
		__u32		wakeup_events;	  /* wakeup every n events */
@@ -327,6 +328,15 @@ struct perf_event_header {
enum perf_event_type {

	/*
	 * If perf_event_attr.sample_id_all is set then all event types will
	 * have the sample_type selected fields related to where/when
	 * (identity) an event took place (TID, TIME, ID, CPU, STREAM_ID)
	 * described in PERF_RECORD_SAMPLE below, it will be stashed just after
	 * the perf_event_header and the fields already present for the existing
	 * fields, i.e. at the end of the payload. That way a newer perf.data
	 * file will be supported by older perf tools, with these new optional
	 * fields being ignored.
	 *
	 * The MMAP events record the PROT_EXEC mappings so that we can
	 * correlate userspace IPs to code. They have the following structure:
	 *
@@ -759,6 +769,7 @@ struct perf_event {

	struct perf_event_attr		attr;
	u16				header_size;
	u16				id_header_size;
	u16				read_size;
	struct hw_perf_event		hw;

+167 −67
Original line number Diff line number Diff line
@@ -133,6 +133,28 @@ static void unclone_ctx(struct perf_event_context *ctx)
	}
}

static u32 perf_event_pid(struct perf_event *event, struct task_struct *p)
{
	/*
	 * only top level events have the pid namespace they were created in
	 */
	if (event->parent)
		event = event->parent;

	return task_tgid_nr_ns(p, event->ns);
}

static u32 perf_event_tid(struct perf_event *event, struct task_struct *p)
{
	/*
	 * only top level events have the pid namespace they were created in
	 */
	if (event->parent)
		event = event->parent;

	return task_pid_nr_ns(p, event->ns);
}

/*
 * If we inherit events we want to return the parent event id
 * to userspace.
@@ -351,15 +373,30 @@ static void perf_event__header_size(struct perf_event *event)
	if (sample_type & PERF_SAMPLE_IP)
		size += sizeof(data->ip);

	if (sample_type & PERF_SAMPLE_ADDR)
		size += sizeof(data->addr);

	if (sample_type & PERF_SAMPLE_PERIOD)
		size += sizeof(data->period);

	if (sample_type & PERF_SAMPLE_READ)
		size += event->read_size;

	event->header_size = size;
}

static void perf_event__id_header_size(struct perf_event *event)
{
	struct perf_sample_data *data;
	u64 sample_type = event->attr.sample_type;
	u16 size = 0;

	if (sample_type & PERF_SAMPLE_TID)
		size += sizeof(data->tid_entry);

	if (sample_type & PERF_SAMPLE_TIME)
		size += sizeof(data->time);

	if (sample_type & PERF_SAMPLE_ADDR)
		size += sizeof(data->addr);

	if (sample_type & PERF_SAMPLE_ID)
		size += sizeof(data->id);

@@ -369,13 +406,7 @@ static void perf_event__header_size(struct perf_event *event)
	if (sample_type & PERF_SAMPLE_CPU)
		size += sizeof(data->cpu_entry);

	if (sample_type & PERF_SAMPLE_PERIOD)
		size += sizeof(data->period);

	if (sample_type & PERF_SAMPLE_READ)
		size += event->read_size;

	event->header_size = size;
	event->id_header_size = size;
}

static void perf_group_attach(struct perf_event *event)
@@ -3357,6 +3388,73 @@ __always_inline void perf_output_copy(struct perf_output_handle *handle,
	} while (len);
}

static void __perf_event_header__init_id(struct perf_event_header *header,
					 struct perf_sample_data *data,
					 struct perf_event *event)
{
	u64 sample_type = event->attr.sample_type;

	data->type = sample_type;
	header->size += event->id_header_size;

	if (sample_type & PERF_SAMPLE_TID) {
		/* namespace issues */
		data->tid_entry.pid = perf_event_pid(event, current);
		data->tid_entry.tid = perf_event_tid(event, current);
	}

	if (sample_type & PERF_SAMPLE_TIME)
		data->time = perf_clock();

	if (sample_type & PERF_SAMPLE_ID)
		data->id = primary_event_id(event);

	if (sample_type & PERF_SAMPLE_STREAM_ID)
		data->stream_id = event->id;

	if (sample_type & PERF_SAMPLE_CPU) {
		data->cpu_entry.cpu	 = raw_smp_processor_id();
		data->cpu_entry.reserved = 0;
	}
}

static void perf_event_header__init_id(struct perf_event_header *header,
				       struct perf_sample_data *data,
				       struct perf_event *event)
{
	if (event->attr.sample_id_all)
		__perf_event_header__init_id(header, data, event);
}

static void __perf_event__output_id_sample(struct perf_output_handle *handle,
					   struct perf_sample_data *data)
{
	u64 sample_type = data->type;

	if (sample_type & PERF_SAMPLE_TID)
		perf_output_put(handle, data->tid_entry);

	if (sample_type & PERF_SAMPLE_TIME)
		perf_output_put(handle, data->time);

	if (sample_type & PERF_SAMPLE_ID)
		perf_output_put(handle, data->id);

	if (sample_type & PERF_SAMPLE_STREAM_ID)
		perf_output_put(handle, data->stream_id);

	if (sample_type & PERF_SAMPLE_CPU)
		perf_output_put(handle, data->cpu_entry);
}

static void perf_event__output_id_sample(struct perf_event *event,
					 struct perf_output_handle *handle,
					 struct perf_sample_data *sample)
{
	if (event->attr.sample_id_all)
		__perf_event__output_id_sample(handle, sample);
}

int perf_output_begin(struct perf_output_handle *handle,
		      struct perf_event *event, unsigned int size,
		      int nmi, int sample)
@@ -3364,6 +3462,7 @@ int perf_output_begin(struct perf_output_handle *handle,
	struct perf_buffer *buffer;
	unsigned long tail, offset, head;
	int have_lost;
	struct perf_sample_data sample_data;
	struct {
		struct perf_event_header header;
		u64			 id;
@@ -3390,8 +3489,12 @@ int perf_output_begin(struct perf_output_handle *handle,
		goto out;

	have_lost = local_read(&buffer->lost);
	if (have_lost)
		size += sizeof(lost_event);
	if (have_lost) {
		lost_event.header.size = sizeof(lost_event);
		perf_event_header__init_id(&lost_event.header, &sample_data,
					   event);
		size += lost_event.header.size;
	}

	perf_output_get_handle(handle);

@@ -3422,11 +3525,11 @@ int perf_output_begin(struct perf_output_handle *handle,
	if (have_lost) {
		lost_event.header.type = PERF_RECORD_LOST;
		lost_event.header.misc = 0;
		lost_event.header.size = sizeof(lost_event);
		lost_event.id          = event->id;
		lost_event.lost        = local_xchg(&buffer->lost, 0);

		perf_output_put(handle, lost_event);
		perf_event__output_id_sample(event, handle, &sample_data);
	}

	return 0;
@@ -3459,28 +3562,6 @@ void perf_output_end(struct perf_output_handle *handle)
	rcu_read_unlock();
}

static u32 perf_event_pid(struct perf_event *event, struct task_struct *p)
{
	/*
	 * only top level events have the pid namespace they were created in
	 */
	if (event->parent)
		event = event->parent;

	return task_tgid_nr_ns(p, event->ns);
}

static u32 perf_event_tid(struct perf_event *event, struct task_struct *p)
{
	/*
	 * only top level events have the pid namespace they were created in
	 */
	if (event->parent)
		event = event->parent;

	return task_pid_nr_ns(p, event->ns);
}

static void perf_output_read_one(struct perf_output_handle *handle,
				 struct perf_event *event,
				 u64 enabled, u64 running)
@@ -3655,37 +3736,17 @@ void perf_prepare_sample(struct perf_event_header *header,
{
	u64 sample_type = event->attr.sample_type;

	data->type = sample_type;

	header->type = PERF_RECORD_SAMPLE;
	header->size = sizeof(*header) + event->header_size;

	header->misc = 0;
	header->misc |= perf_misc_flags(regs);

	__perf_event_header__init_id(header, data, event);

	if (sample_type & PERF_SAMPLE_IP)
		data->ip = perf_instruction_pointer(regs);

	if (sample_type & PERF_SAMPLE_TID) {
		/* namespace issues */
		data->tid_entry.pid = perf_event_pid(event, current);
		data->tid_entry.tid = perf_event_tid(event, current);
	}

	if (sample_type & PERF_SAMPLE_TIME)
		data->time = perf_clock();

	if (sample_type & PERF_SAMPLE_ID)
		data->id = primary_event_id(event);

	if (sample_type & PERF_SAMPLE_STREAM_ID)
		data->stream_id = event->id;

	if (sample_type & PERF_SAMPLE_CPU) {
		data->cpu_entry.cpu		= raw_smp_processor_id();
		data->cpu_entry.reserved	= 0;
	}

	if (sample_type & PERF_SAMPLE_CALLCHAIN) {
		int size = 1;

@@ -3749,6 +3810,7 @@ perf_event_read_event(struct perf_event *event,
			struct task_struct *task)
{
	struct perf_output_handle handle;
	struct perf_sample_data sample;
	struct perf_read_event read_event = {
		.header = {
			.type = PERF_RECORD_READ,
@@ -3760,12 +3822,14 @@ perf_event_read_event(struct perf_event *event,
	};
	int ret;

	perf_event_header__init_id(&read_event.header, &sample, event);
	ret = perf_output_begin(&handle, event, read_event.header.size, 0, 0);
	if (ret)
		return;

	perf_output_put(&handle, read_event);
	perf_output_read(&handle, event);
	perf_event__output_id_sample(event, &handle, &sample);

	perf_output_end(&handle);
}
@@ -3795,14 +3859,16 @@ static void perf_event_task_output(struct perf_event *event,
				     struct perf_task_event *task_event)
{
	struct perf_output_handle handle;
	struct perf_sample_data	sample;
	struct task_struct *task = task_event->task;
	int size, ret;
	int ret, size = task_event->event_id.header.size;

	size  = task_event->event_id.header.size;
	ret = perf_output_begin(&handle, event, size, 0, 0);
	perf_event_header__init_id(&task_event->event_id.header, &sample, event);

	ret = perf_output_begin(&handle, event,
				task_event->event_id.header.size, 0, 0);
	if (ret)
		return;
		goto out;

	task_event->event_id.pid = perf_event_pid(event, task);
	task_event->event_id.ppid = perf_event_pid(event, current);
@@ -3812,7 +3878,11 @@ static void perf_event_task_output(struct perf_event *event,

	perf_output_put(&handle, task_event->event_id);

	perf_event__output_id_sample(event, &handle, &sample);

	perf_output_end(&handle);
out:
	task_event->event_id.header.size = size;
}

static int perf_event_task_match(struct perf_event *event)
@@ -3925,11 +3995,16 @@ static void perf_event_comm_output(struct perf_event *event,
				     struct perf_comm_event *comm_event)
{
	struct perf_output_handle handle;
	struct perf_sample_data sample;
	int size = comm_event->event_id.header.size;
	int ret = perf_output_begin(&handle, event, size, 0, 0);
	int ret;

	perf_event_header__init_id(&comm_event->event_id.header, &sample, event);
	ret = perf_output_begin(&handle, event,
				comm_event->event_id.header.size, 0, 0);

	if (ret)
		return;
		goto out;

	comm_event->event_id.pid = perf_event_pid(event, comm_event->task);
	comm_event->event_id.tid = perf_event_tid(event, comm_event->task);
@@ -3937,7 +4012,12 @@ static void perf_event_comm_output(struct perf_event *event,
	perf_output_put(&handle, comm_event->event_id);
	perf_output_copy(&handle, comm_event->comm,
				   comm_event->comm_size);

	perf_event__output_id_sample(event, &handle, &sample);

	perf_output_end(&handle);
out:
	comm_event->event_id.header.size = size;
}

static int perf_event_comm_match(struct perf_event *event)
@@ -3982,7 +4062,6 @@ static void perf_event_comm_event(struct perf_comm_event *comm_event)
	comm_event->comm_size = size;

	comm_event->event_id.header.size = sizeof(comm_event->event_id) + size;

	rcu_read_lock();
	list_for_each_entry_rcu(pmu, &pmus, entry) {
		cpuctx = get_cpu_ptr(pmu->pmu_cpu_context);
@@ -4061,11 +4140,15 @@ static void perf_event_mmap_output(struct perf_event *event,
				     struct perf_mmap_event *mmap_event)
{
	struct perf_output_handle handle;
	struct perf_sample_data sample;
	int size = mmap_event->event_id.header.size;
	int ret = perf_output_begin(&handle, event, size, 0, 0);
	int ret;

	perf_event_header__init_id(&mmap_event->event_id.header, &sample, event);
	ret = perf_output_begin(&handle, event,
				mmap_event->event_id.header.size, 0, 0);
	if (ret)
		return;
		goto out;

	mmap_event->event_id.pid = perf_event_pid(event, current);
	mmap_event->event_id.tid = perf_event_tid(event, current);
@@ -4073,7 +4156,12 @@ static void perf_event_mmap_output(struct perf_event *event,
	perf_output_put(&handle, mmap_event->event_id);
	perf_output_copy(&handle, mmap_event->file_name,
				   mmap_event->file_size);

	perf_event__output_id_sample(event, &handle, &sample);

	perf_output_end(&handle);
out:
	mmap_event->event_id.header.size = size;
}

static int perf_event_mmap_match(struct perf_event *event,
@@ -4226,6 +4314,7 @@ void perf_event_mmap(struct vm_area_struct *vma)
static void perf_log_throttle(struct perf_event *event, int enable)
{
	struct perf_output_handle handle;
	struct perf_sample_data sample;
	int ret;

	struct {
@@ -4247,11 +4336,15 @@ static void perf_log_throttle(struct perf_event *event, int enable)
	if (enable)
		throttle_event.header.type = PERF_RECORD_UNTHROTTLE;

	ret = perf_output_begin(&handle, event, sizeof(throttle_event), 1, 0);
	perf_event_header__init_id(&throttle_event.header, &sample, event);

	ret = perf_output_begin(&handle, event,
				throttle_event.header.size, 1, 0);
	if (ret)
		return;

	perf_output_put(&handle, throttle_event);
	perf_event__output_id_sample(event, &handle, &sample);
	perf_output_end(&handle);
}

@@ -5745,6 +5838,7 @@ SYSCALL_DEFINE5(perf_event_open,
	 * Precalculate sample_data sizes
	 */
	perf_event__header_size(event);
	perf_event__id_header_size(event);

	/*
	 * Drop the reference on the group_event after placing the
@@ -6098,6 +6192,12 @@ inherit_event(struct perf_event *parent_event,
	child_event->ctx = child_ctx;
	child_event->overflow_handler = parent_event->overflow_handler;

	/*
	 * Precalculate sample_data sizes
	 */
	perf_event__header_size(child_event);
	perf_event__id_header_size(child_event);

	/*
	 * Link it up in the child's context:
	 */
+5 −0
Original line number Diff line number Diff line
@@ -108,6 +108,11 @@ OPTIONS
--data::
	Sample addresses.

-T::
--timestamp::
	Sample timestamps. Use it with 'perf report -D' to see the timestamps,
	for instance.

-n::
--no-samples::
	Don't sample.
+3 −3
Original line number Diff line number Diff line
@@ -58,12 +58,12 @@ static int hists__add_entry(struct hists *self, struct addr_location *al)
	return hist_entry__inc_addr_samples(he, al->addr);
}

static int process_sample_event(event_t *event, struct perf_session *session)
static int process_sample_event(event_t *event, struct sample_data *sample,
				struct perf_session *session)
{
	struct addr_location al;
	struct sample_data data;

	if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) {
	if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) {
		pr_warning("problem processing %d event, skipping it.\n",
			   event->header.type);
		return -1;
+6 −5
Original line number Diff line number Diff line
@@ -30,12 +30,13 @@ static int hists__add_entry(struct hists *self,
	return -ENOMEM;
}

static int diff__process_sample_event(event_t *event, struct perf_session *session)
static int diff__process_sample_event(event_t *event,
				      struct sample_data *sample,
				      struct perf_session *session)
{
	struct addr_location al;
	struct sample_data data = { .period = 1, };

	if (event__preprocess_sample(event, session, &al, &data, NULL) < 0) {
	if (event__preprocess_sample(event, session, &al, sample, NULL) < 0) {
		pr_warning("problem processing %d event, skipping it.\n",
			   event->header.type);
		return -1;
@@ -44,12 +45,12 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi
	if (al.filtered || al.sym == NULL)
		return 0;

	if (hists__add_entry(&session->hists, &al, data.period)) {
	if (hists__add_entry(&session->hists, &al, sample->period)) {
		pr_warning("problem incrementing symbol period, skipping event\n");
		return -1;
	}

	session->hists.stats.total_period += data.period;
	session->hists.stats.total_period += sample->period;
	return 0;
}

Loading