forked from luck/tmp_suning_uos_patched
9ecda41acb
This patch introduces 'write_backward' bit to perf_event_attr, which controls the direction of a ring buffer. After set, the corresponding ring buffer is written from end to beginning. This feature is design to support reading from overwritable ring buffer. Ring buffer can be created by mapping a perf event fd. Kernel puts event records into ring buffer, user tooling like perf fetch them from address returned by mmap(). To prevent racing between kernel and tooling, they communicate to each other through 'head' and 'tail' pointers. Kernel maintains 'head' pointer, points it to the next free area (tail of the last record). Tooling maintains 'tail' pointer, points it to the tail of last consumed record (record has already been fetched). Kernel determines the available space in a ring buffer using these two pointers to avoid overwrite unfetched records. By mapping without 'PROT_WRITE', an overwritable ring buffer is created. Different from normal ring buffer, tooling is unable to maintain 'tail' pointer because writing is forbidden. Therefore, for this type of ring buffers, kernel overwrite old records unconditionally, works like flight recorder. This feature would be useful if reading from overwritable ring buffer were as easy as reading from normal ring buffer. However, there's an obscure problem. The following figure demonstrates a full overwritable ring buffer. In this figure, the 'head' pointer points to the end of last record, and a long record 'E' is pending. For a normal ring buffer, a 'tail' pointer would have pointed to position (X), so kernel knows there's no more space in the ring buffer. However, for an overwritable ring buffer, kernel ignore the 'tail' pointer. (X) head . | . V +------+-------+----------+------+---+ |A....A|B.....B|C........C|D....D| | +------+-------+----------+------+---+ Record 'A' is overwritten by event 'E': head | V +--+---+-------+----------+------+---+ |.E|..A|B.....B|C........C|D....D|E..| +--+---+-------+----------+------+---+ Now tooling decides to read from this ring buffer. However, none of these two natural positions, 'head' and the start of this ring buffer, are pointing to the head of a record. Even the full ring buffer can be accessed by tooling, it is unable to find a position to start decoding. The first attempt tries to solve this problem AFAIK can be found from [1]. It makes kernel to maintain 'tail' pointer: updates it when ring buffer is half full. However, this approach introduces overhead to fast path. Test result shows a 1% overhead [2]. In addition, this method utilizes no more tham 50% records. Another attempt can be found from [3], which allows putting the size of an event at the end of each record. This approach allows tooling to find records in a backward manner from 'head' pointer by reading size of a record from its tail. However, because of alignment requirement, it needs 8 bytes to record the size of a record, which is a huge waste. Its performance is also not good, because more data need to be written. This approach also introduces some extra branch instructions to fast path. 'write_backward' is a better solution to this problem. Following figure demonstrates the state of the overwritable ring buffer when 'write_backward' is set before overwriting: head | V +---+------+----------+-------+------+ | |D....D|C........C|B.....B|A....A| +---+------+----------+-------+------+ and after overwriting: head | V +---+------+----------+-------+---+--+ |..E|D....D|C........C|B.....B|A..|E.| +---+------+----------+-------+---+--+ In each situation, 'head' points to the beginning of the newest record. From this record, tooling can iterate over the full ring buffer and fetch records one by one. The only limitation that needs to be considered is back-to-back reading. Due to the non-deterministic of user programs, it is impossible to ensure the ring buffer keeps stable during reading. Consider an extreme situation: tooling is scheduled out after reading record 'D', then a burst of events come, eat up the whole ring buffer (one or multiple rounds). When the tooling process comes back, reading after 'D' is incorrect now. To prevent this problem, we need to find a way to ensure the ring buffer is stable during reading. ioctl(PERF_EVENT_IOC_PAUSE_OUTPUT) is suggested because its overhead is lower than ioctl(PERF_EVENT_IOC_ENABLE). By carefully verifying 'header' pointer, reader can avoid pausing the ring-buffer. For example: /* A union of all possible events */ union perf_event event; p = head = perf_mmap__read_head(); while (true) { /* copy header of next event */ fetch(&event.header, p, sizeof(event.header)); /* read 'head' pointer */ head = perf_mmap__read_head(); /* check overwritten: is the header good? */ if (!verify(sizeof(event.header), p, head)) break; /* copy the whole event */ fetch(&event, p, event.header.size); /* read 'head' pointer again */ head = perf_mmap__read_head(); /* is the whole event good? */ if (!verify(event.header.size, p, head)) break; p += event.header.size; } However, the overhead is high because: a) In-place decoding is not safe. Copying-verifying-decoding is required. b) Fetching 'head' pointer requires additional synchronization. (From Alexei Starovoitov: Even when this trick works, pause is needed for more than stability of reading. When we collect the events into overwrite buffer we're waiting for some other trigger (like all cpu utilization spike or just one cpu running and all others are idle) and when it happens the buffer has valuable info from the past. At this point new events are no longer interesting and buffer should be paused, events read and unpaused until next trigger comes.) This patch utilizes event's default overflow_handler introduced previously. perf_event_output_backward() is created as the default overflow handler for backward ring buffers. To avoid extra overhead to fast path, original perf_event_output() becomes __perf_event_output() and marked '__always_inline'. In theory, there's no extra overhead introduced to fast path. Performance testing: Calling 3000000 times of 'close(-1)', use gettimeofday() to check duration. Use 'perf record -o /dev/null -e raw_syscalls:*' to capture system calls. In ns. Testing environment: CPU : Intel(R) Core(TM) i7-4790 CPU @ 3.60GHz Kernel : v4.5.0 MEAN STDVAR BASE 800214.950 2853.083 PRE1 2253846.700 9997.014 PRE2 2257495.540 8516.293 POST 2250896.100 8933.921 Where 'BASE' is pure performance without capturing. 'PRE1' is test result of pure 'v4.5.0' kernel. 'PRE2' is test result before this patch. 'POST' is test result after this patch. See [4] for the detailed experimental setup. Considering the stdvar, this patch doesn't introduce performance overhead to the fast path. [1] http://lkml.iu.edu/hypermail/linux/kernel/1304.1/04584.html [2] http://lkml.iu.edu/hypermail/linux/kernel/1307.1/00535.html [3] http://lkml.iu.edu/hypermail/linux/kernel/1512.0/01265.html [4] http://lkml.kernel.org/g/56F89DCD.1040202@huawei.com Signed-off-by: Wang Nan <wangnan0@huawei.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Acked-by: Alexei Starovoitov <ast@kernel.org> Cc: <acme@kernel.org> Cc: <pi3orama@163.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Brendan Gregg <brendan.d.gregg@gmail.com> Cc: He Kuang <hekuang@huawei.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Vince Weaver <vincent.weaver@maine.edu> Cc: Zefan Li <lizefan@huawei.com> Link: http://lkml.kernel.org/r/1459865478-53413-1-git-send-email-wangnan0@huawei.com [ Fixed the changelog some more. ] Signed-off-by: Ingo Molnar <mingo@kernel.org> Signed-off-by: Ingo Molnar <mingo@kernel.org>
838 lines
20 KiB
C
838 lines
20 KiB
C
/*
|
|
* Performance events ring-buffer code:
|
|
*
|
|
* Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de>
|
|
* Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar
|
|
* Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra
|
|
* Copyright © 2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
|
|
*
|
|
* For licensing details see kernel-base/COPYING
|
|
*/
|
|
|
|
#include <linux/perf_event.h>
|
|
#include <linux/vmalloc.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/circ_buf.h>
|
|
#include <linux/poll.h>
|
|
|
|
#include "internal.h"
|
|
|
|
static void perf_output_wakeup(struct perf_output_handle *handle)
|
|
{
|
|
atomic_set(&handle->rb->poll, POLLIN);
|
|
|
|
handle->event->pending_wakeup = 1;
|
|
irq_work_queue(&handle->event->pending);
|
|
}
|
|
|
|
/*
|
|
* We need to ensure a later event_id doesn't publish a head when a former
|
|
* event isn't done writing. However since we need to deal with NMIs we
|
|
* cannot fully serialize things.
|
|
*
|
|
* We only publish the head (and generate a wakeup) when the outer-most
|
|
* event completes.
|
|
*/
|
|
static void perf_output_get_handle(struct perf_output_handle *handle)
|
|
{
|
|
struct ring_buffer *rb = handle->rb;
|
|
|
|
preempt_disable();
|
|
local_inc(&rb->nest);
|
|
handle->wakeup = local_read(&rb->wakeup);
|
|
}
|
|
|
|
static void perf_output_put_handle(struct perf_output_handle *handle)
|
|
{
|
|
struct ring_buffer *rb = handle->rb;
|
|
unsigned long head;
|
|
|
|
again:
|
|
head = local_read(&rb->head);
|
|
|
|
/*
|
|
* IRQ/NMI can happen here, which means we can miss a head update.
|
|
*/
|
|
|
|
if (!local_dec_and_test(&rb->nest))
|
|
goto out;
|
|
|
|
/*
|
|
* Since the mmap() consumer (userspace) can run on a different CPU:
|
|
*
|
|
* kernel user
|
|
*
|
|
* if (LOAD ->data_tail) { LOAD ->data_head
|
|
* (A) smp_rmb() (C)
|
|
* STORE $data LOAD $data
|
|
* smp_wmb() (B) smp_mb() (D)
|
|
* STORE ->data_head STORE ->data_tail
|
|
* }
|
|
*
|
|
* Where A pairs with D, and B pairs with C.
|
|
*
|
|
* In our case (A) is a control dependency that separates the load of
|
|
* the ->data_tail and the stores of $data. In case ->data_tail
|
|
* indicates there is no room in the buffer to store $data we do not.
|
|
*
|
|
* D needs to be a full barrier since it separates the data READ
|
|
* from the tail WRITE.
|
|
*
|
|
* For B a WMB is sufficient since it separates two WRITEs, and for C
|
|
* an RMB is sufficient since it separates two READs.
|
|
*
|
|
* See perf_output_begin().
|
|
*/
|
|
smp_wmb(); /* B, matches C */
|
|
rb->user_page->data_head = head;
|
|
|
|
/*
|
|
* Now check if we missed an update -- rely on previous implied
|
|
* compiler barriers to force a re-read.
|
|
*/
|
|
if (unlikely(head != local_read(&rb->head))) {
|
|
local_inc(&rb->nest);
|
|
goto again;
|
|
}
|
|
|
|
if (handle->wakeup != local_read(&rb->wakeup))
|
|
perf_output_wakeup(handle);
|
|
|
|
out:
|
|
preempt_enable();
|
|
}
|
|
|
|
static bool __always_inline
|
|
ring_buffer_has_space(unsigned long head, unsigned long tail,
|
|
unsigned long data_size, unsigned int size,
|
|
bool backward)
|
|
{
|
|
if (!backward)
|
|
return CIRC_SPACE(head, tail, data_size) >= size;
|
|
else
|
|
return CIRC_SPACE(tail, head, data_size) >= size;
|
|
}
|
|
|
|
static int __always_inline
|
|
__perf_output_begin(struct perf_output_handle *handle,
|
|
struct perf_event *event, unsigned int size,
|
|
bool backward)
|
|
{
|
|
struct ring_buffer *rb;
|
|
unsigned long tail, offset, head;
|
|
int have_lost, page_shift;
|
|
struct {
|
|
struct perf_event_header header;
|
|
u64 id;
|
|
u64 lost;
|
|
} lost_event;
|
|
|
|
rcu_read_lock();
|
|
/*
|
|
* For inherited events we send all the output towards the parent.
|
|
*/
|
|
if (event->parent)
|
|
event = event->parent;
|
|
|
|
rb = rcu_dereference(event->rb);
|
|
if (unlikely(!rb))
|
|
goto out;
|
|
|
|
if (unlikely(rb->paused)) {
|
|
if (rb->nr_pages)
|
|
local_inc(&rb->lost);
|
|
goto out;
|
|
}
|
|
|
|
handle->rb = rb;
|
|
handle->event = event;
|
|
|
|
have_lost = local_read(&rb->lost);
|
|
if (unlikely(have_lost)) {
|
|
size += sizeof(lost_event);
|
|
if (event->attr.sample_id_all)
|
|
size += event->id_header_size;
|
|
}
|
|
|
|
perf_output_get_handle(handle);
|
|
|
|
do {
|
|
tail = READ_ONCE(rb->user_page->data_tail);
|
|
offset = head = local_read(&rb->head);
|
|
if (!rb->overwrite) {
|
|
if (unlikely(!ring_buffer_has_space(head, tail,
|
|
perf_data_size(rb),
|
|
size, backward)))
|
|
goto fail;
|
|
}
|
|
|
|
/*
|
|
* The above forms a control dependency barrier separating the
|
|
* @tail load above from the data stores below. Since the @tail
|
|
* load is required to compute the branch to fail below.
|
|
*
|
|
* A, matches D; the full memory barrier userspace SHOULD issue
|
|
* after reading the data and before storing the new tail
|
|
* position.
|
|
*
|
|
* See perf_output_put_handle().
|
|
*/
|
|
|
|
if (!backward)
|
|
head += size;
|
|
else
|
|
head -= size;
|
|
} while (local_cmpxchg(&rb->head, offset, head) != offset);
|
|
|
|
if (backward) {
|
|
offset = head;
|
|
head = (u64)(-head);
|
|
}
|
|
|
|
/*
|
|
* We rely on the implied barrier() by local_cmpxchg() to ensure
|
|
* none of the data stores below can be lifted up by the compiler.
|
|
*/
|
|
|
|
if (unlikely(head - local_read(&rb->wakeup) > rb->watermark))
|
|
local_add(rb->watermark, &rb->wakeup);
|
|
|
|
page_shift = PAGE_SHIFT + page_order(rb);
|
|
|
|
handle->page = (offset >> page_shift) & (rb->nr_pages - 1);
|
|
offset &= (1UL << page_shift) - 1;
|
|
handle->addr = rb->data_pages[handle->page] + offset;
|
|
handle->size = (1UL << page_shift) - offset;
|
|
|
|
if (unlikely(have_lost)) {
|
|
struct perf_sample_data sample_data;
|
|
|
|
lost_event.header.size = sizeof(lost_event);
|
|
lost_event.header.type = PERF_RECORD_LOST;
|
|
lost_event.header.misc = 0;
|
|
lost_event.id = event->id;
|
|
lost_event.lost = local_xchg(&rb->lost, 0);
|
|
|
|
perf_event_header__init_id(&lost_event.header,
|
|
&sample_data, event);
|
|
perf_output_put(handle, lost_event);
|
|
perf_event__output_id_sample(event, handle, &sample_data);
|
|
}
|
|
|
|
return 0;
|
|
|
|
fail:
|
|
local_inc(&rb->lost);
|
|
perf_output_put_handle(handle);
|
|
out:
|
|
rcu_read_unlock();
|
|
|
|
return -ENOSPC;
|
|
}
|
|
|
|
int perf_output_begin_forward(struct perf_output_handle *handle,
|
|
struct perf_event *event, unsigned int size)
|
|
{
|
|
return __perf_output_begin(handle, event, size, false);
|
|
}
|
|
|
|
int perf_output_begin_backward(struct perf_output_handle *handle,
|
|
struct perf_event *event, unsigned int size)
|
|
{
|
|
return __perf_output_begin(handle, event, size, true);
|
|
}
|
|
|
|
int perf_output_begin(struct perf_output_handle *handle,
|
|
struct perf_event *event, unsigned int size)
|
|
{
|
|
|
|
return __perf_output_begin(handle, event, size,
|
|
unlikely(is_write_backward(event)));
|
|
}
|
|
|
|
unsigned int perf_output_copy(struct perf_output_handle *handle,
|
|
const void *buf, unsigned int len)
|
|
{
|
|
return __output_copy(handle, buf, len);
|
|
}
|
|
|
|
unsigned int perf_output_skip(struct perf_output_handle *handle,
|
|
unsigned int len)
|
|
{
|
|
return __output_skip(handle, NULL, len);
|
|
}
|
|
|
|
void perf_output_end(struct perf_output_handle *handle)
|
|
{
|
|
perf_output_put_handle(handle);
|
|
rcu_read_unlock();
|
|
}
|
|
|
|
static void
|
|
ring_buffer_init(struct ring_buffer *rb, long watermark, int flags)
|
|
{
|
|
long max_size = perf_data_size(rb);
|
|
|
|
if (watermark)
|
|
rb->watermark = min(max_size, watermark);
|
|
|
|
if (!rb->watermark)
|
|
rb->watermark = max_size / 2;
|
|
|
|
if (flags & RING_BUFFER_WRITABLE)
|
|
rb->overwrite = 0;
|
|
else
|
|
rb->overwrite = 1;
|
|
|
|
atomic_set(&rb->refcount, 1);
|
|
|
|
INIT_LIST_HEAD(&rb->event_list);
|
|
spin_lock_init(&rb->event_lock);
|
|
|
|
/*
|
|
* perf_output_begin() only checks rb->paused, therefore
|
|
* rb->paused must be true if we have no pages for output.
|
|
*/
|
|
if (!rb->nr_pages)
|
|
rb->paused = 1;
|
|
}
|
|
|
|
/*
|
|
* This is called before hardware starts writing to the AUX area to
|
|
* obtain an output handle and make sure there's room in the buffer.
|
|
* When the capture completes, call perf_aux_output_end() to commit
|
|
* the recorded data to the buffer.
|
|
*
|
|
* The ordering is similar to that of perf_output_{begin,end}, with
|
|
* the exception of (B), which should be taken care of by the pmu
|
|
* driver, since ordering rules will differ depending on hardware.
|
|
*
|
|
* Call this from pmu::start(); see the comment in perf_aux_output_end()
|
|
* about its use in pmu callbacks. Both can also be called from the PMI
|
|
* handler if needed.
|
|
*/
|
|
void *perf_aux_output_begin(struct perf_output_handle *handle,
|
|
struct perf_event *event)
|
|
{
|
|
struct perf_event *output_event = event;
|
|
unsigned long aux_head, aux_tail;
|
|
struct ring_buffer *rb;
|
|
|
|
if (output_event->parent)
|
|
output_event = output_event->parent;
|
|
|
|
/*
|
|
* Since this will typically be open across pmu::add/pmu::del, we
|
|
* grab ring_buffer's refcount instead of holding rcu read lock
|
|
* to make sure it doesn't disappear under us.
|
|
*/
|
|
rb = ring_buffer_get(output_event);
|
|
if (!rb)
|
|
return NULL;
|
|
|
|
if (!rb_has_aux(rb) || !atomic_inc_not_zero(&rb->aux_refcount))
|
|
goto err;
|
|
|
|
/*
|
|
* If rb::aux_mmap_count is zero (and rb_has_aux() above went through),
|
|
* the aux buffer is in perf_mmap_close(), about to get freed.
|
|
*/
|
|
if (!atomic_read(&rb->aux_mmap_count))
|
|
goto err_put;
|
|
|
|
/*
|
|
* Nesting is not supported for AUX area, make sure nested
|
|
* writers are caught early
|
|
*/
|
|
if (WARN_ON_ONCE(local_xchg(&rb->aux_nest, 1)))
|
|
goto err_put;
|
|
|
|
aux_head = local_read(&rb->aux_head);
|
|
|
|
handle->rb = rb;
|
|
handle->event = event;
|
|
handle->head = aux_head;
|
|
handle->size = 0;
|
|
|
|
/*
|
|
* In overwrite mode, AUX data stores do not depend on aux_tail,
|
|
* therefore (A) control dependency barrier does not exist. The
|
|
* (B) <-> (C) ordering is still observed by the pmu driver.
|
|
*/
|
|
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));
|
|
|
|
/*
|
|
* handle->size computation depends on aux_tail load; this forms a
|
|
* control dependency barrier separating aux_tail load from aux data
|
|
* store that will be enabled on successful return
|
|
*/
|
|
if (!handle->size) { /* A, matches D */
|
|
event->pending_disable = 1;
|
|
perf_output_wakeup(handle);
|
|
local_set(&rb->aux_nest, 0);
|
|
goto err_put;
|
|
}
|
|
}
|
|
|
|
return handle->rb->aux_priv;
|
|
|
|
err_put:
|
|
/* can't be last */
|
|
rb_free_aux(rb);
|
|
|
|
err:
|
|
ring_buffer_put(rb);
|
|
handle->event = NULL;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Commit the data written by hardware into the ring buffer by adjusting
|
|
* aux_head and posting a PERF_RECORD_AUX into the perf buffer. It is the
|
|
* pmu driver's responsibility to observe ordering rules of the hardware,
|
|
* so that all the data is externally visible before this is called.
|
|
*
|
|
* Note: this has to be called from pmu::stop() callback, as the assumption
|
|
* of the AUX buffer management code is that after pmu::stop(), the AUX
|
|
* transaction must be stopped and therefore drop the AUX reference count.
|
|
*/
|
|
void perf_aux_output_end(struct perf_output_handle *handle, unsigned long size,
|
|
bool truncated)
|
|
{
|
|
struct ring_buffer *rb = handle->rb;
|
|
unsigned long aux_head;
|
|
u64 flags = 0;
|
|
|
|
if (truncated)
|
|
flags |= PERF_AUX_FLAG_TRUNCATED;
|
|
|
|
/* in overwrite mode, driver provides aux_head via handle */
|
|
if (rb->aux_overwrite) {
|
|
flags |= PERF_AUX_FLAG_OVERWRITE;
|
|
|
|
aux_head = handle->head;
|
|
local_set(&rb->aux_head, aux_head);
|
|
} else {
|
|
aux_head = local_read(&rb->aux_head);
|
|
local_add(size, &rb->aux_head);
|
|
}
|
|
|
|
if (size || flags) {
|
|
/*
|
|
* Only send RECORD_AUX if we have something useful to communicate
|
|
*/
|
|
|
|
perf_event_aux_event(handle->event, aux_head, size, flags);
|
|
}
|
|
|
|
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->event = NULL;
|
|
|
|
local_set(&rb->aux_nest, 0);
|
|
/* can't be last */
|
|
rb_free_aux(rb);
|
|
ring_buffer_put(rb);
|
|
}
|
|
|
|
/*
|
|
* Skip over a given number of bytes in the AUX buffer, due to, for example,
|
|
* hardware's alignment constraints.
|
|
*/
|
|
int perf_aux_output_skip(struct perf_output_handle *handle, unsigned long size)
|
|
{
|
|
struct ring_buffer *rb = handle->rb;
|
|
unsigned long aux_head;
|
|
|
|
if (size > handle->size)
|
|
return -ENOSPC;
|
|
|
|
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;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void *perf_get_aux(struct perf_output_handle *handle)
|
|
{
|
|
/* this is only valid between perf_aux_output_begin and *_end */
|
|
if (!handle->event)
|
|
return NULL;
|
|
|
|
return handle->rb->aux_priv;
|
|
}
|
|
|
|
#define PERF_AUX_GFP (GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN | __GFP_NORETRY)
|
|
|
|
static struct page *rb_alloc_aux_page(int node, int order)
|
|
{
|
|
struct page *page;
|
|
|
|
if (order > MAX_ORDER)
|
|
order = MAX_ORDER;
|
|
|
|
do {
|
|
page = alloc_pages_node(node, PERF_AUX_GFP, order);
|
|
} while (!page && order--);
|
|
|
|
if (page && order) {
|
|
/*
|
|
* Communicate the allocation size to the driver:
|
|
* if we managed to secure a high-order allocation,
|
|
* set its first page's private to this order;
|
|
* !PagePrivate(page) means it's just a normal page.
|
|
*/
|
|
split_page(page, order);
|
|
SetPagePrivate(page);
|
|
set_page_private(page, order);
|
|
}
|
|
|
|
return page;
|
|
}
|
|
|
|
static void rb_free_aux_page(struct ring_buffer *rb, int idx)
|
|
{
|
|
struct page *page = virt_to_page(rb->aux_pages[idx]);
|
|
|
|
ClearPagePrivate(page);
|
|
page->mapping = NULL;
|
|
__free_page(page);
|
|
}
|
|
|
|
static void __rb_free_aux(struct ring_buffer *rb)
|
|
{
|
|
int pg;
|
|
|
|
/*
|
|
* Should never happen, the last reference should be dropped from
|
|
* perf_mmap_close() path, which first stops aux transactions (which
|
|
* in turn are the atomic holders of aux_refcount) and then does the
|
|
* last rb_free_aux().
|
|
*/
|
|
WARN_ON_ONCE(in_atomic());
|
|
|
|
if (rb->aux_priv) {
|
|
rb->free_aux(rb->aux_priv);
|
|
rb->free_aux = NULL;
|
|
rb->aux_priv = NULL;
|
|
}
|
|
|
|
if (rb->aux_nr_pages) {
|
|
for (pg = 0; pg < rb->aux_nr_pages; pg++)
|
|
rb_free_aux_page(rb, pg);
|
|
|
|
kfree(rb->aux_pages);
|
|
rb->aux_nr_pages = 0;
|
|
}
|
|
}
|
|
|
|
int rb_alloc_aux(struct ring_buffer *rb, struct perf_event *event,
|
|
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);
|
|
int ret = -ENOMEM, max_order = 0;
|
|
|
|
if (!has_aux(event))
|
|
return -ENOTSUPP;
|
|
|
|
if (event->pmu->capabilities & PERF_PMU_CAP_AUX_NO_SG) {
|
|
/*
|
|
* We need to start with the max_order that fits in nr_pages,
|
|
* not the other way around, hence ilog2() and not get_order.
|
|
*/
|
|
max_order = ilog2(nr_pages);
|
|
|
|
/*
|
|
* PMU requests more than one contiguous chunks of memory
|
|
* for SW double buffering
|
|
*/
|
|
if ((event->pmu->capabilities & PERF_PMU_CAP_AUX_SW_DOUBLEBUF) &&
|
|
!overwrite) {
|
|
if (!max_order)
|
|
return -EINVAL;
|
|
|
|
max_order--;
|
|
}
|
|
}
|
|
|
|
rb->aux_pages = kzalloc_node(nr_pages * sizeof(void *), GFP_KERNEL, node);
|
|
if (!rb->aux_pages)
|
|
return -ENOMEM;
|
|
|
|
rb->free_aux = event->pmu->free_aux;
|
|
for (rb->aux_nr_pages = 0; rb->aux_nr_pages < nr_pages;) {
|
|
struct page *page;
|
|
int last, order;
|
|
|
|
order = min(max_order, ilog2(nr_pages - rb->aux_nr_pages));
|
|
page = rb_alloc_aux_page(node, order);
|
|
if (!page)
|
|
goto out;
|
|
|
|
for (last = rb->aux_nr_pages + (1 << page_private(page));
|
|
last > rb->aux_nr_pages; rb->aux_nr_pages++)
|
|
rb->aux_pages[rb->aux_nr_pages] = page_address(page++);
|
|
}
|
|
|
|
/*
|
|
* In overwrite mode, PMUs that don't support SG may not handle more
|
|
* than one contiguous allocation, since they rely on PMI to do double
|
|
* buffering. In this case, the entire buffer has to be one contiguous
|
|
* chunk.
|
|
*/
|
|
if ((event->pmu->capabilities & PERF_PMU_CAP_AUX_NO_SG) &&
|
|
overwrite) {
|
|
struct page *page = virt_to_page(rb->aux_pages[0]);
|
|
|
|
if (page_private(page) != max_order)
|
|
goto out;
|
|
}
|
|
|
|
rb->aux_priv = event->pmu->setup_aux(event->cpu, rb->aux_pages, nr_pages,
|
|
overwrite);
|
|
if (!rb->aux_priv)
|
|
goto out;
|
|
|
|
ret = 0;
|
|
|
|
/*
|
|
* aux_pages (and pmu driver's private data, aux_priv) will be
|
|
* referenced in both producer's and consumer's contexts, thus
|
|
* we keep a refcount here to make sure either of the two can
|
|
* reference them safely.
|
|
*/
|
|
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)
|
|
rb->aux_pgoff = pgoff;
|
|
else
|
|
__rb_free_aux(rb);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void rb_free_aux(struct ring_buffer *rb)
|
|
{
|
|
if (atomic_dec_and_test(&rb->aux_refcount))
|
|
__rb_free_aux(rb);
|
|
}
|
|
|
|
#ifndef CONFIG_PERF_USE_VMALLOC
|
|
|
|
/*
|
|
* Back perf_mmap() with regular GFP_KERNEL-0 pages.
|
|
*/
|
|
|
|
static struct page *
|
|
__perf_mmap_to_page(struct ring_buffer *rb, unsigned long pgoff)
|
|
{
|
|
if (pgoff > rb->nr_pages)
|
|
return NULL;
|
|
|
|
if (pgoff == 0)
|
|
return virt_to_page(rb->user_page);
|
|
|
|
return virt_to_page(rb->data_pages[pgoff - 1]);
|
|
}
|
|
|
|
static void *perf_mmap_alloc_page(int cpu)
|
|
{
|
|
struct page *page;
|
|
int node;
|
|
|
|
node = (cpu == -1) ? cpu : cpu_to_node(cpu);
|
|
page = alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0);
|
|
if (!page)
|
|
return NULL;
|
|
|
|
return page_address(page);
|
|
}
|
|
|
|
struct ring_buffer *rb_alloc(int nr_pages, long watermark, int cpu, int flags)
|
|
{
|
|
struct ring_buffer *rb;
|
|
unsigned long size;
|
|
int i;
|
|
|
|
size = sizeof(struct ring_buffer);
|
|
size += nr_pages * sizeof(void *);
|
|
|
|
rb = kzalloc(size, GFP_KERNEL);
|
|
if (!rb)
|
|
goto fail;
|
|
|
|
rb->user_page = perf_mmap_alloc_page(cpu);
|
|
if (!rb->user_page)
|
|
goto fail_user_page;
|
|
|
|
for (i = 0; i < nr_pages; i++) {
|
|
rb->data_pages[i] = perf_mmap_alloc_page(cpu);
|
|
if (!rb->data_pages[i])
|
|
goto fail_data_pages;
|
|
}
|
|
|
|
rb->nr_pages = nr_pages;
|
|
|
|
ring_buffer_init(rb, watermark, flags);
|
|
|
|
return rb;
|
|
|
|
fail_data_pages:
|
|
for (i--; i >= 0; i--)
|
|
free_page((unsigned long)rb->data_pages[i]);
|
|
|
|
free_page((unsigned long)rb->user_page);
|
|
|
|
fail_user_page:
|
|
kfree(rb);
|
|
|
|
fail:
|
|
return NULL;
|
|
}
|
|
|
|
static void perf_mmap_free_page(unsigned long addr)
|
|
{
|
|
struct page *page = virt_to_page((void *)addr);
|
|
|
|
page->mapping = NULL;
|
|
__free_page(page);
|
|
}
|
|
|
|
void rb_free(struct ring_buffer *rb)
|
|
{
|
|
int i;
|
|
|
|
perf_mmap_free_page((unsigned long)rb->user_page);
|
|
for (i = 0; i < rb->nr_pages; i++)
|
|
perf_mmap_free_page((unsigned long)rb->data_pages[i]);
|
|
kfree(rb);
|
|
}
|
|
|
|
#else
|
|
static int data_page_nr(struct ring_buffer *rb)
|
|
{
|
|
return rb->nr_pages << page_order(rb);
|
|
}
|
|
|
|
static struct page *
|
|
__perf_mmap_to_page(struct ring_buffer *rb, unsigned long pgoff)
|
|
{
|
|
/* The '>' counts in the user page. */
|
|
if (pgoff > data_page_nr(rb))
|
|
return NULL;
|
|
|
|
return vmalloc_to_page((void *)rb->user_page + pgoff * PAGE_SIZE);
|
|
}
|
|
|
|
static void perf_mmap_unmark_page(void *addr)
|
|
{
|
|
struct page *page = vmalloc_to_page(addr);
|
|
|
|
page->mapping = NULL;
|
|
}
|
|
|
|
static void rb_free_work(struct work_struct *work)
|
|
{
|
|
struct ring_buffer *rb;
|
|
void *base;
|
|
int i, nr;
|
|
|
|
rb = container_of(work, struct ring_buffer, work);
|
|
nr = data_page_nr(rb);
|
|
|
|
base = rb->user_page;
|
|
/* The '<=' counts in the user page. */
|
|
for (i = 0; i <= nr; i++)
|
|
perf_mmap_unmark_page(base + (i * PAGE_SIZE));
|
|
|
|
vfree(base);
|
|
kfree(rb);
|
|
}
|
|
|
|
void rb_free(struct ring_buffer *rb)
|
|
{
|
|
schedule_work(&rb->work);
|
|
}
|
|
|
|
struct ring_buffer *rb_alloc(int nr_pages, long watermark, int cpu, int flags)
|
|
{
|
|
struct ring_buffer *rb;
|
|
unsigned long size;
|
|
void *all_buf;
|
|
|
|
size = sizeof(struct ring_buffer);
|
|
size += sizeof(void *);
|
|
|
|
rb = kzalloc(size, GFP_KERNEL);
|
|
if (!rb)
|
|
goto fail;
|
|
|
|
INIT_WORK(&rb->work, rb_free_work);
|
|
|
|
all_buf = vmalloc_user((nr_pages + 1) * PAGE_SIZE);
|
|
if (!all_buf)
|
|
goto fail_all_buf;
|
|
|
|
rb->user_page = all_buf;
|
|
rb->data_pages[0] = all_buf + PAGE_SIZE;
|
|
if (nr_pages) {
|
|
rb->nr_pages = 1;
|
|
rb->page_order = ilog2(nr_pages);
|
|
}
|
|
|
|
ring_buffer_init(rb, watermark, flags);
|
|
|
|
return rb;
|
|
|
|
fail_all_buf:
|
|
kfree(rb);
|
|
|
|
fail:
|
|
return NULL;
|
|
}
|
|
|
|
#endif
|
|
|
|
struct page *
|
|
perf_mmap_to_page(struct ring_buffer *rb, unsigned long pgoff)
|
|
{
|
|
if (rb->aux_nr_pages) {
|
|
/* above AUX space */
|
|
if (pgoff > rb->aux_pgoff + rb->aux_nr_pages)
|
|
return NULL;
|
|
|
|
/* AUX space */
|
|
if (pgoff >= rb->aux_pgoff)
|
|
return virt_to_page(rb->aux_pages[pgoff - rb->aux_pgoff]);
|
|
}
|
|
|
|
return __perf_mmap_to_page(rb, pgoff);
|
|
}
|