diff options
Diffstat (limited to 'kernel/trace/trace_functions_graph.c')
-rw-r--r-- | kernel/trace/trace_functions_graph.c | 104 |
1 files changed, 80 insertions, 24 deletions
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index f5bad4624d2b..b6f0cc2a00cb 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
@@ -13,6 +13,7 @@ | |||
13 | 13 | ||
14 | #include "trace.h" | 14 | #include "trace.h" |
15 | 15 | ||
16 | #define TRACE_GRAPH_INDENT 2 | ||
16 | 17 | ||
17 | #define TRACE_GRAPH_PRINT_OVERRUN 0x1 | 18 | #define TRACE_GRAPH_PRINT_OVERRUN 0x1 |
18 | static struct tracer_opt trace_opts[] = { | 19 | static struct tracer_opt trace_opts[] = { |
@@ -26,6 +27,8 @@ static struct tracer_flags tracer_flags = { | |||
26 | .opts = trace_opts | 27 | .opts = trace_opts |
27 | }; | 28 | }; |
28 | 29 | ||
30 | /* pid on the last trace processed */ | ||
31 | static pid_t last_pid = -1; | ||
29 | 32 | ||
30 | static int graph_trace_init(struct trace_array *tr) | 33 | static int graph_trace_init(struct trace_array *tr) |
31 | { | 34 | { |
@@ -33,7 +36,8 @@ static int graph_trace_init(struct trace_array *tr) | |||
33 | for_each_online_cpu(cpu) | 36 | for_each_online_cpu(cpu) |
34 | tracing_reset(tr, cpu); | 37 | tracing_reset(tr, cpu); |
35 | 38 | ||
36 | return register_ftrace_graph(&trace_function_graph); | 39 | return register_ftrace_graph(&trace_graph_return, |
40 | &trace_graph_entry); | ||
37 | } | 41 | } |
38 | 42 | ||
39 | static void graph_trace_reset(struct trace_array *tr) | 43 | static void graph_trace_reset(struct trace_array *tr) |
@@ -41,45 +45,97 @@ static void graph_trace_reset(struct trace_array *tr) | |||
41 | unregister_ftrace_graph(); | 45 | unregister_ftrace_graph(); |
42 | } | 46 | } |
43 | 47 | ||
48 | /* If the pid changed since the last trace, output this event */ | ||
49 | static int verif_pid(struct trace_seq *s, pid_t pid) | ||
50 | { | ||
51 | if (last_pid != -1 && last_pid == pid) | ||
52 | return 1; | ||
44 | 53 | ||
45 | enum print_line_t | 54 | last_pid = pid; |
46 | print_graph_function(struct trace_iterator *iter) | 55 | return trace_seq_printf(s, "\n------------8<---------- thread %d" |
56 | " ------------8<----------\n\n", | ||
57 | pid); | ||
58 | } | ||
59 | |||
60 | static enum print_line_t | ||
61 | print_graph_entry(struct ftrace_graph_ent *call, struct trace_seq *s, | ||
62 | struct trace_entry *ent) | ||
47 | { | 63 | { |
48 | struct trace_seq *s = &iter->seq; | 64 | int i; |
49 | struct trace_entry *entry = iter->ent; | ||
50 | struct ftrace_graph_entry *field; | ||
51 | int ret; | 65 | int ret; |
52 | 66 | ||
53 | if (entry->type == TRACE_FN_RET) { | 67 | if (!verif_pid(s, ent->pid)) |
54 | trace_assign_type(field, entry); | 68 | return TRACE_TYPE_PARTIAL_LINE; |
55 | ret = trace_seq_printf(s, "%pF -> ", (void *)field->parent_ip); | ||
56 | if (!ret) | ||
57 | return TRACE_TYPE_PARTIAL_LINE; | ||
58 | 69 | ||
59 | ret = seq_print_ip_sym(s, field->ip, | 70 | for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) { |
60 | trace_flags & TRACE_ITER_SYM_MASK); | 71 | ret = trace_seq_printf(s, " "); |
61 | if (!ret) | 72 | if (!ret) |
62 | return TRACE_TYPE_PARTIAL_LINE; | 73 | return TRACE_TYPE_PARTIAL_LINE; |
74 | } | ||
75 | |||
76 | ret = seq_print_ip_sym(s, call->func, 0); | ||
77 | if (!ret) | ||
78 | return TRACE_TYPE_PARTIAL_LINE; | ||
79 | |||
80 | ret = trace_seq_printf(s, "() {\n"); | ||
81 | if (!ret) | ||
82 | return TRACE_TYPE_PARTIAL_LINE; | ||
83 | return TRACE_TYPE_HANDLED; | ||
84 | } | ||
85 | |||
86 | static enum print_line_t | ||
87 | print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s, | ||
88 | struct trace_entry *ent) | ||
89 | { | ||
90 | int i; | ||
91 | int ret; | ||
92 | |||
93 | if (!verif_pid(s, ent->pid)) | ||
94 | return TRACE_TYPE_PARTIAL_LINE; | ||
63 | 95 | ||
64 | ret = trace_seq_printf(s, " (%llu ns)", | 96 | for (i = 0; i < trace->depth * TRACE_GRAPH_INDENT; i++) { |
65 | field->rettime - field->calltime); | 97 | ret = trace_seq_printf(s, " "); |
66 | if (!ret) | 98 | if (!ret) |
67 | return TRACE_TYPE_PARTIAL_LINE; | 99 | return TRACE_TYPE_PARTIAL_LINE; |
100 | } | ||
101 | |||
102 | ret = trace_seq_printf(s, "} "); | ||
103 | if (!ret) | ||
104 | return TRACE_TYPE_PARTIAL_LINE; | ||
68 | 105 | ||
69 | if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERRUN) { | 106 | ret = trace_seq_printf(s, "%llu\n", trace->rettime - trace->calltime); |
70 | ret = trace_seq_printf(s, " (Overruns: %lu)", | 107 | if (!ret) |
71 | field->overrun); | 108 | return TRACE_TYPE_PARTIAL_LINE; |
72 | if (!ret) | ||
73 | return TRACE_TYPE_PARTIAL_LINE; | ||
74 | } | ||
75 | 109 | ||
76 | ret = trace_seq_printf(s, "\n"); | 110 | if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERRUN) { |
111 | ret = trace_seq_printf(s, " (Overruns: %lu)\n", | ||
112 | trace->overrun); | ||
77 | if (!ret) | 113 | if (!ret) |
78 | return TRACE_TYPE_PARTIAL_LINE; | 114 | return TRACE_TYPE_PARTIAL_LINE; |
115 | } | ||
116 | return TRACE_TYPE_HANDLED; | ||
117 | } | ||
118 | |||
119 | enum print_line_t | ||
120 | print_graph_function(struct trace_iterator *iter) | ||
121 | { | ||
122 | struct trace_seq *s = &iter->seq; | ||
123 | struct trace_entry *entry = iter->ent; | ||
79 | 124 | ||
80 | return TRACE_TYPE_HANDLED; | 125 | switch (entry->type) { |
126 | case TRACE_GRAPH_ENT: { | ||
127 | struct ftrace_graph_ent_entry *field; | ||
128 | trace_assign_type(field, entry); | ||
129 | return print_graph_entry(&field->graph_ent, s, entry); | ||
130 | } | ||
131 | case TRACE_GRAPH_RET: { | ||
132 | struct ftrace_graph_ret_entry *field; | ||
133 | trace_assign_type(field, entry); | ||
134 | return print_graph_return(&field->ret, s, entry); | ||
135 | } | ||
136 | default: | ||
137 | return TRACE_TYPE_UNHANDLED; | ||
81 | } | 138 | } |
82 | return TRACE_TYPE_UNHANDLED; | ||
83 | } | 139 | } |
84 | 140 | ||
85 | static struct tracer graph_trace __read_mostly = { | 141 | static struct tracer graph_trace __read_mostly = { |