aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/events/ring_buffer.c
diff options
context:
space:
mode:
authorAlexander Shishkin <alexander.shishkin@linux.intel.com>2015-01-14 07:18:16 -0500
committerIngo Molnar <mingo@kernel.org>2015-04-02 11:14:13 -0400
commitfdc2670666f40ab3e03143f04d1ebf4a05e2c24a (patch)
tree6631370dbbb9a95fe3b8cd4bd62fda2e9b082daa /kernel/events/ring_buffer.c
parent68db7e98c3a6ebe7284b6cf14906ed7c55f3f7f0 (diff)
perf: Add API for PMUs to write to the AUX area
For pmus that wish to write data to ring buffer's AUX area, provide perf_aux_output_{begin,end}() calls to initiate/commit data writes, similarly to perf_output_{begin,end}. These also use the same output handle structure. Also, similarly to software counterparts, these will direct inherited events' output to parents' ring buffers. After the perf_aux_output_begin() returns successfully, handle->size is set to the maximum amount of data that can be written wrt aux_tail pointer, so that no data that the user hasn't seen will be overwritten, therefore this should always be called before hardware writing is enabled. On success, this will return the pointer to pmu driver's private structure allocated for this aux area by pmu::setup_aux. Same pointer can also be retrieved using perf_get_aux() while hardware writing is enabled. PMU driver should pass the actual amount of data written as a parameter to perf_aux_output_end(). All hardware writes should be completed and visible before this one is called. Additionally, perf_aux_output_skip() will adjust output handle and aux_head in case some part of the buffer has to be skipped over to maintain hardware's alignment constraints. Nested writers are forbidden and guards are in place to catch such attempts. Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com> Signed-off-by: Peter 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-8-git-send-email-alexander.shishkin@linux.intel.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/events/ring_buffer.c')
-rw-r--r--kernel/events/ring_buffer.c139
1 files changed, 139 insertions, 0 deletions
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
index 6e3be7a10c50..0cc7b0f39058 100644
--- a/kernel/events/ring_buffer.c
+++ b/kernel/events/ring_buffer.c
@@ -243,6 +243,145 @@ ring_buffer_init(struct ring_buffer *rb, long watermark, int flags)
243 spin_lock_init(&rb->event_lock); 243 spin_lock_init(&rb->event_lock);
244} 244}
245 245
246/*
247 * This is called before hardware starts writing to the AUX area to
248 * obtain an output handle and make sure there's room in the buffer.
249 * When the capture completes, call perf_aux_output_end() to commit
250 * the recorded data to the buffer.
251 *
252 * The ordering is similar to that of perf_output_{begin,end}, with
253 * the exception of (B), which should be taken care of by the pmu
254 * driver, since ordering rules will differ depending on hardware.
255 */
256void *perf_aux_output_begin(struct perf_output_handle *handle,
257 struct perf_event *event)
258{
259 struct perf_event *output_event = event;
260 unsigned long aux_head, aux_tail;
261 struct ring_buffer *rb;
262
263 if (output_event->parent)
264 output_event = output_event->parent;
265
266 /*
267 * Since this will typically be open across pmu::add/pmu::del, we
268 * grab ring_buffer's refcount instead of holding rcu read lock
269 * to make sure it doesn't disappear under us.
270 */
271 rb = ring_buffer_get(output_event);
272 if (!rb)
273 return NULL;
274
275 if (!rb_has_aux(rb) || !atomic_inc_not_zero(&rb->aux_refcount))
276 goto err;
277
278 /*
279 * Nesting is not supported for AUX area, make sure nested
280 * writers are caught early
281 */
282 if (WARN_ON_ONCE(local_xchg(&rb->aux_nest, 1)))
283 goto err_put;
284
285 aux_head = local_read(&rb->aux_head);
286 aux_tail = ACCESS_ONCE(rb->user_page->aux_tail);
287
288 handle->rb = rb;
289 handle->event = event;
290 handle->head = aux_head;
291 if (aux_head - aux_tail < perf_aux_size(rb))
292 handle->size = CIRC_SPACE(aux_head, aux_tail, perf_aux_size(rb));
293 else
294 handle->size = 0;
295
296 /*
297 * handle->size computation depends on aux_tail load; this forms a
298 * control dependency barrier separating aux_tail load from aux data
299 * store that will be enabled on successful return
300 */
301 if (!handle->size) { /* A, matches D */
302 event->pending_disable = 1;
303 perf_output_wakeup(handle);
304 local_set(&rb->aux_nest, 0);
305 goto err_put;
306 }
307
308 return handle->rb->aux_priv;
309
310err_put:
311 rb_free_aux(rb);
312
313err:
314 ring_buffer_put(rb);
315 handle->event = NULL;
316
317 return NULL;
318}
319
320/*
321 * Commit the data written by hardware into the ring buffer by adjusting
322 * aux_head and posting a PERF_RECORD_AUX into the perf buffer. It is the
323 * pmu driver's responsibility to observe ordering rules of the hardware,
324 * so that all the data is externally visible before this is called.
325 */
326void perf_aux_output_end(struct perf_output_handle *handle, unsigned long size,
327 bool truncated)
328{
329 struct ring_buffer *rb = handle->rb;
330 unsigned long aux_head = local_read(&rb->aux_head);
331 u64 flags = 0;
332
333 if (truncated)
334 flags |= PERF_AUX_FLAG_TRUNCATED;
335
336 local_add(size, &rb->aux_head);
337
338 if (size || flags) {
339 /*
340 * Only send RECORD_AUX if we have something useful to communicate
341 */
342
343 perf_event_aux_event(handle->event, aux_head, size, flags);
344 }
345
346 rb->user_page->aux_head = local_read(&rb->aux_head);
347
348 perf_output_wakeup(handle);
349 handle->event = NULL;
350
351 local_set(&rb->aux_nest, 0);
352 rb_free_aux(rb);
353 ring_buffer_put(rb);
354}
355
356/*
357 * Skip over a given number of bytes in the AUX buffer, due to, for example,
358 * hardware's alignment constraints.
359 */
360int perf_aux_output_skip(struct perf_output_handle *handle, unsigned long size)
361{
362 struct ring_buffer *rb = handle->rb;
363 unsigned long aux_head;
364
365 if (size > handle->size)
366 return -ENOSPC;
367
368 local_add(size, &rb->aux_head);
369
370 handle->head = aux_head;
371 handle->size -= size;
372
373 return 0;
374}
375
376void *perf_get_aux(struct perf_output_handle *handle)
377{
378 /* this is only valid between perf_aux_output_begin and *_end */
379 if (!handle->event)
380 return NULL;
381
382 return handle->rb->aux_priv;
383}
384
246#define PERF_AUX_GFP (GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN | __GFP_NORETRY) 385#define PERF_AUX_GFP (GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN | __GFP_NORETRY)
247 386
248static struct page *rb_alloc_aux_page(int node, int order) 387static struct page *rb_alloc_aux_page(int node, int order)