[PATCH v5 18/20] perf: Allocate ring buffers for inherited per-task kernel events

From: Alexander Shishkin
Date: Mon Oct 13 2014 - 09:49:16 EST


Normally, per-task events can't be inherited parents' ring buffers to
avoid multiple events contending for the same buffer. And since buffer
allocation is typically done by the userspace consumer, there is no
practical interface to allocate new buffers for inherited counters.

However, for kernel users we can allocate new buffers for inherited
events as soon as they are created (and also reap them on event
destruction). This pattern has a number of use cases, such as event
sample annotation and process core dump annotation.

When a new event is inherited from a per-task kernel event that has a
ring buffer, allocate a new buffer for this event so that data from the
child task is collected and can later be retrieved for sample annotation
or core dump inclusion. This ring buffer is released when the event is
freed, for example, when the child task exits.

Signed-off-by: Alexander Shishkin <alexander.shishkin@xxxxxxxxxxxxxxx>
---
kernel/events/core.c | 9 +++++++++
kernel/events/internal.h | 11 +++++++++++
2 files changed, 20 insertions(+)

diff --git a/kernel/events/core.c b/kernel/events/core.c
index 5da1bc403f..60e354d668 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -8267,6 +8267,15 @@ inherit_event(struct perf_event *parent_event,
= parent_event->overflow_handler_context;

/*
+ * For per-task kernel events with ring buffers, set_output doesn't
+ * make sense, but we can allocate a new buffer here.
+ */
+ if (parent_event->cpu == -1 && kernel_rb_event(parent_event)) {
+ (void)rb_alloc_kernel(child_event, parent_event->rb->nr_pages,
+ parent_event->rb->aux_nr_pages);
+ }
+
+ /*
* Precalculate sample_data sizes
*/
perf_event__header_size(child_event);
diff --git a/kernel/events/internal.h b/kernel/events/internal.h
index 81cb7afec4..373ac012f5 100644
--- a/kernel/events/internal.h
+++ b/kernel/events/internal.h
@@ -122,6 +122,17 @@ static inline unsigned long perf_aux_size(struct ring_buffer *rb)
return rb->aux_nr_pages << PAGE_SHIFT;
}

+static inline bool kernel_rb_event(struct perf_event *event)
+{
+ /*
+ * Having a ring buffer and not being on any ring buffers' wakeup
+ * list means it was attached by rb_alloc_kernel() and not
+ * ring_buffer_attach(). It's the only case when these two
+ * conditions take place at the same time.
+ */
+ return event->rb && list_empty(&event->rb_entry);
+}
+
#define DEFINE_OUTPUT_COPY(func_name, memcpy_func) \
static inline unsigned long \
func_name(struct perf_output_handle *handle, \
--
2.1.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/