trace: add non-hierarchical function_graph option

Add the 'funcgraph-flat' option to the function_graph tracer to use the default
trace printing format rather than the hierarchical formatting normally used.

Change-Id: If2900bfb86e6f8f51379f56da4f6fabafa630909
Signed-off-by: Jamie Gennis <jgennis@google.com>
This commit is contained in:
Jamie Gennis 2012-11-21 20:14:09 -08:00 committed by John Stultz
parent 6019e59489
commit e33c31a091
3 changed files with 206 additions and 30 deletions

View file

@ -2088,6 +2088,35 @@ will produce:
1) 1.449 us | }
You can disable the hierarchical function call formatting and instead print a
flat list of function entry and return events. This uses the format described
in the Output Formatting section and respects all the trace options that
control that formatting. Hierarchical formatting is the default.
hierachical: echo nofuncgraph-flat > trace_options
flat: echo funcgraph-flat > trace_options
ie:
# tracer: function_graph
#
# entries-in-buffer/entries-written: 68355/68355 #P:2
#
# _-----=> irqs-off
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / delay
# TASK-PID CPU# |||| TIMESTAMP FUNCTION
# | | | |||| | |
sh-1806 [001] d... 198.843443: graph_ent: func=_raw_spin_lock
sh-1806 [001] d... 198.843445: graph_ent: func=__raw_spin_lock
sh-1806 [001] d..1 198.843447: graph_ret: func=__raw_spin_lock
sh-1806 [001] d..1 198.843449: graph_ret: func=_raw_spin_lock
sh-1806 [001] d..1 198.843451: graph_ent: func=_raw_spin_unlock_irqrestore
sh-1806 [001] d... 198.843453: graph_ret: func=_raw_spin_unlock_irqrestore
You might find other useful features for this tracer in the
following "dynamic ftrace" section such as tracing only specific
functions or tasks.

View file

@ -64,6 +64,9 @@ struct fgraph_data {
#define TRACE_GRAPH_INDENT 2
/* Flag options */
#define TRACE_GRAPH_PRINT_FLAT 0x80
static unsigned int max_depth;
static struct tracer_opt trace_opts[] = {
@ -87,6 +90,8 @@ static struct tracer_opt trace_opts[] = {
{ TRACER_OPT(sleep-time, TRACE_GRAPH_SLEEP_TIME) },
/* Include time within nested functions */
{ TRACER_OPT(graph-time, TRACE_GRAPH_GRAPH_TIME) },
/* Use standard trace formatting rather than hierarchical */
{ TRACER_OPT(funcgraph-flat, TRACE_GRAPH_PRINT_FLAT) },
{ } /* Empty entry */
};
@ -1165,6 +1170,9 @@ print_graph_function_flags(struct trace_iterator *iter, u32 flags)
int cpu = iter->cpu;
int ret;
if (flags & TRACE_GRAPH_PRINT_FLAT)
return TRACE_TYPE_UNHANDLED;
if (data && per_cpu_ptr(data->cpu_data, cpu)->ignore) {
per_cpu_ptr(data->cpu_data, cpu)->ignore = 0;
return TRACE_TYPE_HANDLED;
@ -1222,13 +1230,6 @@ print_graph_function(struct trace_iterator *iter)
return print_graph_function_flags(iter, tracer_flags.val);
}
static enum print_line_t
print_graph_function_event(struct trace_iterator *iter, int flags,
struct trace_event *event)
{
return print_graph_function(iter);
}
static void print_lat_header(struct seq_file *s, u32 flags)
{
static const char spaces[] = " " /* 16 spaces */
@ -1297,6 +1298,11 @@ void print_graph_headers_flags(struct seq_file *s, u32 flags)
struct trace_iterator *iter = s->private;
struct trace_array *tr = iter->tr;
if (flags & TRACE_GRAPH_PRINT_FLAT) {
trace_default_header(s);
return;
}
if (!(tr->trace_flags & TRACE_ITER_CONTEXT_INFO))
return;
@ -1378,19 +1384,6 @@ func_graph_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
return 0;
}
static struct trace_event_functions graph_functions = {
.trace = print_graph_function_event,
};
static struct trace_event graph_trace_entry_event = {
.type = TRACE_GRAPH_ENT,
.funcs = &graph_functions,
};
static struct trace_event graph_trace_ret_event = {
.type = TRACE_GRAPH_RET,
.funcs = &graph_functions
};
static struct tracer graph_trace __tracer_data = {
.name = "function_graph",
@ -1467,16 +1460,6 @@ static __init int init_graph_trace(void)
{
max_bytes_for_cpu = snprintf(NULL, 0, "%d", nr_cpu_ids - 1);
if (!register_trace_event(&graph_trace_entry_event)) {
pr_warning("Warning: could not register graph trace events\n");
return 1;
}
if (!register_trace_event(&graph_trace_ret_event)) {
pr_warning("Warning: could not register graph trace events\n");
return 1;
}
return register_tracer(&graph_trace);
}

View file

@ -855,6 +855,168 @@ static struct trace_event trace_fn_event = {
.funcs = &trace_fn_funcs,
};
/* TRACE_GRAPH_ENT */
static enum print_line_t trace_graph_ent_trace(struct trace_iterator *iter, int flags,
struct trace_event *event)
{
struct trace_seq *s = &iter->seq;
struct ftrace_graph_ent_entry *field;
trace_assign_type(field, iter->ent);
if (!trace_seq_puts(s, "graph_ent: func="))
return TRACE_TYPE_PARTIAL_LINE;
if (!seq_print_ip_sym(s, field->graph_ent.func, flags))
return TRACE_TYPE_PARTIAL_LINE;
if (!trace_seq_puts(s, "\n"))
return TRACE_TYPE_PARTIAL_LINE;
return TRACE_TYPE_HANDLED;
}
static enum print_line_t trace_graph_ent_raw(struct trace_iterator *iter, int flags,
struct trace_event *event)
{
struct ftrace_graph_ent_entry *field;
trace_assign_type(field, iter->ent);
if (!trace_seq_printf(&iter->seq, "%lx %d\n",
field->graph_ent.func,
field->graph_ent.depth))
return TRACE_TYPE_PARTIAL_LINE;
return TRACE_TYPE_HANDLED;
}
static enum print_line_t trace_graph_ent_hex(struct trace_iterator *iter, int flags,
struct trace_event *event)
{
struct ftrace_graph_ent_entry *field;
struct trace_seq *s = &iter->seq;
trace_assign_type(field, iter->ent);
SEQ_PUT_HEX_FIELD_RET(s, field->graph_ent.func);
SEQ_PUT_HEX_FIELD_RET(s, field->graph_ent.depth);
return TRACE_TYPE_HANDLED;
}
static enum print_line_t trace_graph_ent_bin(struct trace_iterator *iter, int flags,
struct trace_event *event)
{
struct ftrace_graph_ent_entry *field;
struct trace_seq *s = &iter->seq;
trace_assign_type(field, iter->ent);
SEQ_PUT_FIELD_RET(s, field->graph_ent.func);
SEQ_PUT_FIELD_RET(s, field->graph_ent.depth);
return TRACE_TYPE_HANDLED;
}
static struct trace_event_functions trace_graph_ent_funcs = {
.trace = trace_graph_ent_trace,
.raw = trace_graph_ent_raw,
.hex = trace_graph_ent_hex,
.binary = trace_graph_ent_bin,
};
static struct trace_event trace_graph_ent_event = {
.type = TRACE_GRAPH_ENT,
.funcs = &trace_graph_ent_funcs,
};
/* TRACE_GRAPH_RET */
static enum print_line_t trace_graph_ret_trace(struct trace_iterator *iter, int flags,
struct trace_event *event)
{
struct trace_seq *s = &iter->seq;
struct trace_entry *entry = iter->ent;
struct ftrace_graph_ret_entry *field;
trace_assign_type(field, entry);
if (!trace_seq_puts(s, "graph_ret: func="))
return TRACE_TYPE_PARTIAL_LINE;
if (!seq_print_ip_sym(s, field->ret.func, flags))
return TRACE_TYPE_PARTIAL_LINE;
if (!trace_seq_puts(s, "\n"))
return TRACE_TYPE_PARTIAL_LINE;
return TRACE_TYPE_HANDLED;
}
static enum print_line_t trace_graph_ret_raw(struct trace_iterator *iter, int flags,
struct trace_event *event)
{
struct ftrace_graph_ret_entry *field;
trace_assign_type(field, iter->ent);
if (!trace_seq_printf(&iter->seq, "%lx %lld %lld %ld %d\n",
field->ret.func,
field->ret.calltime,
field->ret.rettime,
field->ret.overrun,
field->ret.depth));
return TRACE_TYPE_PARTIAL_LINE;
return TRACE_TYPE_HANDLED;
}
static enum print_line_t trace_graph_ret_hex(struct trace_iterator *iter, int flags,
struct trace_event *event)
{
struct ftrace_graph_ret_entry *field;
struct trace_seq *s = &iter->seq;
trace_assign_type(field, iter->ent);
SEQ_PUT_HEX_FIELD_RET(s, field->ret.func);
SEQ_PUT_HEX_FIELD_RET(s, field->ret.calltime);
SEQ_PUT_HEX_FIELD_RET(s, field->ret.rettime);
SEQ_PUT_HEX_FIELD_RET(s, field->ret.overrun);
SEQ_PUT_HEX_FIELD_RET(s, field->ret.depth);
return TRACE_TYPE_HANDLED;
}
static enum print_line_t trace_graph_ret_bin(struct trace_iterator *iter, int flags,
struct trace_event *event)
{
struct ftrace_graph_ret_entry *field;
struct trace_seq *s = &iter->seq;
trace_assign_type(field, iter->ent);
SEQ_PUT_FIELD_RET(s, field->ret.func);
SEQ_PUT_FIELD_RET(s, field->ret.calltime);
SEQ_PUT_FIELD_RET(s, field->ret.rettime);
SEQ_PUT_FIELD_RET(s, field->ret.overrun);
SEQ_PUT_FIELD_RET(s, field->ret.depth);
return TRACE_TYPE_HANDLED;
}
static struct trace_event_functions trace_graph_ret_funcs = {
.trace = trace_graph_ret_trace,
.raw = trace_graph_ret_raw,
.hex = trace_graph_ret_hex,
.binary = trace_graph_ret_bin,
};
static struct trace_event trace_graph_ret_event = {
.type = TRACE_GRAPH_RET,
.funcs = &trace_graph_ret_funcs,
};
/* TRACE_CTX an TRACE_WAKE */
static enum print_line_t trace_ctxwake_print(struct trace_iterator *iter,
char *delim)
@ -1232,6 +1394,8 @@ static struct trace_event trace_print_event = {
static struct trace_event *events[] __initdata = {
&trace_fn_event,
&trace_graph_ent_event,
&trace_graph_ret_event,
&trace_ctx_event,
&trace_wake_event,
&trace_stack_event,