aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/perf_counter.c
diff options
context:
space:
mode:
authorPeter Zijlstra <a.p.zijlstra@chello.nl>2009-09-17 13:01:10 -0400
committerIngo Molnar <mingo@elte.hu>2009-09-17 16:08:26 -0400
commit2667de81f3256c944b06abdf2c56c2f192fcb724 (patch)
treed642156cfe0c52d2fb7ec1de4a2060018c8e3f8d /kernel/perf_counter.c
parent850bc73ffcc99cddfb52bc23217c60810c508853 (diff)
perf_counter: Allow for a wakeup watermark
Currently we wake the mmap() consumer once every PAGE_SIZE of data and/or once event wakeup_events when specified. For high speed sampling this results in too many wakeups wrt. the buffer size, hence change this. We move the default wakeup limit to 1/4-th the buffer size, and provide for means to manually specify this limit. Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <new-submission> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/perf_counter.c')
-rw-r--r--kernel/perf_counter.c32
1 files changed, 19 insertions, 13 deletions
diff --git a/kernel/perf_counter.c b/kernel/perf_counter.c
index fe0d1adde804..29b73b6e8146 100644
--- a/kernel/perf_counter.c
+++ b/kernel/perf_counter.c
@@ -2176,6 +2176,13 @@ static int perf_mmap_data_alloc(struct perf_counter *counter, int nr_pages)
2176 data->nr_pages = nr_pages; 2176 data->nr_pages = nr_pages;
2177 atomic_set(&data->lock, -1); 2177 atomic_set(&data->lock, -1);
2178 2178
2179 if (counter->attr.watermark) {
2180 data->watermark = min_t(long, PAGE_SIZE * nr_pages,
2181 counter->attr.wakeup_watermark);
2182 }
2183 if (!data->watermark)
2184 data->watermark = max(PAGE_SIZE, PAGE_SIZE * nr_pages / 4);
2185
2179 rcu_assign_pointer(counter->data, data); 2186 rcu_assign_pointer(counter->data, data);
2180 2187
2181 return 0; 2188 return 0;
@@ -2517,23 +2524,15 @@ struct perf_output_handle {
2517 unsigned long flags; 2524 unsigned long flags;
2518}; 2525};
2519 2526
2520static bool perf_output_space(struct perf_mmap_data *data, 2527static bool perf_output_space(struct perf_mmap_data *data, unsigned long tail,
2521 unsigned int offset, unsigned int head) 2528 unsigned long offset, unsigned long head)
2522{ 2529{
2523 unsigned long tail;
2524 unsigned long mask; 2530 unsigned long mask;
2525 2531
2526 if (!data->writable) 2532 if (!data->writable)
2527 return true; 2533 return true;
2528 2534
2529 mask = (data->nr_pages << PAGE_SHIFT) - 1; 2535 mask = (data->nr_pages << PAGE_SHIFT) - 1;
2530 /*
2531 * Userspace could choose to issue a mb() before updating the tail
2532 * pointer. So that all reads will be completed before the write is
2533 * issued.
2534 */
2535 tail = ACCESS_ONCE(data->user_page->data_tail);
2536 smp_rmb();
2537 2536
2538 offset = (offset - tail) & mask; 2537 offset = (offset - tail) & mask;
2539 head = (head - tail) & mask; 2538 head = (head - tail) & mask;
@@ -2679,7 +2678,7 @@ static int perf_output_begin(struct perf_output_handle *handle,
2679{ 2678{
2680 struct perf_counter *output_counter; 2679 struct perf_counter *output_counter;
2681 struct perf_mmap_data *data; 2680 struct perf_mmap_data *data;
2682 unsigned int offset, head; 2681 unsigned long tail, offset, head;
2683 int have_lost; 2682 int have_lost;
2684 struct { 2683 struct {
2685 struct perf_event_header header; 2684 struct perf_event_header header;
@@ -2717,16 +2716,23 @@ static int perf_output_begin(struct perf_output_handle *handle,
2717 perf_output_lock(handle); 2716 perf_output_lock(handle);
2718 2717
2719 do { 2718 do {
2719 /*
2720 * Userspace could choose to issue a mb() before updating the
2721 * tail pointer. So that all reads will be completed before the
2722 * write is issued.
2723 */
2724 tail = ACCESS_ONCE(data->user_page->data_tail);
2725 smp_rmb();
2720 offset = head = atomic_long_read(&data->head); 2726 offset = head = atomic_long_read(&data->head);
2721 head += size; 2727 head += size;
2722 if (unlikely(!perf_output_space(data, offset, head))) 2728 if (unlikely(!perf_output_space(data, tail, offset, head)))
2723 goto fail; 2729 goto fail;
2724 } while (atomic_long_cmpxchg(&data->head, offset, head) != offset); 2730 } while (atomic_long_cmpxchg(&data->head, offset, head) != offset);
2725 2731
2726 handle->offset = offset; 2732 handle->offset = offset;
2727 handle->head = head; 2733 handle->head = head;
2728 2734
2729 if ((offset >> PAGE_SHIFT) != (head >> PAGE_SHIFT)) 2735 if (head - tail > data->watermark)
2730 atomic_set(&data->wakeup, 1); 2736 atomic_set(&data->wakeup, 1);
2731 2737
2732 if (have_lost) { 2738 if (have_lost) {