Skip to content

Commit

Permalink
perf_counter: track task-comm data
Browse files Browse the repository at this point in the history
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: Peter Zijlstra <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Corey Ashford <[email protected]>
LKML-Reference: <[email protected]>
Signed-off-by: Ingo Molnar <[email protected]>
  • Loading branch information
Peter Zijlstra authored and Ingo Molnar committed Apr 8, 2009
1 parent 8740f94 commit 8d1b2d9
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 1 deletion.
1 change: 1 addition & 0 deletions fs/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
16 changes: 15 additions & 1 deletion include/linux/perf_counter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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_*
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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__ */
Expand Down
93 changes: 93 additions & 0 deletions kernel/perf_counter.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down

0 comments on commit 8d1b2d9

Please sign in to comment.