Commit 1a594131 authored by Alexander Shishkin's avatar Alexander Shishkin Committed by Ingo Molnar

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: default avatarAlexander Shishkin <alexander.shishkin@linux.intel.com>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Kaixu Xia <kaixu.xia@linaro.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Robert Richter <rric@kernel.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: acme@infradead.org
Cc: adrian.hunter@intel.com
Cc: kan.liang@intel.com
Cc: markus.t.metzger@intel.com
Cc: mathieu.poirier@linaro.org
Link: http://lkml.kernel.org/r/1421237903-181015-10-git-send-email-alexander.shishkin@linux.intel.comSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 2023a0d2
...@@ -261,6 +261,7 @@ enum perf_event_read_format { ...@@ -261,6 +261,7 @@ enum perf_event_read_format {
#define PERF_ATTR_SIZE_VER3 96 /* add: sample_regs_user */ #define PERF_ATTR_SIZE_VER3 96 /* add: sample_regs_user */
/* add: sample_stack_user */ /* add: sample_stack_user */
#define PERF_ATTR_SIZE_VER4 104 /* add: sample_regs_intr */ #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: * Hardware event_id to monitor via a performance monitoring event:
...@@ -366,6 +367,12 @@ struct perf_event_attr { ...@@ -366,6 +367,12 @@ struct perf_event_attr {
* See asm/perf_regs.h for details. * See asm/perf_regs.h for details.
*/ */
__u64 sample_regs_intr; __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)) #define perf_flags(attr) (*(&(attr)->read_format + 1))
......
...@@ -4677,7 +4677,8 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -4677,7 +4677,8 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
perf_event_init_userpage(event); perf_event_init_userpage(event);
perf_event_update_userpage(event); perf_event_update_userpage(event);
} else { } 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) if (!ret)
rb->aux_mmap_locked = extra; rb->aux_mmap_locked = extra;
} }
......
...@@ -27,6 +27,7 @@ struct ring_buffer { ...@@ -27,6 +27,7 @@ struct ring_buffer {
local_t lost; /* nr records lost */ local_t lost; /* nr records lost */
long watermark; /* wakeup watermark */ long watermark; /* wakeup watermark */
long aux_watermark;
/* poll crap */ /* poll crap */
spinlock_t event_lock; spinlock_t event_lock;
struct list_head event_list; struct list_head event_list;
...@@ -38,6 +39,7 @@ struct ring_buffer { ...@@ -38,6 +39,7 @@ struct ring_buffer {
/* AUX area */ /* AUX area */
local_t aux_head; local_t aux_head;
local_t aux_nest; local_t aux_nest;
local_t aux_wakeup;
unsigned long aux_pgoff; unsigned long aux_pgoff;
int aux_nr_pages; int aux_nr_pages;
int aux_overwrite; int aux_overwrite;
...@@ -57,7 +59,7 @@ extern struct ring_buffer * ...@@ -57,7 +59,7 @@ extern struct ring_buffer *
rb_alloc(int nr_pages, long watermark, int cpu, int flags); rb_alloc(int nr_pages, long watermark, int cpu, int flags);
extern void perf_event_wakeup(struct perf_event *event); extern void perf_event_wakeup(struct perf_event *event);
extern int rb_alloc_aux(struct ring_buffer *rb, 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 void rb_free_aux(struct ring_buffer *rb);
extern struct ring_buffer *ring_buffer_get(struct perf_event *event); extern struct ring_buffer *ring_buffer_get(struct perf_event *event);
extern void ring_buffer_put(struct ring_buffer *rb); extern void ring_buffer_put(struct ring_buffer *rb);
......
...@@ -296,6 +296,7 @@ void *perf_aux_output_begin(struct perf_output_handle *handle, ...@@ -296,6 +296,7 @@ void *perf_aux_output_begin(struct perf_output_handle *handle,
*/ */
if (!rb->aux_overwrite) { if (!rb->aux_overwrite) {
aux_tail = ACCESS_ONCE(rb->user_page->aux_tail); 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)) if (aux_head - aux_tail < perf_aux_size(rb))
handle->size = CIRC_SPACE(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, ...@@ -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); 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; handle->event = NULL;
local_set(&rb->aux_nest, 0); local_set(&rb->aux_nest, 0);
...@@ -383,6 +387,14 @@ int perf_aux_output_skip(struct perf_output_handle *handle, unsigned long size) ...@@ -383,6 +387,14 @@ int perf_aux_output_skip(struct perf_output_handle *handle, unsigned long size)
local_add(size, &rb->aux_head); 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->head = aux_head;
handle->size -= size; handle->size -= size;
...@@ -433,7 +445,7 @@ static void rb_free_aux_page(struct ring_buffer *rb, int idx) ...@@ -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, 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); bool overwrite = !(flags & RING_BUFFER_WRITABLE);
int node = (event->cpu == -1) ? -1 : cpu_to_node(event->cpu); 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, ...@@ -497,6 +509,10 @@ int rb_alloc_aux(struct ring_buffer *rb, struct perf_event *event,
atomic_set(&rb->aux_refcount, 1); atomic_set(&rb->aux_refcount, 1);
rb->aux_overwrite = overwrite; rb->aux_overwrite = overwrite;
rb->aux_watermark = watermark;
if (!rb->aux_watermark && !rb->aux_overwrite)
rb->aux_watermark = nr_pages << (PAGE_SHIFT - 1);
out: out:
if (!ret) if (!ret)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment