aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace.c
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <srostedt@redhat.com>2013-03-06 21:45:37 -0500
committerSteven Rostedt <rostedt@goodmis.org>2013-03-15 00:35:51 -0400
commitad909e21bbe69f1d39055d346540abd827190eca (patch)
tree0bb6dc03e46ab15d3fef884029bf1c4c8b3c172a /kernel/trace/trace.c
parenta695cb5816228f86576f5f5c6809fdf8ed382ece (diff)
tracing: Add internal tracing_snapshot() functions
The new snapshot feature is quite handy. It's a way for the user to take advantage of the spare buffer that, until then, only the latency tracers used to "snapshot" the buffer when it hit a max latency. Now users can trigger a "snapshot" manually when some condition is hit in a program. But a snapshot currently can not be triggered by a condition inside the kernel. With the addition of tracing_snapshot() and tracing_snapshot_alloc(), snapshots can now be taking when a condition is hit, and the developer wants to snapshot the case without stopping the trace. Note, any snapshot will overwrite the old one, so take care in how this is done. These new functions are to be used like tracing_on(), tracing_off() and trace_printk() are. That is, they should never be called in the mainline Linux kernel. They are solely for the purpose of debugging. The tracing_snapshot() will not allocate a buffer, but it is safe to be called from any context (except NMIs). But if a snapshot buffer isn't allocated when it is called, it will write to the live buffer, complaining about the lack of a snapshot buffer, and then stop tracing (giving you the "permanent snapshot"). tracing_snapshot_alloc() will allocate the snapshot buffer if it was not already allocated and then take the snapshot. This routine *may sleep*, and must be called from context that can sleep. The allocation is done with GFP_KERNEL and not atomic. If you need a snapshot in an atomic context, say in early boot, then it is best to call the tracing_snapshot_alloc() before then, where it will allocate the buffer, and then you can use the tracing_snapshot() anywhere you want and still get snapshots. Cc: Hiraku Toyooka <hiraku.toyooka.gu@hitachi.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace/trace.c')
-rw-r--r--kernel/trace/trace.c84
1 files changed, 84 insertions, 0 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 3a89496dc99b..307524d784ec 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -339,6 +339,90 @@ void tracing_on(void)
339} 339}
340EXPORT_SYMBOL_GPL(tracing_on); 340EXPORT_SYMBOL_GPL(tracing_on);
341 341
342#ifdef CONFIG_TRACER_SNAPSHOT
343/**
344 * trace_snapshot - take a snapshot of the current buffer.
345 *
346 * This causes a swap between the snapshot buffer and the current live
347 * tracing buffer. You can use this to take snapshots of the live
348 * trace when some condition is triggered, but continue to trace.
349 *
350 * Note, make sure to allocate the snapshot with either
351 * a tracing_snapshot_alloc(), or by doing it manually
352 * with: echo 1 > /sys/kernel/debug/tracing/snapshot
353 *
354 * If the snapshot buffer is not allocated, it will stop tracing.
355 * Basically making a permanent snapshot.
356 */
357void tracing_snapshot(void)
358{
359 struct trace_array *tr = &global_trace;
360 struct tracer *tracer = tr->current_trace;
361 unsigned long flags;
362
363 if (!tr->allocated_snapshot) {
364 trace_printk("*** SNAPSHOT NOT ALLOCATED ***\n");
365 trace_printk("*** stopping trace here! ***\n");
366 tracing_off();
367 return;
368 }
369
370 /* Note, snapshot can not be used when the tracer uses it */
371 if (tracer->use_max_tr) {
372 trace_printk("*** LATENCY TRACER ACTIVE ***\n");
373 trace_printk("*** Can not use snapshot (sorry) ***\n");
374 return;
375 }
376
377 local_irq_save(flags);
378 update_max_tr(tr, current, smp_processor_id());
379 local_irq_restore(flags);
380}
381
382static int resize_buffer_duplicate_size(struct trace_buffer *trace_buf,
383 struct trace_buffer *size_buf, int cpu_id);
384
385/**
386 * trace_snapshot_alloc - allocate and take a snapshot of the current buffer.
387 *
388 * This is similar to trace_snapshot(), but it will allocate the
389 * snapshot buffer if it isn't already allocated. Use this only
390 * where it is safe to sleep, as the allocation may sleep.
391 *
392 * This causes a swap between the snapshot buffer and the current live
393 * tracing buffer. You can use this to take snapshots of the live
394 * trace when some condition is triggered, but continue to trace.
395 */
396void tracing_snapshot_alloc(void)
397{
398 struct trace_array *tr = &global_trace;
399 int ret;
400
401 if (!tr->allocated_snapshot) {
402
403 /* allocate spare buffer */
404 ret = resize_buffer_duplicate_size(&tr->max_buffer,
405 &tr->trace_buffer, RING_BUFFER_ALL_CPUS);
406 if (WARN_ON(ret < 0))
407 return;
408
409 tr->allocated_snapshot = true;
410 }
411
412 tracing_snapshot();
413}
414#else
415void tracing_snapshot(void)
416{
417 WARN_ONCE(1, "Snapshot feature not enabled, but internal snapshot used");
418}
419void tracing_snapshot_alloc(void)
420{
421 /* Give warning */
422 tracing_snapshot();
423}
424#endif /* CONFIG_TRACER_SNAPSHOT */
425
342/** 426/**
343 * tracing_off - turn off tracing buffers 427 * tracing_off - turn off tracing buffers
344 * 428 *