lkml.org 
[lkml]   [2009]   [Apr]   [8]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[tip:perfcounters/core] perf_counter: track task-comm data
    Commit-ID:  8d1b2d9361b494bfc761700c348c65ebbe3deb5b
    Gitweb: http://git.kernel.org/tip/8d1b2d9361b494bfc761700c348c65ebbe3deb5b
    Author: Peter Zijlstra <a.p.zijlstra@chello.nl>
    AuthorDate: Wed, 8 Apr 2009 15:01:30 +0200
    Committer: Ingo Molnar <mingo@elte.hu>
    CommitDate: Wed, 8 Apr 2009 19:05:47 +0200

    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>


    ---
    fs/exec.c | 1 +
    include/linux/perf_counter.h | 16 +++++++-
    kernel/perf_counter.c | 93 ++++++++++++++++++++++++++++++++++++++++++
    3 files changed, 109 insertions(+), 1 deletions(-)

    diff --git a/fs/exec.c b/fs/exec.c
    index e015c0b..bf47ed0 100644
    --- a/fs/exec.c
    +++ b/fs/exec.c
    @@ -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)
    diff --git a/include/linux/perf_counter.h b/include/linux/perf_counter.h
    index 8bf764f..a70a55f 100644
    --- a/include/linux/perf_counter.h
    +++ b/include/linux/perf_counter.h
    @@ -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 */
    @@ -231,6 +232,16 @@ enum perf_event_type {
    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__ */
    diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c
    index bf12df6..2d4aebb 100644
    --- a/kernel/perf_counter.c
    +++ b/kernel/perf_counter.c
    @@ -1917,6 +1917,99 @@ static void perf_counter_output(struct perf_counter *counter,
    }

    /*
    + * 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
    */


    \
     
     \ /
      Last update: 2009-04-08 19:15    [W:4.576 / U:0.384 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site