aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_functions_graph.c
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2008-11-25 18:57:25 -0500
committerIngo Molnar <mingo@elte.hu>2008-11-25 19:59:45 -0500
commit287b6e68ca7209caec40b2f44f837c580a413bae (patch)
treeb0867d75868f6049dc5747bd39fdae2d477dde66 /kernel/trace/trace_functions_graph.c
parentfb52607afcd0629776f1dc9e657647ceae81dd50 (diff)
tracing/function-return-tracer: set a more human readable output
Impact: feature This patch sets a C-like output for the function graph tracing. For this aim, we now call two handler for each function: one on the entry and one other on return. This way we can draw a well-ordered call stack. The pid of the previous trace is loosely stored to be compared against the one of the current trace to see if there were a context switch. Without this little feature, the call tree would seem broken at some locations. We could use the sched_tracer to capture these sched_events but this way of processing is much more simpler. 2 spaces have been chosen for indentation to fit the screen while deep calls. The time of execution in nanosecs is printed just after closed braces, it seems more easy this way to find the corresponding function. If the time was printed as a first column, it would be not so easy to find the corresponding function if it is called on a deep depth. I plan to output the return value but on 32 bits CPU, the return value can be 32 or 64, and its difficult to guess on which case we are. I don't know what would be the better solution on X86-32: only print eax (low-part) or even edx (high-part). Actually it's thee same problem when a function return a 8 bits value, the high part of eax could contain junk values... Here is an example of trace: sys_read() { fget_light() { } 526 vfs_read() { rw_verify_area() { security_file_permission() { cap_file_permission() { } 519 } 1564 } 2640 do_sync_read() { pipe_read() { __might_sleep() { } 511 pipe_wait() { prepare_to_wait() { } 760 deactivate_task() { dequeue_task() { dequeue_task_fair() { dequeue_entity() { update_curr() { update_min_vruntime() { } 504 } 1587 clear_buddies() { } 512 add_cfs_task_weight() { } 519 update_min_vruntime() { } 511 } 5602 dequeue_entity() { update_curr() { update_min_vruntime() { } 496 } 1631 clear_buddies() { } 496 update_min_vruntime() { } 527 } 4580 hrtick_update() { hrtick_start_fair() { } 488 } 1489 } 13700 } 14949 } 16016 msecs_to_jiffies() { } 496 put_prev_task_fair() { } 504 pick_next_task_fair() { } 489 pick_next_task_rt() { } 496 pick_next_task_fair() { } 489 pick_next_task_idle() { } 489 ------------8<---------- thread 4 ------------8<---------- finish_task_switch() { } 1203 do_softirq() { __do_softirq() { __local_bh_disable() { } 669 rcu_process_callbacks() { __rcu_process_callbacks() { cpu_quiet() { rcu_start_batch() { } 503 } 1647 } 3128 __rcu_process_callbacks() { } 542 } 5362 _local_bh_enable() { } 587 } 8880 } 9986 kthread_should_stop() { } 669 deactivate_task() { dequeue_task() { dequeue_task_fair() { dequeue_entity() { update_curr() { calc_delta_mine() { } 511 update_min_vruntime() { } 511 } 2813 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.c104
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
18static struct tracer_opt trace_opts[] = { 19static 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 */
31static pid_t last_pid = -1;
29 32
30static int graph_trace_init(struct trace_array *tr) 33static 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
39static void graph_trace_reset(struct trace_array *tr) 43static 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 */
49static int verif_pid(struct trace_seq *s, pid_t pid)
50{
51 if (last_pid != -1 && last_pid == pid)
52 return 1;
44 53
45enum print_line_t 54 last_pid = pid;
46print_graph_function(struct trace_iterator *iter) 55 return trace_seq_printf(s, "\n------------8<---------- thread %d"
56 " ------------8<----------\n\n",
57 pid);
58}
59
60static enum print_line_t
61print_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
86static enum print_line_t
87print_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
119enum print_line_t
120print_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
85static struct tracer graph_trace __read_mostly = { 141static struct tracer graph_trace __read_mostly = {