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>
15 #include "trace_output.h"
17 #define TRACE_GRAPH_INDENT 2
20 #define TRACE_GRAPH_PRINT_OVERRUN 0x1
21 #define TRACE_GRAPH_PRINT_CPU 0x2
22 #define TRACE_GRAPH_PRINT_OVERHEAD 0x4
23 #define TRACE_GRAPH_PRINT_PROC 0x8
25 static struct tracer_opt trace_opts[] = {
26 /* Display overruns ? */
27 { TRACER_OPT(funcgraph-overrun, TRACE_GRAPH_PRINT_OVERRUN) },
29 { TRACER_OPT(funcgraph-cpu, TRACE_GRAPH_PRINT_CPU) },
30 /* Display Overhead ? */
31 { TRACER_OPT(funcgraph-overhead, TRACE_GRAPH_PRINT_OVERHEAD) },
32 /* Display proc name/pid */
33 { TRACER_OPT(funcgraph-proc, TRACE_GRAPH_PRINT_PROC) },
37 static struct tracer_flags tracer_flags = {
38 /* Don't display overruns and proc by default */
39 .val = TRACE_GRAPH_PRINT_CPU | TRACE_GRAPH_PRINT_OVERHEAD,
43 /* pid on the last trace processed */
44 static pid_t last_pid[NR_CPUS] = { [0 ... NR_CPUS-1] = -1 };
46 static int graph_trace_init(struct trace_array *tr)
50 for_each_online_cpu(cpu)
51 tracing_reset(tr, cpu);
53 ret = register_ftrace_graph(&trace_graph_return,
57 tracing_start_cmdline_record();
62 static void graph_trace_reset(struct trace_array *tr)
64 tracing_stop_cmdline_record();
65 unregister_ftrace_graph();
68 static inline int log10_cpu(int nb)
77 static enum print_line_t
78 print_graph_cpu(struct trace_seq *s, int cpu)
82 int log10_this = log10_cpu(cpu);
83 int log10_all = log10_cpu(cpumask_weight(cpu_online_mask));
87 * Start with a space character - to make it stand out
88 * to the right a bit when trace output is pasted into
91 ret = trace_seq_printf(s, " ");
94 * Tricky - we space the CPU field according to the max
95 * number of online CPUs. On a 2-cpu system it would take
96 * a maximum of 1 digit - on a 128 cpu system it would
97 * take up to 3 digits:
99 for (i = 0; i < log10_all - log10_this; i++) {
100 ret = trace_seq_printf(s, " ");
102 return TRACE_TYPE_PARTIAL_LINE;
104 ret = trace_seq_printf(s, "%d) ", cpu);
106 return TRACE_TYPE_PARTIAL_LINE;
108 return TRACE_TYPE_HANDLED;
111 #define TRACE_GRAPH_PROCINFO_LENGTH 14
113 static enum print_line_t
114 print_graph_proc(struct trace_seq *s, pid_t pid)
121 /* sign + log10(MAX_INT) + '\0' */
124 strncpy(comm, trace_find_cmdline(pid), 7);
126 sprintf(pid_str, "%d", pid);
128 /* 1 stands for the "-" character */
129 len = strlen(comm) + strlen(pid_str) + 1;
131 if (len < TRACE_GRAPH_PROCINFO_LENGTH)
132 spaces = TRACE_GRAPH_PROCINFO_LENGTH - len;
134 /* First spaces to align center */
135 for (i = 0; i < spaces / 2; i++) {
136 ret = trace_seq_printf(s, " ");
138 return TRACE_TYPE_PARTIAL_LINE;
141 ret = trace_seq_printf(s, "%s-%s", comm, pid_str);
143 return TRACE_TYPE_PARTIAL_LINE;
145 /* Last spaces to align center */
146 for (i = 0; i < spaces - (spaces / 2); i++) {
147 ret = trace_seq_printf(s, " ");
149 return TRACE_TYPE_PARTIAL_LINE;
151 return TRACE_TYPE_HANDLED;
155 /* If the pid changed since the last trace, output this event */
156 static enum print_line_t
157 verif_pid(struct trace_seq *s, pid_t pid, int cpu)
162 if (last_pid[cpu] != -1 && last_pid[cpu] == pid)
163 return TRACE_TYPE_HANDLED;
165 prev_pid = last_pid[cpu];
169 * Context-switch trace line:
171 ------------------------------------------
172 | 1) migration/0--1 => sshd-1755
173 ------------------------------------------
176 ret = trace_seq_printf(s,
177 " ------------------------------------------\n");
179 TRACE_TYPE_PARTIAL_LINE;
181 ret = print_graph_cpu(s, cpu);
182 if (ret == TRACE_TYPE_PARTIAL_LINE)
183 TRACE_TYPE_PARTIAL_LINE;
185 ret = print_graph_proc(s, prev_pid);
186 if (ret == TRACE_TYPE_PARTIAL_LINE)
187 TRACE_TYPE_PARTIAL_LINE;
189 ret = trace_seq_printf(s, " => ");
191 TRACE_TYPE_PARTIAL_LINE;
193 ret = print_graph_proc(s, pid);
194 if (ret == TRACE_TYPE_PARTIAL_LINE)
195 TRACE_TYPE_PARTIAL_LINE;
197 ret = trace_seq_printf(s,
198 "\n ------------------------------------------\n\n");
200 TRACE_TYPE_PARTIAL_LINE;
206 trace_branch_is_leaf(struct trace_iterator *iter,
207 struct ftrace_graph_ent_entry *curr)
209 struct ring_buffer_iter *ring_iter;
210 struct ring_buffer_event *event;
211 struct ftrace_graph_ret_entry *next;
213 ring_iter = iter->buffer_iter[iter->cpu];
218 event = ring_buffer_iter_peek(ring_iter, NULL);
223 next = ring_buffer_event_data(event);
225 if (next->ent.type != TRACE_GRAPH_RET)
228 if (curr->ent.pid != next->ent.pid ||
229 curr->graph_ent.func != next->ret.func)
235 static enum print_line_t
236 print_graph_irq(struct trace_seq *s, unsigned long addr,
237 enum trace_type type, int cpu, pid_t pid)
241 if (addr < (unsigned long)__irqentry_text_start ||
242 addr >= (unsigned long)__irqentry_text_end)
243 return TRACE_TYPE_UNHANDLED;
245 if (type == TRACE_GRAPH_ENT) {
246 ret = trace_seq_printf(s, "==========> | ");
249 if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) {
250 ret = print_graph_cpu(s, cpu);
251 if (ret == TRACE_TYPE_PARTIAL_LINE)
252 return TRACE_TYPE_PARTIAL_LINE;
255 if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) {
256 ret = print_graph_proc(s, pid);
257 if (ret == TRACE_TYPE_PARTIAL_LINE)
258 return TRACE_TYPE_PARTIAL_LINE;
260 ret = trace_seq_printf(s, " | ");
262 return TRACE_TYPE_PARTIAL_LINE;
266 if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) {
267 ret = trace_seq_printf(s, " ");
269 return TRACE_TYPE_PARTIAL_LINE;
272 ret = trace_seq_printf(s, "<========== |\n");
275 return TRACE_TYPE_PARTIAL_LINE;
276 return TRACE_TYPE_HANDLED;
279 static enum print_line_t
280 print_graph_duration(unsigned long long duration, struct trace_seq *s)
282 unsigned long nsecs_rem = do_div(duration, 1000);
283 /* log10(ULONG_MAX) + '\0' */
289 sprintf(msecs_str, "%lu", (unsigned long) duration);
292 ret = trace_seq_printf(s, msecs_str);
294 return TRACE_TYPE_PARTIAL_LINE;
296 len = strlen(msecs_str);
298 /* Print nsecs (we don't want to exceed 7 numbers) */
300 snprintf(nsecs_str, 8 - len, "%03lu", nsecs_rem);
301 ret = trace_seq_printf(s, ".%s", nsecs_str);
303 return TRACE_TYPE_PARTIAL_LINE;
304 len += strlen(nsecs_str);
307 ret = trace_seq_printf(s, " us ");
309 return TRACE_TYPE_PARTIAL_LINE;
311 /* Print remaining spaces to fit the row's width */
312 for (i = len; i < 7; i++) {
313 ret = trace_seq_printf(s, " ");
315 return TRACE_TYPE_PARTIAL_LINE;
318 ret = trace_seq_printf(s, "| ");
320 return TRACE_TYPE_PARTIAL_LINE;
321 return TRACE_TYPE_HANDLED;
325 /* Signal a overhead of time execution to the output */
327 print_graph_overhead(unsigned long long duration, struct trace_seq *s)
329 /* Duration exceeded 100 msecs */
330 if (duration > 100000ULL)
331 return trace_seq_printf(s, "! ");
333 /* Duration exceeded 10 msecs */
334 if (duration > 10000ULL)
335 return trace_seq_printf(s, "+ ");
337 return trace_seq_printf(s, " ");
340 /* Case of a leaf function on its call entry */
341 static enum print_line_t
342 print_graph_entry_leaf(struct trace_iterator *iter,
343 struct ftrace_graph_ent_entry *entry, struct trace_seq *s)
345 struct ftrace_graph_ret_entry *ret_entry;
346 struct ftrace_graph_ret *graph_ret;
347 struct ring_buffer_event *event;
348 struct ftrace_graph_ent *call;
349 unsigned long long duration;
353 event = ring_buffer_read(iter->buffer_iter[iter->cpu], NULL);
354 ret_entry = ring_buffer_event_data(event);
355 graph_ret = &ret_entry->ret;
356 call = &entry->graph_ent;
357 duration = graph_ret->rettime - graph_ret->calltime;
360 if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) {
361 ret = print_graph_overhead(duration, s);
363 return TRACE_TYPE_PARTIAL_LINE;
367 ret = print_graph_duration(duration, s);
368 if (ret == TRACE_TYPE_PARTIAL_LINE)
369 return TRACE_TYPE_PARTIAL_LINE;
372 for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) {
373 ret = trace_seq_printf(s, " ");
375 return TRACE_TYPE_PARTIAL_LINE;
378 ret = seq_print_ip_sym(s, call->func, 0);
380 return TRACE_TYPE_PARTIAL_LINE;
382 ret = trace_seq_printf(s, "();\n");
384 return TRACE_TYPE_PARTIAL_LINE;
386 return TRACE_TYPE_HANDLED;
389 static enum print_line_t
390 print_graph_entry_nested(struct ftrace_graph_ent_entry *entry,
391 struct trace_seq *s, pid_t pid, int cpu)
395 struct ftrace_graph_ent *call = &entry->graph_ent;
398 if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) {
399 ret = trace_seq_printf(s, " ");
401 return TRACE_TYPE_PARTIAL_LINE;
405 ret = print_graph_irq(s, call->func, TRACE_GRAPH_ENT, cpu, pid);
406 if (ret == TRACE_TYPE_UNHANDLED) {
408 ret = trace_seq_printf(s, " | ");
410 return TRACE_TYPE_PARTIAL_LINE;
412 if (ret == TRACE_TYPE_PARTIAL_LINE)
413 return TRACE_TYPE_PARTIAL_LINE;
418 for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) {
419 ret = trace_seq_printf(s, " ");
421 return TRACE_TYPE_PARTIAL_LINE;
424 ret = seq_print_ip_sym(s, call->func, 0);
426 return TRACE_TYPE_PARTIAL_LINE;
428 ret = trace_seq_printf(s, "() {\n");
430 return TRACE_TYPE_PARTIAL_LINE;
432 return TRACE_TYPE_HANDLED;
435 static enum print_line_t
436 print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s,
437 struct trace_iterator *iter, int cpu)
440 struct trace_entry *ent = iter->ent;
443 if (verif_pid(s, ent->pid, cpu) == TRACE_TYPE_PARTIAL_LINE)
444 return TRACE_TYPE_PARTIAL_LINE;
447 if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) {
448 ret = print_graph_cpu(s, cpu);
449 if (ret == TRACE_TYPE_PARTIAL_LINE)
450 return TRACE_TYPE_PARTIAL_LINE;
454 if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) {
455 ret = print_graph_proc(s, ent->pid);
456 if (ret == TRACE_TYPE_PARTIAL_LINE)
457 return TRACE_TYPE_PARTIAL_LINE;
459 ret = trace_seq_printf(s, " | ");
461 return TRACE_TYPE_PARTIAL_LINE;
464 if (trace_branch_is_leaf(iter, field))
465 return print_graph_entry_leaf(iter, field, s);
467 return print_graph_entry_nested(field, s, iter->ent->pid, cpu);
471 static enum print_line_t
472 print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
473 struct trace_entry *ent, int cpu)
477 unsigned long long duration = trace->rettime - trace->calltime;
480 if (verif_pid(s, ent->pid, cpu) == TRACE_TYPE_PARTIAL_LINE)
481 return TRACE_TYPE_PARTIAL_LINE;
484 if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) {
485 ret = print_graph_cpu(s, cpu);
486 if (ret == TRACE_TYPE_PARTIAL_LINE)
487 return TRACE_TYPE_PARTIAL_LINE;
491 if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) {
492 ret = print_graph_proc(s, ent->pid);
493 if (ret == TRACE_TYPE_PARTIAL_LINE)
494 return TRACE_TYPE_PARTIAL_LINE;
496 ret = trace_seq_printf(s, " | ");
498 return TRACE_TYPE_PARTIAL_LINE;
502 if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) {
503 ret = print_graph_overhead(duration, s);
505 return TRACE_TYPE_PARTIAL_LINE;
509 ret = print_graph_duration(duration, s);
510 if (ret == TRACE_TYPE_PARTIAL_LINE)
511 return TRACE_TYPE_PARTIAL_LINE;
514 for (i = 0; i < trace->depth * TRACE_GRAPH_INDENT; i++) {
515 ret = trace_seq_printf(s, " ");
517 return TRACE_TYPE_PARTIAL_LINE;
520 ret = trace_seq_printf(s, "}\n");
522 return TRACE_TYPE_PARTIAL_LINE;
525 if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERRUN) {
526 ret = trace_seq_printf(s, " (Overruns: %lu)\n",
529 return TRACE_TYPE_PARTIAL_LINE;
532 ret = print_graph_irq(s, trace->func, TRACE_GRAPH_RET, cpu, ent->pid);
533 if (ret == TRACE_TYPE_PARTIAL_LINE)
534 return TRACE_TYPE_PARTIAL_LINE;
536 return TRACE_TYPE_HANDLED;
539 static enum print_line_t
540 print_graph_comment(struct print_entry *trace, struct trace_seq *s,
541 struct trace_entry *ent, struct trace_iterator *iter)
547 if (verif_pid(s, ent->pid, iter->cpu) == TRACE_TYPE_PARTIAL_LINE)
548 return TRACE_TYPE_PARTIAL_LINE;
551 if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) {
552 ret = print_graph_cpu(s, iter->cpu);
553 if (ret == TRACE_TYPE_PARTIAL_LINE)
554 return TRACE_TYPE_PARTIAL_LINE;
558 if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) {
559 ret = print_graph_proc(s, ent->pid);
560 if (ret == TRACE_TYPE_PARTIAL_LINE)
561 return TRACE_TYPE_PARTIAL_LINE;
563 ret = trace_seq_printf(s, " | ");
565 return TRACE_TYPE_PARTIAL_LINE;
569 if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) {
570 ret = trace_seq_printf(s, " ");
572 return TRACE_TYPE_PARTIAL_LINE;
576 ret = trace_seq_printf(s, " | ");
578 return TRACE_TYPE_PARTIAL_LINE;
581 if (trace->depth > 0)
582 for (i = 0; i < (trace->depth + 1) * TRACE_GRAPH_INDENT; i++) {
583 ret = trace_seq_printf(s, " ");
585 return TRACE_TYPE_PARTIAL_LINE;
589 ret = trace_seq_printf(s, "/* %s", trace->buf);
591 return TRACE_TYPE_PARTIAL_LINE;
593 /* Strip ending newline */
594 if (s->buffer[s->len - 1] == '\n') {
595 s->buffer[s->len - 1] = '\0';
599 ret = trace_seq_printf(s, " */\n");
601 return TRACE_TYPE_PARTIAL_LINE;
603 return TRACE_TYPE_HANDLED;
608 print_graph_function(struct trace_iterator *iter)
610 struct trace_seq *s = &iter->seq;
611 struct trace_entry *entry = iter->ent;
613 switch (entry->type) {
614 case TRACE_GRAPH_ENT: {
615 struct ftrace_graph_ent_entry *field;
616 trace_assign_type(field, entry);
617 return print_graph_entry(field, s, iter,
620 case TRACE_GRAPH_RET: {
621 struct ftrace_graph_ret_entry *field;
622 trace_assign_type(field, entry);
623 return print_graph_return(&field->ret, s, entry, iter->cpu);
626 struct print_entry *field;
627 trace_assign_type(field, entry);
628 return print_graph_comment(field, s, entry, iter);
631 return TRACE_TYPE_UNHANDLED;
635 static void print_graph_headers(struct seq_file *s)
639 if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU)
640 seq_printf(s, "CPU ");
641 if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC)
642 seq_printf(s, "TASK/PID ");
643 if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD)
644 seq_printf(s, "OVERHEAD/");
645 seq_printf(s, "DURATION FUNCTION CALLS\n");
649 if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU)
651 if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC)
652 seq_printf(s, "| | ");
653 if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) {
655 seq_printf(s, "| | | | |\n");
657 seq_printf(s, " | | | | |\n");
659 static struct tracer graph_trace __read_mostly = {
660 .name = "function_graph",
661 .init = graph_trace_init,
662 .reset = graph_trace_reset,
663 .print_line = print_graph_function,
664 .print_header = print_graph_headers,
665 .flags = &tracer_flags,
668 static __init int init_graph_trace(void)
670 return register_tracer(&graph_trace);
673 device_initcall(init_graph_trace);