Commit-ID:  1a5941312414c71dece6717da9a0fa1303127afa
Gitweb:     http://git.kernel.org/tip/1a5941312414c71dece6717da9a0fa1303127afa
Author:     Alexander Shishkin <[email protected]>
AuthorDate: Wed, 14 Jan 2015 14:18:18 +0200
Committer:  Ingo Molnar <[email protected]>
CommitDate: Thu, 2 Apr 2015 17:14:16 +0200

perf: Add wakeup watermark control to the AUX area

When AUX area gets a certain amount of new data, we want to wake up
userspace to collect it. This adds a new control to specify how much
data will cause a wakeup. This is then passed down to pmu drivers via
output handle's "wakeup" field, so that the driver can find the nearest
point where it can generate an interrupt.

We repurpose __reserved_2 in the event attribute for this, even though
it was never checked to be zero before, aux_watermark will only matter
for new AUX-aware code, so the old code should still be fine.

Signed-off-by: Alexander Shishkin <[email protected]>
Signed-off-by: Peter Zijlstra (Intel) <[email protected]>
Cc: Borislav Petkov <[email protected]>
Cc: Frederic Weisbecker <[email protected]>
Cc: H. Peter Anvin <[email protected]>
Cc: Kaixu Xia <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Mike Galbraith <[email protected]>
Cc: Paul Mackerras <[email protected]>
Cc: Robert Richter <[email protected]>
Cc: Stephane Eranian <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Cc: [email protected]
Link: 
http://lkml.kernel.org/r/1421237903-181015-10-git-send-email-alexander.shish...@linux.intel.com
Signed-off-by: Ingo Molnar <[email protected]>
---
 include/uapi/linux/perf_event.h |  7 +++++++
 kernel/events/core.c            |  3 ++-
 kernel/events/internal.h        |  4 +++-
 kernel/events/ring_buffer.c     | 22 +++++++++++++++++++---
 4 files changed, 31 insertions(+), 5 deletions(-)

diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index 29ef2f7..84819546 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -261,6 +261,7 @@ enum perf_event_read_format {
 #define PERF_ATTR_SIZE_VER3    96      /* add: sample_regs_user */
                                        /* add: sample_stack_user */
 #define PERF_ATTR_SIZE_VER4    104     /* add: sample_regs_intr */
+#define PERF_ATTR_SIZE_VER5    112     /* add: aux_watermark */
 
 /*
  * Hardware event_id to monitor via a performance monitoring event:
@@ -366,6 +367,12 @@ struct perf_event_attr {
         * See asm/perf_regs.h for details.
         */
        __u64   sample_regs_intr;
+
+       /*
+        * Wakeup watermark for AUX area
+        */
+       __u32   aux_watermark;
+       __u32   __reserved_2;   /* align to __u64 */
 };
 
 #define perf_flags(attr)       (*(&(attr)->read_format + 1))
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 81e8d14..31f6b50 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -4677,7 +4677,8 @@ accounting:
                perf_event_init_userpage(event);
                perf_event_update_userpage(event);
        } else {
-               ret = rb_alloc_aux(rb, event, vma->vm_pgoff, nr_pages, flags);
+               ret = rb_alloc_aux(rb, event, vma->vm_pgoff, nr_pages,
+                                  event->attr.aux_watermark, flags);
                if (!ret)
                        rb->aux_mmap_locked = extra;
        }
diff --git a/kernel/events/internal.h b/kernel/events/internal.h
index ffd51d9..9f6ce9b 100644
--- a/kernel/events/internal.h
+++ b/kernel/events/internal.h
@@ -27,6 +27,7 @@ struct ring_buffer {
        local_t                         lost;           /* nr records lost   */
 
        long                            watermark;      /* wakeup watermark  */
+       long                            aux_watermark;
        /* poll crap */
        spinlock_t                      event_lock;
        struct list_head                event_list;
@@ -38,6 +39,7 @@ struct ring_buffer {
        /* AUX area */
        local_t                         aux_head;
        local_t                         aux_nest;
+       local_t                         aux_wakeup;
        unsigned long                   aux_pgoff;
        int                             aux_nr_pages;
        int                             aux_overwrite;
@@ -57,7 +59,7 @@ extern struct ring_buffer *
 rb_alloc(int nr_pages, long watermark, int cpu, int flags);
 extern void perf_event_wakeup(struct perf_event *event);
 extern int rb_alloc_aux(struct ring_buffer *rb, struct perf_event *event,
-                       pgoff_t pgoff, int nr_pages, int flags);
+                       pgoff_t pgoff, int nr_pages, long watermark, int flags);
 extern void rb_free_aux(struct ring_buffer *rb);
 extern struct ring_buffer *ring_buffer_get(struct perf_event *event);
 extern void ring_buffer_put(struct ring_buffer *rb);
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
index 67b3283..232f00f 100644
--- a/kernel/events/ring_buffer.c
+++ b/kernel/events/ring_buffer.c
@@ -296,6 +296,7 @@ void *perf_aux_output_begin(struct perf_output_handle 
*handle,
         */
        if (!rb->aux_overwrite) {
                aux_tail = ACCESS_ONCE(rb->user_page->aux_tail);
+               handle->wakeup = local_read(&rb->aux_wakeup) + 
rb->aux_watermark;
                if (aux_head - aux_tail < perf_aux_size(rb))
                        handle->size = CIRC_SPACE(aux_head, aux_tail, 
perf_aux_size(rb));
 
@@ -359,9 +360,12 @@ void perf_aux_output_end(struct perf_output_handle 
*handle, unsigned long size,
                perf_event_aux_event(handle->event, aux_head, size, flags);
        }
 
-       rb->user_page->aux_head = local_read(&rb->aux_head);
+       aux_head = rb->user_page->aux_head = local_read(&rb->aux_head);
 
-       perf_output_wakeup(handle);
+       if (aux_head - local_read(&rb->aux_wakeup) >= rb->aux_watermark) {
+               perf_output_wakeup(handle);
+               local_add(rb->aux_watermark, &rb->aux_wakeup);
+       }
        handle->event = NULL;
 
        local_set(&rb->aux_nest, 0);
@@ -383,6 +387,14 @@ int perf_aux_output_skip(struct perf_output_handle 
*handle, unsigned long size)
 
        local_add(size, &rb->aux_head);
 
+       aux_head = rb->user_page->aux_head = local_read(&rb->aux_head);
+       if (aux_head - local_read(&rb->aux_wakeup) >= rb->aux_watermark) {
+               perf_output_wakeup(handle);
+               local_add(rb->aux_watermark, &rb->aux_wakeup);
+               handle->wakeup = local_read(&rb->aux_wakeup) +
+                                rb->aux_watermark;
+       }
+
        handle->head = aux_head;
        handle->size -= size;
 
@@ -433,7 +445,7 @@ static void rb_free_aux_page(struct ring_buffer *rb, int 
idx)
 }
 
 int rb_alloc_aux(struct ring_buffer *rb, struct perf_event *event,
-                pgoff_t pgoff, int nr_pages, int flags)
+                pgoff_t pgoff, int nr_pages, long watermark, int flags)
 {
        bool overwrite = !(flags & RING_BUFFER_WRITABLE);
        int node = (event->cpu == -1) ? -1 : cpu_to_node(event->cpu);
@@ -497,6 +509,10 @@ int rb_alloc_aux(struct ring_buffer *rb, struct perf_event 
*event,
        atomic_set(&rb->aux_refcount, 1);
 
        rb->aux_overwrite = overwrite;
+       rb->aux_watermark = watermark;
+
+       if (!rb->aux_watermark && !rb->aux_overwrite)
+               rb->aux_watermark = nr_pages << (PAGE_SHIFT - 1);
 
 out:
        if (!ret)
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to