Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8d1b2d93 authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Ingo Molnar
Browse files

perf_counter: track task-comm data



Similar to the mmap data stream, add one that tracks the task COMM field,
so that the userspace reporting knows what to call a task.

Signed-off-by: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
LKML-Reference: <20090408130409.127422406@chello.nl>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 8740f941
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -951,6 +951,7 @@ void set_task_comm(struct task_struct *tsk, char *buf)
	task_lock(tsk);
	strlcpy(tsk->comm, buf, sizeof(tsk->comm));
	task_unlock(tsk);
	perf_counter_comm(tsk);
}

int flush_old_exec(struct linux_binprm * bprm)
+15 −1
Original line number Diff line number Diff line
@@ -142,8 +142,9 @@ struct perf_counter_hw_event {
				exclude_idle   :  1, /* don't count when idle */
				mmap           :  1, /* include mmap data     */
				munmap         :  1, /* include munmap data   */
				comm	       :  1, /* include comm data     */

				__reserved_1   : 53;
				__reserved_1   : 52;

	__u32			extra_config_len;
	__u32			wakeup_events;	/* wakeup every n events */
@@ -230,6 +231,16 @@ enum perf_event_type {
	PERF_EVENT_MMAP			= 1,
	PERF_EVENT_MUNMAP		= 2,

	/*
	 * struct {
	 * 	struct perf_event_header	header;
	 *
	 * 	u32				pid, tid;
	 * 	char				comm[];
	 * };
	 */
	PERF_EVENT_COMM			= 3,

	/*
	 * When header.misc & PERF_EVENT_MISC_OVERFLOW the event_type field
	 * will be PERF_RECORD_*
@@ -545,6 +556,8 @@ extern void perf_counter_mmap(unsigned long addr, unsigned long len,
extern void perf_counter_munmap(unsigned long addr, unsigned long len,
				unsigned long pgoff, struct file *file);

extern void perf_counter_comm(struct task_struct *tsk);

#define MAX_STACK_DEPTH		255

struct perf_callchain_entry {
@@ -583,6 +596,7 @@ static inline void
perf_counter_munmap(unsigned long addr, unsigned long len,
		    unsigned long pgoff, struct file *file) 		{ }

static inline void perf_counter_comm(struct task_struct *tsk)		{ }
#endif

#endif /* __KERNEL__ */
+93 −0
Original line number Diff line number Diff line
@@ -1916,6 +1916,99 @@ static void perf_counter_output(struct perf_counter *counter,
	perf_output_end(&handle);
}

/*
 * comm tracking
 */

struct perf_comm_event {
	struct task_struct 	*task;
	char 			*comm;
	int			comm_size;

	struct {
		struct perf_event_header	header;

		u32				pid;
		u32				tid;
	} event;
};

static void perf_counter_comm_output(struct perf_counter *counter,
				     struct perf_comm_event *comm_event)
{
	struct perf_output_handle handle;
	int size = comm_event->event.header.size;
	int ret = perf_output_begin(&handle, counter, size, 0, 0);

	if (ret)
		return;

	perf_output_put(&handle, comm_event->event);
	perf_output_copy(&handle, comm_event->comm,
				   comm_event->comm_size);
	perf_output_end(&handle);
}

static int perf_counter_comm_match(struct perf_counter *counter,
				   struct perf_comm_event *comm_event)
{
	if (counter->hw_event.comm &&
	    comm_event->event.header.type == PERF_EVENT_COMM)
		return 1;

	return 0;
}

static void perf_counter_comm_ctx(struct perf_counter_context *ctx,
				  struct perf_comm_event *comm_event)
{
	struct perf_counter *counter;

	if (system_state != SYSTEM_RUNNING || list_empty(&ctx->event_list))
		return;

	rcu_read_lock();
	list_for_each_entry_rcu(counter, &ctx->event_list, event_entry) {
		if (perf_counter_comm_match(counter, comm_event))
			perf_counter_comm_output(counter, comm_event);
	}
	rcu_read_unlock();
}

static void perf_counter_comm_event(struct perf_comm_event *comm_event)
{
	struct perf_cpu_context *cpuctx;
	unsigned int size;
	char *comm = comm_event->task->comm;

	size = ALIGN(strlen(comm), sizeof(u64));

	comm_event->comm = comm;
	comm_event->comm_size = size;

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

	cpuctx = &get_cpu_var(perf_cpu_context);
	perf_counter_comm_ctx(&cpuctx->ctx, comm_event);
	put_cpu_var(perf_cpu_context);

	perf_counter_comm_ctx(&current->perf_counter_ctx, comm_event);
}

void perf_counter_comm(struct task_struct *task)
{
	struct perf_comm_event comm_event = {
		.task	= task,
		.event  = {
			.header = { .type = PERF_EVENT_COMM, },
			.pid	= task->group_leader->pid,
			.tid	= task->pid,
		},
	};

	perf_counter_comm_event(&comm_event);
}

/*
 * mmap tracking
 */