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: Peter 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: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
8740f9418c
commit
8d1b2d9361
3 changed files with 109 additions and 1 deletions
|
@ -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)
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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(¤t->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
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue