|
@@ -74,6 +74,20 @@ static struct tracer_flags tracer_flags = {
|
|
|
|
|
|
static struct trace_array *graph_array;
|
|
|
|
|
|
+/*
|
|
|
+ * DURATION column is being also used to display IRQ signs,
|
|
|
+ * following values are used by print_graph_irq and others
|
|
|
+ * to fill in space into DURATION column.
|
|
|
+ */
|
|
|
+enum {
|
|
|
+ DURATION_FILL_FULL = -1,
|
|
|
+ DURATION_FILL_START = -2,
|
|
|
+ DURATION_FILL_END = -3,
|
|
|
+};
|
|
|
+
|
|
|
+static enum print_line_t
|
|
|
+print_graph_duration(unsigned long long duration, struct trace_seq *s,
|
|
|
+ u32 flags);
|
|
|
|
|
|
/* Add a function return address to the trace stack on thread info.*/
|
|
|
int
|
|
@@ -577,32 +591,6 @@ get_return_for_leaf(struct trace_iterator *iter,
|
|
|
return next;
|
|
|
}
|
|
|
|
|
|
-/* Signal a overhead of time execution to the output */
|
|
|
-static int
|
|
|
-print_graph_overhead(unsigned long long duration, struct trace_seq *s,
|
|
|
- u32 flags)
|
|
|
-{
|
|
|
- /* If duration disappear, we don't need anything */
|
|
|
- if (!(flags & TRACE_GRAPH_PRINT_DURATION))
|
|
|
- return 1;
|
|
|
-
|
|
|
- /* Non nested entry or return */
|
|
|
- if (duration == -1)
|
|
|
- return trace_seq_printf(s, " ");
|
|
|
-
|
|
|
- if (flags & TRACE_GRAPH_PRINT_OVERHEAD) {
|
|
|
- /* Duration exceeded 100 msecs */
|
|
|
- if (duration > 100000ULL)
|
|
|
- return trace_seq_printf(s, "! ");
|
|
|
-
|
|
|
- /* Duration exceeded 10 msecs */
|
|
|
- if (duration > 10000ULL)
|
|
|
- return trace_seq_printf(s, "+ ");
|
|
|
- }
|
|
|
-
|
|
|
- return trace_seq_printf(s, " ");
|
|
|
-}
|
|
|
-
|
|
|
static int print_graph_abs_time(u64 t, struct trace_seq *s)
|
|
|
{
|
|
|
unsigned long usecs_rem;
|
|
@@ -625,34 +613,36 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr,
|
|
|
addr >= (unsigned long)__irqentry_text_end)
|
|
|
return TRACE_TYPE_UNHANDLED;
|
|
|
|
|
|
- /* Absolute time */
|
|
|
- if (flags & TRACE_GRAPH_PRINT_ABS_TIME) {
|
|
|
- ret = print_graph_abs_time(iter->ts, s);
|
|
|
- if (!ret)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
- }
|
|
|
+ if (trace_flags & TRACE_ITER_CONTEXT_INFO) {
|
|
|
+ /* Absolute time */
|
|
|
+ if (flags & TRACE_GRAPH_PRINT_ABS_TIME) {
|
|
|
+ ret = print_graph_abs_time(iter->ts, s);
|
|
|
+ if (!ret)
|
|
|
+ return TRACE_TYPE_PARTIAL_LINE;
|
|
|
+ }
|
|
|
|
|
|
- /* Cpu */
|
|
|
- if (flags & TRACE_GRAPH_PRINT_CPU) {
|
|
|
- ret = print_graph_cpu(s, cpu);
|
|
|
- if (ret == TRACE_TYPE_PARTIAL_LINE)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
- }
|
|
|
+ /* Cpu */
|
|
|
+ if (flags & TRACE_GRAPH_PRINT_CPU) {
|
|
|
+ ret = print_graph_cpu(s, cpu);
|
|
|
+ if (ret == TRACE_TYPE_PARTIAL_LINE)
|
|
|
+ return TRACE_TYPE_PARTIAL_LINE;
|
|
|
+ }
|
|
|
|
|
|
- /* Proc */
|
|
|
- if (flags & TRACE_GRAPH_PRINT_PROC) {
|
|
|
- ret = print_graph_proc(s, pid);
|
|
|
- if (ret == TRACE_TYPE_PARTIAL_LINE)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
- ret = trace_seq_printf(s, " | ");
|
|
|
- if (!ret)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
+ /* Proc */
|
|
|
+ if (flags & TRACE_GRAPH_PRINT_PROC) {
|
|
|
+ ret = print_graph_proc(s, pid);
|
|
|
+ if (ret == TRACE_TYPE_PARTIAL_LINE)
|
|
|
+ return TRACE_TYPE_PARTIAL_LINE;
|
|
|
+ ret = trace_seq_printf(s, " | ");
|
|
|
+ if (!ret)
|
|
|
+ return TRACE_TYPE_PARTIAL_LINE;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* No overhead */
|
|
|
- ret = print_graph_overhead(-1, s, flags);
|
|
|
- if (!ret)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
+ ret = print_graph_duration(DURATION_FILL_START, s, flags);
|
|
|
+ if (ret != TRACE_TYPE_HANDLED)
|
|
|
+ return ret;
|
|
|
|
|
|
if (type == TRACE_GRAPH_ENT)
|
|
|
ret = trace_seq_printf(s, "==========>");
|
|
@@ -662,9 +652,10 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr,
|
|
|
if (!ret)
|
|
|
return TRACE_TYPE_PARTIAL_LINE;
|
|
|
|
|
|
- /* Don't close the duration column if haven't one */
|
|
|
- if (flags & TRACE_GRAPH_PRINT_DURATION)
|
|
|
- trace_seq_printf(s, " |");
|
|
|
+ ret = print_graph_duration(DURATION_FILL_END, s, flags);
|
|
|
+ if (ret != TRACE_TYPE_HANDLED)
|
|
|
+ return ret;
|
|
|
+
|
|
|
ret = trace_seq_printf(s, "\n");
|
|
|
|
|
|
if (!ret)
|
|
@@ -716,9 +707,49 @@ trace_print_graph_duration(unsigned long long duration, struct trace_seq *s)
|
|
|
}
|
|
|
|
|
|
static enum print_line_t
|
|
|
-print_graph_duration(unsigned long long duration, struct trace_seq *s)
|
|
|
+print_graph_duration(unsigned long long duration, struct trace_seq *s,
|
|
|
+ u32 flags)
|
|
|
{
|
|
|
- int ret;
|
|
|
+ int ret = -1;
|
|
|
+
|
|
|
+ if (!(flags & TRACE_GRAPH_PRINT_DURATION) ||
|
|
|
+ !(trace_flags & TRACE_ITER_CONTEXT_INFO))
|
|
|
+ return TRACE_TYPE_HANDLED;
|
|
|
+
|
|
|
+ /* No real adata, just filling the column with spaces */
|
|
|
+ switch (duration) {
|
|
|
+ case DURATION_FILL_FULL:
|
|
|
+ ret = trace_seq_printf(s, " | ");
|
|
|
+ return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE;
|
|
|
+ case DURATION_FILL_START:
|
|
|
+ ret = trace_seq_printf(s, " ");
|
|
|
+ return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE;
|
|
|
+ case DURATION_FILL_END:
|
|
|
+ ret = trace_seq_printf(s, " |");
|
|
|
+ return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Signal a overhead of time execution to the output */
|
|
|
+ if (flags & TRACE_GRAPH_PRINT_OVERHEAD) {
|
|
|
+ /* Duration exceeded 100 msecs */
|
|
|
+ if (duration > 100000ULL)
|
|
|
+ ret = trace_seq_printf(s, "! ");
|
|
|
+ /* Duration exceeded 10 msecs */
|
|
|
+ else if (duration > 10000ULL)
|
|
|
+ ret = trace_seq_printf(s, "+ ");
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The -1 means we either did not exceed the duration tresholds
|
|
|
+ * or we dont want to print out the overhead. Either way we need
|
|
|
+ * to fill out the space.
|
|
|
+ */
|
|
|
+ if (ret == -1)
|
|
|
+ ret = trace_seq_printf(s, " ");
|
|
|
+
|
|
|
+ /* Catching here any failure happenned above */
|
|
|
+ if (!ret)
|
|
|
+ return TRACE_TYPE_PARTIAL_LINE;
|
|
|
|
|
|
ret = trace_print_graph_duration(duration, s);
|
|
|
if (ret != TRACE_TYPE_HANDLED)
|
|
@@ -767,18 +798,11 @@ print_graph_entry_leaf(struct trace_iterator *iter,
|
|
|
cpu_data->enter_funcs[call->depth] = 0;
|
|
|
}
|
|
|
|
|
|
- /* Overhead */
|
|
|
- ret = print_graph_overhead(duration, s, flags);
|
|
|
- if (!ret)
|
|
|
+ /* Overhead and duration */
|
|
|
+ ret = print_graph_duration(duration, s, flags);
|
|
|
+ if (ret == TRACE_TYPE_PARTIAL_LINE)
|
|
|
return TRACE_TYPE_PARTIAL_LINE;
|
|
|
|
|
|
- /* Duration */
|
|
|
- if (flags & TRACE_GRAPH_PRINT_DURATION) {
|
|
|
- ret = print_graph_duration(duration, s);
|
|
|
- if (ret == TRACE_TYPE_PARTIAL_LINE)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
- }
|
|
|
-
|
|
|
/* Function */
|
|
|
for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) {
|
|
|
ret = trace_seq_printf(s, " ");
|
|
@@ -815,17 +839,10 @@ print_graph_entry_nested(struct trace_iterator *iter,
|
|
|
cpu_data->enter_funcs[call->depth] = call->func;
|
|
|
}
|
|
|
|
|
|
- /* No overhead */
|
|
|
- ret = print_graph_overhead(-1, s, flags);
|
|
|
- if (!ret)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
-
|
|
|
/* No time */
|
|
|
- if (flags & TRACE_GRAPH_PRINT_DURATION) {
|
|
|
- ret = trace_seq_printf(s, " | ");
|
|
|
- if (!ret)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
- }
|
|
|
+ ret = print_graph_duration(DURATION_FILL_FULL, s, flags);
|
|
|
+ if (ret != TRACE_TYPE_HANDLED)
|
|
|
+ return ret;
|
|
|
|
|
|
/* Function */
|
|
|
for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) {
|
|
@@ -865,6 +882,9 @@ print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s,
|
|
|
return TRACE_TYPE_PARTIAL_LINE;
|
|
|
}
|
|
|
|
|
|
+ if (!(trace_flags & TRACE_ITER_CONTEXT_INFO))
|
|
|
+ return 0;
|
|
|
+
|
|
|
/* Absolute time */
|
|
|
if (flags & TRACE_GRAPH_PRINT_ABS_TIME) {
|
|
|
ret = print_graph_abs_time(iter->ts, s);
|
|
@@ -1078,18 +1098,11 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
|
|
|
if (print_graph_prologue(iter, s, 0, 0, flags))
|
|
|
return TRACE_TYPE_PARTIAL_LINE;
|
|
|
|
|
|
- /* Overhead */
|
|
|
- ret = print_graph_overhead(duration, s, flags);
|
|
|
- if (!ret)
|
|
|
+ /* Overhead and duration */
|
|
|
+ ret = print_graph_duration(duration, s, flags);
|
|
|
+ if (ret == TRACE_TYPE_PARTIAL_LINE)
|
|
|
return TRACE_TYPE_PARTIAL_LINE;
|
|
|
|
|
|
- /* Duration */
|
|
|
- if (flags & TRACE_GRAPH_PRINT_DURATION) {
|
|
|
- ret = print_graph_duration(duration, s);
|
|
|
- if (ret == TRACE_TYPE_PARTIAL_LINE)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
- }
|
|
|
-
|
|
|
/* Closing brace */
|
|
|
for (i = 0; i < trace->depth * TRACE_GRAPH_INDENT; i++) {
|
|
|
ret = trace_seq_printf(s, " ");
|
|
@@ -1146,17 +1159,10 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent,
|
|
|
if (print_graph_prologue(iter, s, 0, 0, flags))
|
|
|
return TRACE_TYPE_PARTIAL_LINE;
|
|
|
|
|
|
- /* No overhead */
|
|
|
- ret = print_graph_overhead(-1, s, flags);
|
|
|
- if (!ret)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
-
|
|
|
/* No time */
|
|
|
- if (flags & TRACE_GRAPH_PRINT_DURATION) {
|
|
|
- ret = trace_seq_printf(s, " | ");
|
|
|
- if (!ret)
|
|
|
- return TRACE_TYPE_PARTIAL_LINE;
|
|
|
- }
|
|
|
+ ret = print_graph_duration(DURATION_FILL_FULL, s, flags);
|
|
|
+ if (ret != TRACE_TYPE_HANDLED)
|
|
|
+ return ret;
|
|
|
|
|
|
/* Indentation */
|
|
|
if (depth > 0)
|
|
@@ -1207,7 +1213,7 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent,
|
|
|
|
|
|
|
|
|
enum print_line_t
|
|
|
-__print_graph_function_flags(struct trace_iterator *iter, u32 flags)
|
|
|
+print_graph_function_flags(struct trace_iterator *iter, u32 flags)
|
|
|
{
|
|
|
struct ftrace_graph_ent_entry *field;
|
|
|
struct fgraph_data *data = iter->private;
|
|
@@ -1270,18 +1276,7 @@ __print_graph_function_flags(struct trace_iterator *iter, u32 flags)
|
|
|
static enum print_line_t
|
|
|
print_graph_function(struct trace_iterator *iter)
|
|
|
{
|
|
|
- return __print_graph_function_flags(iter, tracer_flags.val);
|
|
|
-}
|
|
|
-
|
|
|
-enum print_line_t print_graph_function_flags(struct trace_iterator *iter,
|
|
|
- u32 flags)
|
|
|
-{
|
|
|
- if (trace_flags & TRACE_ITER_LATENCY_FMT)
|
|
|
- flags |= TRACE_GRAPH_PRINT_DURATION;
|
|
|
- else
|
|
|
- flags |= TRACE_GRAPH_PRINT_ABS_TIME;
|
|
|
-
|
|
|
- return __print_graph_function_flags(iter, flags);
|
|
|
+ return print_graph_function_flags(iter, tracer_flags.val);
|
|
|
}
|
|
|
|
|
|
static enum print_line_t
|
|
@@ -1309,8 +1304,7 @@ static void print_lat_header(struct seq_file *s, u32 flags)
|
|
|
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||| / _-=> lock-depth \n", size, spaces);
|
|
|
- seq_printf(s, "#%.*s|||| / \n", size, spaces);
|
|
|
+ seq_printf(s, "#%.*s||| / \n", size, spaces);
|
|
|
}
|
|
|
|
|
|
static void __print_graph_headers_flags(struct seq_file *s, u32 flags)
|
|
@@ -1329,7 +1323,7 @@ static void __print_graph_headers_flags(struct seq_file *s, u32 flags)
|
|
|
if (flags & TRACE_GRAPH_PRINT_PROC)
|
|
|
seq_printf(s, " TASK/PID ");
|
|
|
if (lat)
|
|
|
- seq_printf(s, "|||||");
|
|
|
+ seq_printf(s, "||||");
|
|
|
if (flags & TRACE_GRAPH_PRINT_DURATION)
|
|
|
seq_printf(s, " DURATION ");
|
|
|
seq_printf(s, " FUNCTION CALLS\n");
|
|
@@ -1343,7 +1337,7 @@ static void __print_graph_headers_flags(struct seq_file *s, u32 flags)
|
|
|
if (flags & TRACE_GRAPH_PRINT_PROC)
|
|
|
seq_printf(s, " | | ");
|
|
|
if (lat)
|
|
|
- seq_printf(s, "|||||");
|
|
|
+ seq_printf(s, "||||");
|
|
|
if (flags & TRACE_GRAPH_PRINT_DURATION)
|
|
|
seq_printf(s, " | | ");
|
|
|
seq_printf(s, " | | | |\n");
|
|
@@ -1358,15 +1352,16 @@ void print_graph_headers_flags(struct seq_file *s, u32 flags)
|
|
|
{
|
|
|
struct trace_iterator *iter = s->private;
|
|
|
|
|
|
+ if (!(trace_flags & TRACE_ITER_CONTEXT_INFO))
|
|
|
+ return;
|
|
|
+
|
|
|
if (trace_flags & TRACE_ITER_LATENCY_FMT) {
|
|
|
/* print nothing if the buffers are empty */
|
|
|
if (trace_empty(iter))
|
|
|
return;
|
|
|
|
|
|
print_trace_header(s, iter);
|
|
|
- flags |= TRACE_GRAPH_PRINT_DURATION;
|
|
|
- } else
|
|
|
- flags |= TRACE_GRAPH_PRINT_ABS_TIME;
|
|
|
+ }
|
|
|
|
|
|
__print_graph_headers_flags(s, flags);
|
|
|
}
|