Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7ee9aa44 authored by Jamie Gennis's avatar Jamie Gennis Committed by Dmitry Shmidt
Browse files

ANDROID: 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: default avatarJamie Gennis <jgennis@google.com>
parent 6eaff2cd
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
@@ -2102,6 +2102,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.
+13 −30
Original line number Diff line number Diff line
@@ -65,6 +65,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[] = {
@@ -88,6 +91,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 */
};

@@ -1232,6 +1237,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;
@@ -1289,13 +1297,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 */
@@ -1364,6 +1365,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;

@@ -1445,19 +1451,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",
@@ -1534,16 +1527,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_warn("Warning: could not register graph trace events\n");
		return 1;
	}

	if (!register_trace_event(&graph_trace_ret_event)) {
		pr_warn("Warning: could not register graph trace events\n");
		return 1;
	}

	return register_tracer(&graph_trace);
}

+164 −0
Original line number Diff line number Diff line
@@ -859,6 +859,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)
@@ -1301,6 +1463,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,