lkml.org 
[lkml]   [2011]   [May]   [2]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 2/4] perf: Add persistent event facilities
    Date
    From: Borislav Petkov <borislav.petkov@amd.com>

    Add a barebones implementation for registering persistent events with
    perf. For that, we don't destroy the buffers when they're unmapped;
    also, we map them read-only so that multiple agents can access them.

    Signed-off-by: Borislav Petkov <borislav.petkov@amd.com>
    ---
    include/linux/perf_event.h | 22 +++++++++++++++-
    kernel/events/Makefile | 2 +-
    kernel/events/core.c | 29 ++++++++++++++++++---
    kernel/events/persistent.c | 59 ++++++++++++++++++++++++++++++++++++++++++++
    4 files changed, 105 insertions(+), 7 deletions(-)
    create mode 100644 kernel/events/persistent.c

    diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
    index 9eec53d..18f2a68 100644
    --- a/include/linux/perf_event.h
    +++ b/include/linux/perf_event.h
    @@ -216,8 +216,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 */
    + persistent : 1, /* event always on */

    - __reserved_1 : 45;
    + __reserved_1 : 44;

    union {
    __u32 wakeup_events; /* wakeup every n events */
    @@ -1158,6 +1159,15 @@ extern void perf_swevent_put_recursion_context(int rctx);
    extern void perf_event_enable(struct perf_event *event);
    extern void perf_event_disable(struct perf_event *event);
    extern void perf_event_task_tick(void);
    +extern struct perf_buffer *
    +perf_buffer_alloc(int nr_pages, long watermark, int cpu, int flags);
    +extern void perf_buffer_put(struct perf_buffer *buffer);
    +extern struct perf_event *
    +perf_enable_persistent_event(struct perf_event_attr *attr,
    + int cpu, unsigned bufsz);
    +extern void perf_disable_persistent_event(struct perf_event *event, int cpu);
    +extern int perf_persistent_open(struct inode *inode, struct file *file);
    +extern const struct file_operations perf_pers_fops;
    #else
    static inline void
    perf_event_task_sched_in(struct task_struct *task) { }
    @@ -1192,6 +1202,16 @@ static inline void perf_swevent_put_recursion_context(int rctx) { }
    static inline void perf_event_enable(struct perf_event *event) { }
    static inline void perf_event_disable(struct perf_event *event) { }
    static inline void perf_event_task_tick(void) { }
    +static inline struct perf_buffer *
    +perf_buffer_alloc(int nr_pages, long watermark, int cpu, int flags) { return NULL; }
    +static inline void perf_buffer_put(struct perf_buffer *buffer) {}
    +static inline struct perf_event *
    +perf_enable_persistent_event(struct perf_event_attr *attr, int cpu,
    + unsigned bufsz) { return -EINVAL; }
    +static inline void
    +perf_disable_persistent_event(struct perf_event *event, int cpu) {}
    +static inline int
    +perf_persistent_open(struct inode *inode, struct file *file) { return -1; }
    #endif

    #define perf_output_put(handle, x) \
    diff --git a/kernel/events/Makefile b/kernel/events/Makefile
    index 26c00e4..e2d4d8e 100644
    --- a/kernel/events/Makefile
    +++ b/kernel/events/Makefile
    @@ -2,4 +2,4 @@ ifdef CONFIG_FUNCTION_TRACER
    CFLAGS_REMOVE_core.o = -pg
    endif

    -obj-y += core.o
    +obj-y += core.o persistent.o
    diff --git a/kernel/events/core.c b/kernel/events/core.c
    index 440bc48..2d8b1af 100644
    --- a/kernel/events/core.c
    +++ b/kernel/events/core.c
    @@ -2898,7 +2898,7 @@ static void free_event_rcu(struct rcu_head *head)
    kfree(event);
    }

    -static void perf_buffer_put(struct perf_buffer *buffer);
    +void perf_buffer_put(struct perf_buffer *buffer);

    static void free_event(struct perf_event *event)
    {
    @@ -3458,7 +3458,7 @@ static void *perf_mmap_alloc_page(int cpu)
    return page_address(page);
    }

    -static struct perf_buffer *
    +struct perf_buffer *
    perf_buffer_alloc(int nr_pages, long watermark, int cpu, int flags)
    {
    struct perf_buffer *buffer;
    @@ -3575,7 +3575,7 @@ static void perf_buffer_free(struct perf_buffer *buffer)
    schedule_work(&buffer->work);
    }

    -static struct perf_buffer *
    +struct perf_buffer *
    perf_buffer_alloc(int nr_pages, long watermark, int cpu, int flags)
    {
    struct perf_buffer *buffer;
    @@ -3676,7 +3676,7 @@ static struct perf_buffer *perf_buffer_get(struct perf_event *event)
    return buffer;
    }

    -static void perf_buffer_put(struct perf_buffer *buffer)
    +void perf_buffer_put(struct perf_buffer *buffer)
    {
    if (!atomic_dec_and_test(&buffer->refcount))
    return;
    @@ -3695,6 +3695,11 @@ static void perf_mmap_close(struct vm_area_struct *vma)
    {
    struct perf_event *event = vma->vm_file->private_data;

    + if (event->attr.persistent) {
    + atomic_dec(&event->mmap_count);
    + return;
    + }
    +
    if (atomic_dec_and_mutex_lock(&event->mmap_count, &event->mmap_mutex)) {
    unsigned long size = perf_data_size(event->buffer);
    struct user_struct *user = event->mmap_user;
    @@ -3737,7 +3742,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
    if (event->cpu == -1 && event->attr.inherit)
    return -EINVAL;

    - if (!(vma->vm_flags & VM_SHARED))
    + if (!(vma->vm_flags & VM_SHARED) && !event->attr.persistent)
    return -EINVAL;

    vma_size = vma->vm_end - vma->vm_start;
    @@ -3846,6 +3851,16 @@ static const struct file_operations perf_fops = {
    .fasync = perf_fasync,
    };

    +const struct file_operations perf_pers_fops = {
    + .llseek = no_llseek,
    + .open = perf_persistent_open,
    + .poll = perf_poll,
    + .unlocked_ioctl = perf_ioctl,
    + .compat_ioctl = perf_ioctl,
    + .mmap = perf_mmap,
    + .fasync = perf_fasync,
    +};
    +
    /*
    * Perf event wakeup
    *
    @@ -6756,6 +6771,10 @@ __perf_event_exit_task(struct perf_event *child_event,
    raw_spin_unlock_irq(&child_ctx->lock);
    }

    + /* do not remove persistent events on task exit */
    + if (child_event->attr.persistent)
    + return;
    +
    perf_remove_from_context(child_event);

    /*
    diff --git a/kernel/events/persistent.c b/kernel/events/persistent.c
    new file mode 100644
    index 0000000..e52752a
    --- /dev/null
    +++ b/kernel/events/persistent.c
    @@ -0,0 +1,59 @@
    +#include <linux/perf_event.h>
    +
    +/*
    + * Create and enable the perf event described by @attr.
    + *
    + * Returns the @event pointer which receives the allocated event from
    + * perf on success. Make sure to check return code before touching @event
    + * any further.
    + *
    + * @attr: perf attr template
    + * @cpu: on which cpu
    + * @nr_pages: perf buffer size in pages
    + *
    + */
    +struct perf_event *perf_enable_persistent_event(struct perf_event_attr *attr,
    + int cpu, unsigned nr_pages)
    +{
    + struct perf_buffer *buffer;
    + struct perf_event *event;
    +
    + event = perf_event_create_kernel_counter(attr, cpu, NULL, NULL);
    + if (IS_ERR(event))
    + return event;
    +
    + buffer = perf_buffer_alloc(nr_pages, 0, cpu, PERF_BUFFER_WRITABLE);
    + if (IS_ERR(buffer))
    + goto err;
    +
    + rcu_assign_pointer(event->buffer, buffer);
    + perf_event_enable(event);
    +
    + return event;
    +
    +err:
    + perf_event_release_kernel(event);
    + return ERR_PTR(-EINVAL);
    +}
    +
    +void perf_disable_persistent_event(struct perf_event *event, int cpu)
    +{
    + if (!event)
    + return;
    +
    + perf_event_disable(event);
    +
    + if (event->buffer) {
    + perf_buffer_put(event->buffer);
    + rcu_assign_pointer(event->buffer, NULL);
    + }
    +
    + perf_event_release_kernel(event);
    +}
    +
    +int perf_persistent_open(struct inode *inode, struct file *file)
    +{
    + file->private_data = inode->i_private;
    +
    + return 0;
    +}
    --
    1.7.4.rc2


    \
     
     \ /
      Last update: 2011-05-02 19:39    [W:0.031 / U:88.820 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site