aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2009-04-15 16:53:47 -0400
committerIngo Molnar <mingo@elte.hu>2009-04-17 11:03:28 -0400
commitd1b182a8d49ed6416325b4e0a1cb0f17cd4e702a (patch)
treef482bfba39828503f32ed994829d2d3cd6b81bfe /kernel
parente6187007d6c365b551c69ea3df46f06fd1c8bd19 (diff)
tracing/events/ring-buffer: expose format of ring buffer headers to users
Currently, every thing needed to read the binary output from the ring buffers is available, with the exception of the way the ring buffers handles itself internally. This patch creates two special files in the debugfs/tracing/events directory: # cat /debug/tracing/events/header_page field: u64 timestamp; offset:0; size:8; field: local_t commit; offset:8; size:8; field: char data; offset:16; size:4080; # cat /debug/tracing/events/header_event type : 2 bits len : 3 bits time_delta : 27 bits array : 32 bits padding : type == 0 time_extend : type == 1 data : type == 3 This is to allow a userspace app to see if the ring buffer format changes or not. [ Impact: allow userspace apps to know of ringbuffer format changes ] Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/trace/ring_buffer.c44
-rw-r--r--kernel/trace/trace_events.c38
2 files changed, 82 insertions, 0 deletions
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index f935bd5ec3e8..84a6055f37c9 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -22,6 +22,28 @@
22#include "trace.h" 22#include "trace.h"
23 23
24/* 24/*
25 * The ring buffer header is special. We must manually up keep it.
26 */
27int ring_buffer_print_entry_header(struct trace_seq *s)
28{
29 int ret;
30
31 ret = trace_seq_printf(s, "\ttype : 2 bits\n");
32 ret = trace_seq_printf(s, "\tlen : 3 bits\n");
33 ret = trace_seq_printf(s, "\ttime_delta : 27 bits\n");
34 ret = trace_seq_printf(s, "\tarray : 32 bits\n");
35 ret = trace_seq_printf(s, "\n");
36 ret = trace_seq_printf(s, "\tpadding : type == %d\n",
37 RINGBUF_TYPE_PADDING);
38 ret = trace_seq_printf(s, "\ttime_extend : type == %d\n",
39 RINGBUF_TYPE_TIME_EXTEND);
40 ret = trace_seq_printf(s, "\tdata : type == %d\n",
41 RINGBUF_TYPE_DATA);
42
43 return ret;
44}
45
46/*
25 * The ring buffer is made up of a list of pages. A separate list of pages is 47 * The ring buffer is made up of a list of pages. A separate list of pages is
26 * allocated for each CPU. A writer may only write to a buffer that is 48 * allocated for each CPU. A writer may only write to a buffer that is
27 * associated with the CPU it is currently executing on. A reader may read 49 * associated with the CPU it is currently executing on. A reader may read
@@ -340,6 +362,28 @@ static inline int test_time_stamp(u64 delta)
340 362
341#define BUF_PAGE_SIZE (PAGE_SIZE - BUF_PAGE_HDR_SIZE) 363#define BUF_PAGE_SIZE (PAGE_SIZE - BUF_PAGE_HDR_SIZE)
342 364
365int ring_buffer_print_page_header(struct trace_seq *s)
366{
367 struct buffer_data_page field;
368 int ret;
369
370 ret = trace_seq_printf(s, "\tfield: u64 timestamp;\t"
371 "offset:0;\tsize:%u;\n",
372 (unsigned int)sizeof(field.time_stamp));
373
374 ret = trace_seq_printf(s, "\tfield: local_t commit;\t"
375 "offset:%u;\tsize:%u;\n",
376 (unsigned int)offsetof(typeof(field), commit),
377 (unsigned int)sizeof(field.commit));
378
379 ret = trace_seq_printf(s, "\tfield: char data;\t"
380 "offset:%u;\tsize:%u;\n",
381 (unsigned int)offsetof(typeof(field), data),
382 (unsigned int)BUF_PAGE_SIZE);
383
384 return ret;
385}
386
343/* 387/*
344 * head_page == tail_page && head == tail then buffer is empty. 388 * head_page == tail_page && head == tail then buffer is empty.
345 */ 389 */
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index f81d6eec4e43..7163a2bb021a 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -610,6 +610,30 @@ subsystem_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
610 return cnt; 610 return cnt;
611} 611}
612 612
613static ssize_t
614show_header(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
615{
616 int (*func)(struct trace_seq *s) = filp->private_data;
617 struct trace_seq *s;
618 int r;
619
620 if (*ppos)
621 return 0;
622
623 s = kmalloc(sizeof(*s), GFP_KERNEL);
624 if (!s)
625 return -ENOMEM;
626
627 trace_seq_init(s);
628
629 func(s);
630 r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
631
632 kfree(s);
633
634 return r;
635}
636
613static const struct seq_operations show_event_seq_ops = { 637static const struct seq_operations show_event_seq_ops = {
614 .start = t_start, 638 .start = t_start,
615 .next = t_next, 639 .next = t_next,
@@ -667,6 +691,11 @@ static const struct file_operations ftrace_subsystem_filter_fops = {
667 .write = subsystem_filter_write, 691 .write = subsystem_filter_write,
668}; 692};
669 693
694static const struct file_operations ftrace_show_header_fops = {
695 .open = tracing_open_generic,
696 .read = show_header,
697};
698
670static struct dentry *event_trace_events_dir(void) 699static struct dentry *event_trace_events_dir(void)
671{ 700{
672 static struct dentry *d_tracer; 701 static struct dentry *d_tracer;
@@ -909,6 +938,15 @@ static __init int event_trace_init(void)
909 if (!d_events) 938 if (!d_events)
910 return 0; 939 return 0;
911 940
941 /* ring buffer internal formats */
942 trace_create_file("header_page", 0444, d_events,
943 ring_buffer_print_page_header,
944 &ftrace_show_header_fops);
945
946 trace_create_file("header_event", 0444, d_events,
947 ring_buffer_print_entry_header,
948 &ftrace_show_header_fops);
949
912 for_each_event(call, __start_ftrace_events, __stop_ftrace_events) { 950 for_each_event(call, __start_ftrace_events, __stop_ftrace_events) {
913 /* The linker may leave blanks */ 951 /* The linker may leave blanks */
914 if (!call->name) 952 if (!call->name)