diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2009-09-17 13:01:10 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-09-17 16:08:26 -0400 |
commit | 2667de81f3256c944b06abdf2c56c2f192fcb724 (patch) | |
tree | d642156cfe0c52d2fb7ec1de4a2060018c8e3f8d /kernel/perf_counter.c | |
parent | 850bc73ffcc99cddfb52bc23217c60810c508853 (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.c | 32 |
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 | ||
2520 | static bool perf_output_space(struct perf_mmap_data *data, | 2527 | static 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) { |