3 * Function graph tracer.
4 * Copyright (c) 2008 Frederic Weisbecker <fweisbec@gmail.com>
5 * Mostly borrowed from function tracer which
6 * is Copyright (c) Steven Rostedt <srostedt@redhat.com>
9 #include <linux/debugfs.h>
10 #include <linux/uaccess.h>
11 #include <linux/ftrace.h>
16 #define TRACE_GRAPH_INDENT 2
19 #define TRACE_GRAPH_PRINT_OVERRUN 0x1
20 #define TRACE_GRAPH_PRINT_CPU 0x2
21 #define TRACE_GRAPH_PRINT_OVERHEAD 0x4
23 static struct tracer_opt trace_opts[] = {
24 /* Display overruns ? */
25 { TRACER_OPT(funcgraph-overrun, TRACE_GRAPH_PRINT_OVERRUN) },
27 { TRACER_OPT(funcgraph-cpu, TRACE_GRAPH_PRINT_CPU) },
28 /* Display Overhead ? */
29 { TRACER_OPT(funcgraph-overhead, TRACE_GRAPH_PRINT_OVERHEAD) },
33 static struct tracer_flags tracer_flags = {
34 /* Don't display overruns by default */
35 .val = TRACE_GRAPH_PRINT_CPU | TRACE_GRAPH_PRINT_OVERHEAD,
39 /* pid on the last trace processed */
40 static pid_t last_pid[NR_CPUS] = { [0 ... NR_CPUS-1] = -1 };
42 static int graph_trace_init(struct trace_array *tr)
46 for_each_online_cpu(cpu)
47 tracing_reset(tr, cpu);
49 ret = register_ftrace_graph(&trace_graph_return,
53 tracing_start_cmdline_record();
58 static void graph_trace_reset(struct trace_array *tr)
60 tracing_stop_cmdline_record();
61 unregister_ftrace_graph();
64 static inline int log10_cpu(int nb)
73 static enum print_line_t
74 print_graph_cpu(struct trace_seq *s, int cpu)
78 int log10_this = log10_cpu(cpu);
79 int log10_all = log10_cpu(cpus_weight_nr(cpu_online_map));
83 * Start with a space character - to make it stand out
84 * to the right a bit when trace output is pasted into
87 ret = trace_seq_printf(s, " ");
90 * Tricky - we space the CPU field according to the max
91 * number of online CPUs. On a 2-cpu system it would take
92 * a maximum of 1 digit - on a 128 cpu system it would
93 * take up to 3 digits:
95 for (i = 0; i < log10_all - log10_this; i++) {
96 ret = trace_seq_printf(s, " ");
98 return TRACE_TYPE_PARTIAL_LINE;
100 ret = trace_seq_printf(s, "%d) ", cpu);
102 return TRACE_TYPE_PARTIAL_LINE;
104 return TRACE_TYPE_HANDLED;
108 /* If the pid changed since the last trace, output this event */
109 static int verif_pid(struct trace_seq *s, pid_t pid, int cpu)
111 char *comm, *prev_comm;
115 if (last_pid[cpu] != -1 && last_pid[cpu] == pid)
118 prev_pid = last_pid[cpu];
121 comm = trace_find_cmdline(pid);
122 prev_comm = trace_find_cmdline(prev_pid);
125 * Context-switch trace line:
127 ------------------------------------------
128 | 1) migration/0--1 => sshd-1755
129 ------------------------------------------
132 ret = trace_seq_printf(s,
133 " ------------------------------------------\n");
134 ret += trace_seq_printf(s, " | %d) %s-%d => %s-%d\n",
135 cpu, prev_comm, prev_pid, comm, pid);
136 ret += trace_seq_printf(s,
137 " ------------------------------------------\n\n");
142 trace_branch_is_leaf(struct trace_iterator *iter,
143 struct ftrace_graph_ent_entry *curr)
145 struct ring_buffer_iter *ring_iter;
146 struct ring_buffer_event *event;
147 struct ftrace_graph_ret_entry *next;
149 ring_iter = iter->buffer_iter[iter->cpu];
154 event = ring_buffer_iter_peek(ring_iter, NULL);
159 next = ring_buffer_event_data(event);
161 if (next->ent.type != TRACE_GRAPH_RET)
164 if (curr->ent.pid != next->ent.pid ||
165 curr->graph_ent.func != next->ret.func)
173 print_graph_duration(unsigned long long duration, struct trace_seq *s)
175 unsigned long nsecs_rem = do_div(duration, 1000);
176 return trace_seq_printf(s, "%4llu.%3lu us | ", duration, nsecs_rem);
179 /* Signal a overhead of time execution to the output */
181 print_graph_overhead(unsigned long long duration, struct trace_seq *s)
183 /* Duration exceeded 100 msecs */
184 if (duration > 100000ULL)
185 return trace_seq_printf(s, "! ");
187 /* Duration exceeded 10 msecs */
188 if (duration > 10000ULL)
189 return trace_seq_printf(s, "+ ");
191 return trace_seq_printf(s, " ");
194 /* Case of a leaf function on its call entry */
195 static enum print_line_t
196 print_graph_entry_leaf(struct trace_iterator *iter,
197 struct ftrace_graph_ent_entry *entry, struct trace_seq *s)
199 struct ftrace_graph_ret_entry *ret_entry;
200 struct ftrace_graph_ret *graph_ret;
201 struct ring_buffer_event *event;
202 struct ftrace_graph_ent *call;
203 unsigned long long duration;
207 event = ring_buffer_read(iter->buffer_iter[iter->cpu], NULL);
208 ret_entry = ring_buffer_event_data(event);
209 graph_ret = &ret_entry->ret;
210 call = &entry->graph_ent;
211 duration = graph_ret->rettime - graph_ret->calltime;
213 /* Must not exceed 8 characters: 9999.999 us */
214 if (duration > 10000000ULL)
215 duration = 9999999ULL;
218 if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) {
219 ret = print_graph_overhead(duration, s);
221 return TRACE_TYPE_PARTIAL_LINE;
225 ret = print_graph_duration(duration, s);
227 return TRACE_TYPE_PARTIAL_LINE;
230 for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) {
231 ret = trace_seq_printf(s, " ");
233 return TRACE_TYPE_PARTIAL_LINE;
236 ret = seq_print_ip_sym(s, call->func, 0);
238 return TRACE_TYPE_PARTIAL_LINE;
240 ret = trace_seq_printf(s, "();\n");
242 return TRACE_TYPE_PARTIAL_LINE;
244 return TRACE_TYPE_HANDLED;
247 static enum print_line_t
248 print_graph_entry_nested(struct ftrace_graph_ent_entry *entry,
253 struct ftrace_graph_ent *call = &entry->graph_ent;
256 if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) {
257 ret = trace_seq_printf(s, " ");
259 return TRACE_TYPE_PARTIAL_LINE;
263 ret = trace_seq_printf(s, " | ");
266 for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) {
267 ret = trace_seq_printf(s, " ");
269 return TRACE_TYPE_PARTIAL_LINE;
272 ret = seq_print_ip_sym(s, call->func, 0);
274 return TRACE_TYPE_PARTIAL_LINE;
276 ret = trace_seq_printf(s, "() {\n");
278 return TRACE_TYPE_PARTIAL_LINE;
280 return TRACE_TYPE_HANDLED;
283 static enum print_line_t
284 print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s,
285 struct trace_iterator *iter, int cpu)
288 struct trace_entry *ent = iter->ent;
291 if (!verif_pid(s, ent->pid, cpu))
292 return TRACE_TYPE_PARTIAL_LINE;
295 if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) {
296 ret = print_graph_cpu(s, cpu);
298 return TRACE_TYPE_PARTIAL_LINE;
301 if (trace_branch_is_leaf(iter, field))
302 return print_graph_entry_leaf(iter, field, s);
304 return print_graph_entry_nested(field, s);
308 static enum print_line_t
309 print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
310 struct trace_entry *ent, int cpu)
314 unsigned long long duration = trace->rettime - trace->calltime;
316 /* Must not exceed 8 characters: xxxx.yyy us */
317 if (duration > 10000000ULL)
318 duration = 9999999ULL;
321 if (!verif_pid(s, ent->pid, cpu))
322 return TRACE_TYPE_PARTIAL_LINE;
325 if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) {
326 ret = print_graph_cpu(s, cpu);
328 return TRACE_TYPE_PARTIAL_LINE;
332 if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) {
333 ret = print_graph_overhead(duration, s);
335 return TRACE_TYPE_PARTIAL_LINE;
339 ret = print_graph_duration(duration, s);
341 return TRACE_TYPE_PARTIAL_LINE;
344 for (i = 0; i < trace->depth * TRACE_GRAPH_INDENT; i++) {
345 ret = trace_seq_printf(s, " ");
347 return TRACE_TYPE_PARTIAL_LINE;
350 ret = trace_seq_printf(s, "}\n");
352 return TRACE_TYPE_PARTIAL_LINE;
355 if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERRUN) {
356 ret = trace_seq_printf(s, " (Overruns: %lu)\n",
359 return TRACE_TYPE_PARTIAL_LINE;
361 return TRACE_TYPE_HANDLED;
365 print_graph_function(struct trace_iterator *iter)
367 struct trace_seq *s = &iter->seq;
368 struct trace_entry *entry = iter->ent;
370 switch (entry->type) {
371 case TRACE_GRAPH_ENT: {
372 struct ftrace_graph_ent_entry *field;
373 trace_assign_type(field, entry);
374 return print_graph_entry(field, s, iter,
377 case TRACE_GRAPH_RET: {
378 struct ftrace_graph_ret_entry *field;
379 trace_assign_type(field, entry);
380 return print_graph_return(&field->ret, s, entry, iter->cpu);
383 return TRACE_TYPE_UNHANDLED;
387 static struct tracer graph_trace __read_mostly = {
388 .name = "function_graph",
389 .init = graph_trace_init,
390 .reset = graph_trace_reset,
391 .print_line = print_graph_function,
392 .flags = &tracer_flags,
395 static __init int init_graph_trace(void)
397 return register_tracer(&graph_trace);
400 device_initcall(init_graph_trace);