Commit 49ff5903 authored by Steven Rostedt's avatar Steven Rostedt Committed by Steven Rostedt

tracing: add latency format to function_graph tracer

While debugging something with the function_graph tracer, I found the
need to see the preempt count of the traces. Unfortunately, since
the function graph tracer has its own output formatting, it does not
honor the latency-format option.

This patch makes the function_graph tracer honor the latency-format
option, but still keeps control of the output. But now we have the
same details that the latency-format supplies.

 # tracer: function_graph
 #
 #      _-----=> irqs-off
 #     / _----=> need-resched
 #    | / _---=> hardirq/softirq
 #    || / _--=> preempt-depth
 #    ||| /
 #    ||||
 # CPU||||  DURATION                  FUNCTION CALLS
 # |  ||||   |   |                     |   |   |   |
  3)  d..1  1.333 us    |        idle_cpu();
  3)  d.h1              |        tick_check_idle() {
  3)  d.h1  0.550 us    |          tick_check_oneshot_broadcast();
  3)  d.h1              |          tick_nohz_stop_idle() {
  3)  d.h1              |            ktime_get() {
  3)  d.h1              |              ktime_get_ts() {
Signed-off-by: default avatarSteven Rostedt <rostedt@goodmis.org>
parent fc06b852
...@@ -364,6 +364,29 @@ print_graph_proc(struct trace_seq *s, pid_t pid) ...@@ -364,6 +364,29 @@ print_graph_proc(struct trace_seq *s, pid_t pid)
} }
static enum print_line_t
print_graph_lat_fmt(struct trace_seq *s, struct trace_entry *entry)
{
int hardirq, softirq;
hardirq = entry->flags & TRACE_FLAG_HARDIRQ;
softirq = entry->flags & TRACE_FLAG_SOFTIRQ;
if (!trace_seq_printf(s, " %c%c%c",
(entry->flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
(entry->flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
'X' : '.',
(entry->flags & TRACE_FLAG_NEED_RESCHED) ?
'N' : '.',
(hardirq && softirq) ? 'H' :
hardirq ? 'h' : softirq ? 's' : '.'))
return 0;
if (entry->preempt_count)
return trace_seq_printf(s, "%x", entry->preempt_count);
return trace_seq_puts(s, ".");
}
/* If the pid changed since the last trace, output this event */ /* If the pid changed since the last trace, output this event */
static enum print_line_t static enum print_line_t
verif_pid(struct trace_seq *s, pid_t pid, int cpu, struct fgraph_data *data) verif_pid(struct trace_seq *s, pid_t pid, int cpu, struct fgraph_data *data)
...@@ -521,6 +544,7 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr, ...@@ -521,6 +544,7 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr,
if (ret == TRACE_TYPE_PARTIAL_LINE) if (ret == TRACE_TYPE_PARTIAL_LINE)
return TRACE_TYPE_PARTIAL_LINE; return TRACE_TYPE_PARTIAL_LINE;
} }
/* Proc */ /* Proc */
if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) { if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) {
ret = print_graph_proc(s, pid); ret = print_graph_proc(s, pid);
...@@ -758,6 +782,13 @@ print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s, ...@@ -758,6 +782,13 @@ print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s,
return TRACE_TYPE_PARTIAL_LINE; return TRACE_TYPE_PARTIAL_LINE;
} }
/* Latency format */
if (trace_flags & TRACE_ITER_LATENCY_FMT) {
ret = print_graph_lat_fmt(s, ent);
if (ret == TRACE_TYPE_PARTIAL_LINE)
return TRACE_TYPE_PARTIAL_LINE;
}
return 0; return 0;
} }
...@@ -952,28 +983,59 @@ print_graph_function(struct trace_iterator *iter) ...@@ -952,28 +983,59 @@ print_graph_function(struct trace_iterator *iter)
return TRACE_TYPE_HANDLED; return TRACE_TYPE_HANDLED;
} }
static void print_lat_header(struct seq_file *s)
{
static const char spaces[] = " " /* 16 spaces */
" " /* 4 spaces */
" "; /* 17 spaces */
int size = 0;
if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME)
size += 16;
if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU)
size += 4;
if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC)
size += 17;
seq_printf(s, "#%.*s _-----=> irqs-off \n", size, spaces);
seq_printf(s, "#%.*s / _----=> need-resched \n", size, spaces);
seq_printf(s, "#%.*s| / _---=> hardirq/softirq \n", size, spaces);
seq_printf(s, "#%.*s|| / _--=> preempt-depth \n", size, spaces);
seq_printf(s, "#%.*s||| / \n", size, spaces);
seq_printf(s, "#%.*s|||| \n", size, spaces);
}
static void print_graph_headers(struct seq_file *s) static void print_graph_headers(struct seq_file *s)
{ {
int lat = trace_flags & TRACE_ITER_LATENCY_FMT;
if (lat)
print_lat_header(s);
/* 1st line */ /* 1st line */
seq_printf(s, "# "); seq_printf(s, "#");
if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME) if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME)
seq_printf(s, " TIME "); seq_printf(s, " TIME ");
if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU)
seq_printf(s, "CPU"); seq_printf(s, " CPU");
if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC)
seq_printf(s, " TASK/PID "); seq_printf(s, " TASK/PID ");
if (lat)
seq_printf(s, "||||");
if (tracer_flags.val & TRACE_GRAPH_PRINT_DURATION) if (tracer_flags.val & TRACE_GRAPH_PRINT_DURATION)
seq_printf(s, " DURATION "); seq_printf(s, " DURATION ");
seq_printf(s, " FUNCTION CALLS\n"); seq_printf(s, " FUNCTION CALLS\n");
/* 2nd line */ /* 2nd line */
seq_printf(s, "# "); seq_printf(s, "#");
if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME) if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME)
seq_printf(s, " | "); seq_printf(s, " | ");
if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU)
seq_printf(s, "| "); seq_printf(s, " | ");
if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC)
seq_printf(s, " | | "); seq_printf(s, " | | ");
if (lat)
seq_printf(s, "||||");
if (tracer_flags.val & TRACE_GRAPH_PRINT_DURATION) if (tracer_flags.val & TRACE_GRAPH_PRINT_DURATION)
seq_printf(s, " | | "); seq_printf(s, " | | ");
seq_printf(s, " | | | |\n"); seq_printf(s, " | | | |\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment