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:
parent
6019e59489
commit
e33c31a091
3 changed files with 206 additions and 30 deletions
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Reference in a new issue