aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_functions_graph.c
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2008-11-27 18:42:46 -0500
committerIngo Molnar <mingo@elte.hu>2008-11-28 03:45:04 -0500
commit1a056155edd458eb93ef383fa8e5741d7e7c6360 (patch)
tree9d58c7c118be65899b62f0c43892e5980a9912c2 /kernel/trace/trace_functions_graph.c
parent83a8df618eb04bd2819a758f3b409b1449862434 (diff)
tracing/function-graph-tracer: adjustments of the trace informations
Impact: increase the visual qualities of the call-graph-tracer output This patch applies various trace output formatting changes: - CPU is now a decimal number, followed by a parenthesis. - Overhead is now on the second column (gives a good visibility) - Cost is now on the third column, can't exceed 9999.99 us. It is followed by a virtual line based on a "|" character. - Functions calls are now the last column on the right. This way, we haven't dynamic column (which flow is harder to follow) on its right. - CPU and Overhead have their own option flag. They are default-on but you can disable them easily: echo nofuncgraph-cpu > trace_options echo nofuncgraph-overhead > trace_options TODO: _ Refactoring of the thread switch output. _ Give a default-off option to output the thread and its pid on each row. _ Provide headers _ .... Here is an example of the new trace style: 0) | mutex_unlock() { 0) 0.639 us | __mutex_unlock_slowpath(); 0) 1.607 us | } 0) | remove_wait_queue() { 0) 0.616 us | _spin_lock_irqsave(); 0) 0.616 us | _spin_unlock_irqrestore(); 0) 2.779 us | } 0) 0.495 us | n_tty_set_room(); 0) ! 9999.999 us | } 0) | tty_ldisc_deref() { 0) 0.615 us | _spin_lock_irqsave(); 0) 0.616 us | _spin_unlock_irqrestore(); 0) 2.793 us | } 0) | current_fs_time() { 0) 0.488 us | current_kernel_time(); 0) 0.495 us | timespec_trunc(); 0) 2.486 us | } 0) ! 9999.999 us | } 0) ! 9999.999 us | } 0) ! 9999.999 us | } 0) | sys_read() { 0) 0.796 us | fget_light(); 0) | vfs_read() { 0) | rw_verify_area() { 0) | security_file_permission() { 0) 0.488 us | cap_file_permission(); 0) 1.720 us | } 0) 3. 4 us | } 0) | tty_read() { 0) 0.488 us | tty_paranoia_check(); 0) | tty_ldisc_ref_wait() { 0) | tty_ldisc_try() { 0) 0.615 us | _spin_lock_irqsave(); 0) 0.615 us | _spin_unlock_irqrestore(); 0) 5.436 us | } 0) 6.427 us | } Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Acked-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/trace/trace_functions_graph.c')
-rw-r--r--kernel/trace/trace_functions_graph.c142
1 files changed, 93 insertions, 49 deletions
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
index b958d60377b3..596a3ee43053 100644
--- a/kernel/trace/trace_functions_graph.c
+++ b/kernel/trace/trace_functions_graph.c
@@ -14,20 +14,25 @@
14#include "trace.h" 14#include "trace.h"
15 15
16#define TRACE_GRAPH_INDENT 2 16#define TRACE_GRAPH_INDENT 2
17/* Spaces between function call and time duration */
18#define TRACE_GRAPH_TIMESPACE_ENTRY " "
19/* Spaces between function call and closing braces */
20#define TRACE_GRAPH_TIMESPACE_RET " "
21 17
18/* Flag options */
22#define TRACE_GRAPH_PRINT_OVERRUN 0x1 19#define TRACE_GRAPH_PRINT_OVERRUN 0x1
20#define TRACE_GRAPH_PRINT_CPU 0x2
21#define TRACE_GRAPH_PRINT_OVERHEAD 0x4
22
23static struct tracer_opt trace_opts[] = { 23static struct tracer_opt trace_opts[] = {
24 /* Display overruns or not */ 24 /* Display overruns ? */
25 { TRACER_OPT(overrun, TRACE_GRAPH_PRINT_OVERRUN) }, 25 { TRACER_OPT(funcgraph-overrun, TRACE_GRAPH_PRINT_OVERRUN) },
26 /* Display CPU ? */
27 { TRACER_OPT(funcgraph-cpu, TRACE_GRAPH_PRINT_CPU) },
28 /* Display Overhead ? */
29 { TRACER_OPT(funcgraph-overhead, TRACE_GRAPH_PRINT_OVERHEAD) },
26 { } /* Empty entry */ 30 { } /* Empty entry */
27}; 31};
28 32
29static struct tracer_flags tracer_flags = { 33static struct tracer_flags tracer_flags = {
30 .val = 0, /* Don't display overruns by default */ 34 /* Don't display overruns by default */
35 .val = TRACE_GRAPH_PRINT_CPU | TRACE_GRAPH_PRINT_OVERHEAD,
31 .opts = trace_opts 36 .opts = trace_opts
32}; 37};
33 38
@@ -56,6 +61,36 @@ static void graph_trace_reset(struct trace_array *tr)
56 unregister_ftrace_graph(); 61 unregister_ftrace_graph();
57} 62}
58 63
64static inline int log10_cpu(int nb)
65{
66 if (nb / 100)
67 return 3;
68 if (nb / 10)
69 return 2;
70 return 1;
71}
72
73static enum print_line_t
74print_graph_cpu(struct trace_seq *s, int cpu)
75{
76 int i;
77 int ret;
78 int log10_this = log10_cpu(cpu);
79 int log10_all = log10_cpu(cpus_weight_nr(cpu_online_map));
80
81
82 for (i = 0; i < log10_all - log10_this; i++) {
83 ret = trace_seq_printf(s, " ");
84 if (!ret)
85 return TRACE_TYPE_PARTIAL_LINE;
86 }
87 ret = trace_seq_printf(s, "%d) ", cpu);
88 if (!ret)
89 return TRACE_TYPE_PARTIAL_LINE;
90 return TRACE_TYPE_HANDLED;
91}
92
93
59/* If the pid changed since the last trace, output this event */ 94/* If the pid changed since the last trace, output this event */
60static int verif_pid(struct trace_seq *s, pid_t pid, int cpu) 95static int verif_pid(struct trace_seq *s, pid_t pid, int cpu)
61{ 96{
@@ -67,8 +102,7 @@ static int verif_pid(struct trace_seq *s, pid_t pid, int cpu)
67 last_pid[cpu] = pid; 102 last_pid[cpu] = pid;
68 comm = trace_find_cmdline(pid); 103 comm = trace_find_cmdline(pid);
69 104
70 return trace_seq_printf(s, "\nCPU[%03d] " 105 return trace_seq_printf(s, "\n------------8<---------- thread %s-%d"
71 " ------------8<---------- thread %s-%d"
72 " ------------8<----------\n\n", 106 " ------------8<----------\n\n",
73 cpu, comm, pid); 107 cpu, comm, pid);
74} 108}
@@ -86,7 +120,7 @@ trace_branch_is_leaf(struct trace_iterator *iter,
86 if (!ring_iter) 120 if (!ring_iter)
87 return false; 121 return false;
88 122
89 event = ring_buffer_iter_peek(iter->buffer_iter[iter->cpu], NULL); 123 event = ring_buffer_iter_peek(ring_iter, NULL);
90 124
91 if (!event) 125 if (!event)
92 return false; 126 return false;
@@ -108,7 +142,7 @@ static inline int
108print_graph_duration(unsigned long long duration, struct trace_seq *s) 142print_graph_duration(unsigned long long duration, struct trace_seq *s)
109{ 143{
110 unsigned long nsecs_rem = do_div(duration, 1000); 144 unsigned long nsecs_rem = do_div(duration, 1000);
111 return trace_seq_printf(s, "+ %llu.%lu us\n", duration, nsecs_rem); 145 return trace_seq_printf(s, "%4llu.%3lu us | ", duration, nsecs_rem);
112} 146}
113 147
114/* Signal a overhead of time execution to the output */ 148/* Signal a overhead of time execution to the output */
@@ -136,8 +170,8 @@ print_graph_entry_leaf(struct trace_iterator *iter,
136 struct ring_buffer_event *event; 170 struct ring_buffer_event *event;
137 struct ftrace_graph_ent *call; 171 struct ftrace_graph_ent *call;
138 unsigned long long duration; 172 unsigned long long duration;
139 int i;
140 int ret; 173 int ret;
174 int i;
141 175
142 event = ring_buffer_read(iter->buffer_iter[iter->cpu], NULL); 176 event = ring_buffer_read(iter->buffer_iter[iter->cpu], NULL);
143 ret_entry = ring_buffer_event_data(event); 177 ret_entry = ring_buffer_event_data(event);
@@ -145,8 +179,19 @@ print_graph_entry_leaf(struct trace_iterator *iter,
145 call = &entry->graph_ent; 179 call = &entry->graph_ent;
146 duration = graph_ret->rettime - graph_ret->calltime; 180 duration = graph_ret->rettime - graph_ret->calltime;
147 181
182 /* Must not exceed 8 characters: 9999.999 us */
183 if (duration > 10000000ULL)
184 duration = 9999999ULL;
185
148 /* Overhead */ 186 /* Overhead */
149 ret = print_graph_overhead(duration, s); 187 if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) {
188 ret = print_graph_overhead(duration, s);
189 if (!ret)
190 return TRACE_TYPE_PARTIAL_LINE;
191 }
192
193 /* Duration */
194 ret = print_graph_duration(duration, s);
150 if (!ret) 195 if (!ret)
151 return TRACE_TYPE_PARTIAL_LINE; 196 return TRACE_TYPE_PARTIAL_LINE;
152 197
@@ -161,16 +206,7 @@ print_graph_entry_leaf(struct trace_iterator *iter,
161 if (!ret) 206 if (!ret)
162 return TRACE_TYPE_PARTIAL_LINE; 207 return TRACE_TYPE_PARTIAL_LINE;
163 208
164 ret = trace_seq_printf(s, "();"); 209 ret = trace_seq_printf(s, "();\n");
165 if (!ret)
166 return TRACE_TYPE_PARTIAL_LINE;
167
168 /* Duration */
169 ret = trace_seq_printf(s, TRACE_GRAPH_TIMESPACE_ENTRY);
170 if (!ret)
171 return TRACE_TYPE_PARTIAL_LINE;
172
173 ret = print_graph_duration(duration, s);
174 if (!ret) 210 if (!ret)
175 return TRACE_TYPE_PARTIAL_LINE; 211 return TRACE_TYPE_PARTIAL_LINE;
176 212
@@ -186,9 +222,14 @@ print_graph_entry_nested(struct ftrace_graph_ent_entry *entry,
186 struct ftrace_graph_ent *call = &entry->graph_ent; 222 struct ftrace_graph_ent *call = &entry->graph_ent;
187 223
188 /* No overhead */ 224 /* No overhead */
189 ret = trace_seq_printf(s, " "); 225 if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) {
190 if (!ret) 226 ret = trace_seq_printf(s, " ");
191 return TRACE_TYPE_PARTIAL_LINE; 227 if (!ret)
228 return TRACE_TYPE_PARTIAL_LINE;
229 }
230
231 /* No time */
232 ret = trace_seq_printf(s, " | ");
192 233
193 /* Function */ 234 /* Function */
194 for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) { 235 for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) {
@@ -201,12 +242,7 @@ print_graph_entry_nested(struct ftrace_graph_ent_entry *entry,
201 if (!ret) 242 if (!ret)
202 return TRACE_TYPE_PARTIAL_LINE; 243 return TRACE_TYPE_PARTIAL_LINE;
203 244
204 ret = trace_seq_printf(s, "() {"); 245 ret = trace_seq_printf(s, "() {\n");
205 if (!ret)
206 return TRACE_TYPE_PARTIAL_LINE;
207
208 /* No duration to print at this state */
209 ret = trace_seq_printf(s, TRACE_GRAPH_TIMESPACE_ENTRY "-\n");
210 if (!ret) 246 if (!ret)
211 return TRACE_TYPE_PARTIAL_LINE; 247 return TRACE_TYPE_PARTIAL_LINE;
212 248
@@ -220,12 +256,16 @@ print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s,
220 int ret; 256 int ret;
221 struct trace_entry *ent = iter->ent; 257 struct trace_entry *ent = iter->ent;
222 258
259 /* Pid */
223 if (!verif_pid(s, ent->pid, cpu)) 260 if (!verif_pid(s, ent->pid, cpu))
224 return TRACE_TYPE_PARTIAL_LINE; 261 return TRACE_TYPE_PARTIAL_LINE;
225 262
226 ret = trace_seq_printf(s, "CPU[%03d] ", cpu); 263 /* Cpu */
227 if (!ret) 264 if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) {
228 return TRACE_TYPE_PARTIAL_LINE; 265 ret = print_graph_cpu(s, cpu);
266 if (!ret)
267 return TRACE_TYPE_PARTIAL_LINE;
268 }
229 269
230 if (trace_branch_is_leaf(iter, field)) 270 if (trace_branch_is_leaf(iter, field))
231 return print_graph_entry_leaf(iter, field, s); 271 return print_graph_entry_leaf(iter, field, s);
@@ -242,17 +282,30 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
242 int ret; 282 int ret;
243 unsigned long long duration = trace->rettime - trace->calltime; 283 unsigned long long duration = trace->rettime - trace->calltime;
244 284
285 /* Must not exceed 8 characters: xxxx.yyy us */
286 if (duration > 10000000ULL)
287 duration = 9999999ULL;
288
245 /* Pid */ 289 /* Pid */
246 if (!verif_pid(s, ent->pid, cpu)) 290 if (!verif_pid(s, ent->pid, cpu))
247 return TRACE_TYPE_PARTIAL_LINE; 291 return TRACE_TYPE_PARTIAL_LINE;
248 292
249 /* Cpu */ 293 /* Cpu */
250 ret = trace_seq_printf(s, "CPU[%03d] ", cpu); 294 if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) {
251 if (!ret) 295 ret = print_graph_cpu(s, cpu);
252 return TRACE_TYPE_PARTIAL_LINE; 296 if (!ret)
297 return TRACE_TYPE_PARTIAL_LINE;
298 }
253 299
254 /* Overhead */ 300 /* Overhead */
255 ret = print_graph_overhead(duration, s); 301 if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) {
302 ret = print_graph_overhead(duration, s);
303 if (!ret)
304 return TRACE_TYPE_PARTIAL_LINE;
305 }
306
307 /* Duration */
308 ret = print_graph_duration(duration, s);
256 if (!ret) 309 if (!ret)
257 return TRACE_TYPE_PARTIAL_LINE; 310 return TRACE_TYPE_PARTIAL_LINE;
258 311
@@ -263,16 +316,7 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
263 return TRACE_TYPE_PARTIAL_LINE; 316 return TRACE_TYPE_PARTIAL_LINE;
264 } 317 }
265 318
266 ret = trace_seq_printf(s, "} "); 319 ret = trace_seq_printf(s, "}\n");
267 if (!ret)
268 return TRACE_TYPE_PARTIAL_LINE;
269
270 /* Duration */
271 ret = trace_seq_printf(s, TRACE_GRAPH_TIMESPACE_RET);
272 if (!ret)
273 return TRACE_TYPE_PARTIAL_LINE;
274
275 ret = print_graph_duration(duration, s);
276 if (!ret) 320 if (!ret)
277 return TRACE_TYPE_PARTIAL_LINE; 321 return TRACE_TYPE_PARTIAL_LINE;
278 322