Skip to content

Commit

Permalink
tracing: add __print_flags for events
Browse files Browse the repository at this point in the history
Developers have been asking for the ability in the ftrace event tracer
to display names of bits in a flags variable.

Instead of printing out c2, it would be easier to read FOO|BAR|GOO,
assuming that FOO is bit 1, BAR is bit 6 and GOO is bit 7.

Some examples where this would be useful are the state flags in a context
switch, kmalloc flags, and even permision flags in accessing files.

[
  v2 changes include:

  Frederic Weisbecker's idea of using a mask instead of bits,
  thus we can output GFP_KERNEL instead of GPF_WAIT|GFP_IO|GFP_FS.

  Li Zefan's idea of allowing the caller of __print_flags to add their
  own delimiter (or no delimiter) where we can get for file permissions
  rwx instead of r|w|x.
]

[
  v3 changes:

   Christoph Hellwig's idea of using an array instead of va_args.
]

[ Impact: better displaying of flags in trace output ]

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
  • Loading branch information
Steven Rostedt authored and Frederic Weisbecker committed May 26, 2009
1 parent 0e907c9 commit be74b73
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 1 deletion.
13 changes: 12 additions & 1 deletion include/linux/ftrace_event.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,23 @@

#include <linux/trace_seq.h>
#include <linux/ring_buffer.h>

#include <linux/percpu.h>

struct trace_array;
struct tracer;
struct dentry;

DECLARE_PER_CPU(struct trace_seq, ftrace_event_seq);

struct trace_print_flags {
unsigned long mask;
const char *name;
};

const char *ftrace_print_flags_seq(struct trace_seq *p, const char *delim,
unsigned long flags,
const struct trace_print_flags *flag_array);

/*
* The trace entry - the most basic unit of tracing. This is what
* is printed in the end as a single line in the trace output, such as:
Expand Down
14 changes: 14 additions & 0 deletions include/trace/ftrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
* struct trace_seq *s = &iter->seq;
* struct ftrace_raw_<call> *field; <-- defined in stage 1
* struct trace_entry *entry;
* struct trace_seq *p;
* int ret;
*
* entry = iter->ent;
Expand All @@ -98,7 +99,9 @@
*
* field = (typeof(field))entry;
*
* p = get_cpu_var(ftrace_event_seq);
* ret = trace_seq_printf(s, <TP_printk> "\n");
* put_cpu();
* if (!ret)
* return TRACE_TYPE_PARTIAL_LINE;
*
Expand All @@ -119,6 +122,14 @@
#undef __get_str
#define __get_str(field) ((char *)__entry + __entry->__str_loc_##field)

#undef __print_flags
#define __print_flags(flag, delim, flag_array...) \
({ \
static const struct trace_print_flags flags[] = \
{ flag_array, { -1, NULL }}; \
ftrace_print_flags_seq(p, delim, flag, flags); \
})

#undef TRACE_EVENT
#define TRACE_EVENT(call, proto, args, tstruct, assign, print) \
enum print_line_t \
Expand All @@ -127,6 +138,7 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags) \
struct trace_seq *s = &iter->seq; \
struct ftrace_raw_##call *field; \
struct trace_entry *entry; \
struct trace_seq *p; \
int ret; \
\
entry = iter->ent; \
Expand All @@ -138,7 +150,9 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags) \
\
field = (typeof(field))entry; \
\
p = &get_cpu_var(ftrace_event_seq); \
ret = trace_seq_printf(s, #call ": " print); \
put_cpu(); \
if (!ret) \
return TRACE_TYPE_PARTIAL_LINE; \
\
Expand Down
39 changes: 39 additions & 0 deletions kernel/trace/trace_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
#define EVENT_HASHSIZE 128

static DECLARE_RWSEM(trace_event_mutex);

DEFINE_PER_CPU(struct trace_seq, ftrace_event_seq);

static struct hlist_head event_hash[EVENT_HASHSIZE] __read_mostly;

static int next_event_type = __TRACE_LAST_TYPE + 1;
Expand Down Expand Up @@ -212,6 +215,42 @@ int trace_seq_path(struct trace_seq *s, struct path *path)
return 0;
}

const char *
ftrace_print_flags_seq(struct trace_seq *p, const char *delim,
unsigned long flags,
const struct trace_print_flags *flag_array)
{
unsigned long mask;
const char *str;
int i;

trace_seq_init(p);

for (i = 0; flag_array[i].name && flags; i++) {

mask = flag_array[i].mask;
if ((flags & mask) != mask)
continue;

str = flag_array[i].name;
flags &= ~mask;
if (p->len && delim)
trace_seq_puts(p, delim);
trace_seq_puts(p, str);
}

/* check for left over flags */
if (flags) {
if (p->len && delim)
trace_seq_puts(p, delim);
trace_seq_printf(p, "0x%lx", flags);
}

trace_seq_putc(p, 0);

return p->buffer;
}

#ifdef CONFIG_KRETPROBES
static inline const char *kretprobed(const char *name)
{
Expand Down

0 comments on commit be74b73

Please sign in to comment.